.NET Web Api - several GET and POST methods

2019-06-03 10:53发布

问题:

I'm writing a REST API and have the following problem:

With the resource /messages/, I have the following methods in my MessageController:

[HttpGet]
// retrieves all messages for a user
public HttpResponseMessage GetMessages(Guid RecordId) {}

[HttpGet]
// retrieves only a single messages, specified by guid
public HttpResponseMessage GetMessage(Guid RecordId) {}

In my WebApiConfig.cs I have the following routing:

config.Routes.MapHttpRoute(
    name: "MessageRouting",
    routeTemplate: "messages/{RecordId}/",
    defaults: new { controller = "Message", RecordId= RouteParameter.Optional }
);

This, of course, fails because the routing doesn't know which method to call. The issue here is, to remain RESTful, I want to avoid having additional query parameters such as

GET /messages/?userid=1

Should I rather pull the userId from the AccessToken and call GetMessages as follows?

GET /messages
AccessToken=foo

I will run into the same problem using [HttpPost] and [HttpPut] as well - I always have either a collection, or a single item that I want to work with, so for each Http Method I will have at least 2 Methods to call.

I don't have the option of moving a GetMessages() method to the UserController, because there I will run into the same problem - it seems that with Web Api, a controller can only have each HTTP Method defined a single time, which makes it horribly hard to work with collections vs. single items.

I'm a little torn between remaining RESTful and having URLs uniquely identify resources, but it seems .NET doesn't give me a choice here, as I can't specify the HTTP Method in the routing. Or can I?

回答1:

Found the solution - in WebApiConfig.cs, you can specify the "name" attribute for routes. This attribute can be used to annotate the methods, such as:

public class MessageController() {

    [ActionName("MultipleMessages")]
    [HttpGet]
    public HttpResponseMessage GetMessages(Guid UserId) {}

    [ActionName("SingleMessage")]
    [HttpGet]
    public HttpResponseMessage GetMessage(Guid MessageId) {}

}

That way you can have several GET or POST methods in the same controller. The route calling these methods would look like this:

// multiple messages, will call MessageController.GetMessages()
config.Routes.MapHttpRoute(
    name: "MultipleMessages",
    routeTemplate: "users/{UserId}/messages",
    defaults: new { controller = "Message", UserId = RouteParameter.Optional }
);

// single messages, will call MessageController.GetMessage()
config.Routes.MapHttpRoute(
    name: "SingleMessage",
    routeTemplate: "messages/{MessageId}/",
    defaults: new { controller = "Message", MessageId = RouteParameter.Optional }
);