Jak trasować akcje inne niż CRUD w interfejsie API RESTful ASP.NET?

Próbuję zaprojektować RESTful web API dla naszej usługi przy użyciu ASP.NET Web API. Mam problem z ustaleniem, w jaki sposób przekierować działania inne niż CRUD do właściwej akcji kontrolera. Załóżmy, że mój zasób to drzwi. Mogę zrobić wszystkie znane rzeczy CRUD za pomocą moich drzwi. Powiedzmy, że ten model dla moich drzwi to:

public class Door
{
   public long Id { get; set; }
   public string InsideRoomName { get; set; }
   public string OutsideRoomName { get; set; }
}

Mogę wykonać wszystkie moje standardowe operacje CRUD za pośrednictwem interfejsu internetowego:

POST: http://api.contoso.com/v1/doors
GET: http://api.contoso.com/v1/doors
GET: http://api.contoso.com/v1/doors/1234
GET: http://api.contoso.com/v1/doors?InsideRoomName=Cafeteria
PUT: http://api.contoso.com/v1/doors/1234
DELETE: http://api.contoso.com/v1/doors/1234

i tak dalej. Tam, gdzie wpadam w tarapaty, muszę modelować akcje nie-CRUD na moich drzwiach. Chcę modelować czasownik Lock and Unlock przeciwko mojemu zasobowi. Czytanie przezArtykuły ASP.NET wydaje się, że przy korzystaniu z akcji niestandardowych należy przełączyć się na wywołanie stylu RPC. To daje mi ścieżkę:

PUT: http://api.contoso.com/v1/doors/1234/lock
PUT: http://api.contoso.com/v1/doors/1234/unlock

Wydaje się, że jest to sprzeczne z duchem REST, który ma na celu wskazanie zasobu. Przypuszczam, że mógłbym modelować czasownik jako zasób:

POST: http://api.contoso.com/v1/doors/1234/lockrequests
POST: http://api.contoso.com/v1/doors/1234/unlockrequests

W tym przypadku nadal mogę użyć polecenia rekomenduj {kontroler} / {id} / {akcja}, ale wygląda na to, że nadal tworzę mieszany interfejs RPC / REST. Czy jest to możliwe, a nawet zalecane, jeśli chodzi o interfejsy REST, aby umieścić niestandardową akcję na liście parametrów?

PUT: http://api.contoso.com/v1/doors/1234?lock
PUT: http://api.contoso.com/v1/doors/1234?unlock

Mogłabym przewidzieć potrzebę obsługi tego połączenia również przy użyciu parametrów zapytania, takich jak:

PUT: http://api.contoso.com/v1/doors?lock&InsideRoomName=Cafeteria

Jak mogę utworzyć trasę do mapowania tego żądania do mojego kontrolera DoorsController?

public class DoorsController : ApiController
{
   public IEnumerable<Doord> Get();
   public Door Get(long id);
   public void Put(long id, Door door);
   public void Post(Door door);
   public void Delete(long id);

   public void Lock(long id);
   public void Unlock(long id);
   public void Lock(string InsideRoomName);
}

Mogę tutaj robić fałszywe założenia dotyczące tego, co jest, a co nie jest najlepszą praktyką w odniesieniu do projektowania interfejsu API REST, więc wszelkie wskazówki tam są również doceniane.

questionAnswers(3)

yourAnswerToTheQuestion