Passing multiple service uris

I created an asp.net web api 2 controller to manage a logical asset. As usual, the post creates it and returns uri to the asset, and deleting removes it, but I have 2 puts to perform separate actions on the asset, so my code looks like this:

public class Controller : ApiController { public IHttpActionResult Post(Stuff stuff) { var id = CreateNewStuff(stuff); return CreatedAtRoute("DefaultApi", new { id = this.id }, id); } [HttpPut] public IHttpActionResult ActionA(int id, ActionAStuff stuff) { // Perform action A return Ok(); } [HttpPut] public IHttpActionResult ActionB(int id, ActionBStuff stuff) { // Perform action B return Ok(); } public IHttpActionResult Delete(int id) { // Delete the asset return Ok(); } } 

In order for this routing to understand this, my routing rules (including the default rule):

 config.Routes.MapHttpRoute(name: "ActionApi", routeTemplate: "api/{controller}/{action}/{id}"); config.Routes.MapHttpRoute(name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional }); 

This works and feels that the system neatly splits put code into an action and ensures that the system rejects requests for actions that we do not support.

The problem is that the client who creates the asset via mail does not know what the ur (put) of the action (action) is, how it is done for the uri asset through the location header returned from the message. If we change the form of the uri in the future, the clients will break because they will manually create the uris.

What is the correct way to either return multiple service uris from the message, or simply do the above.

+7
asp.net-mvc asp.net-web-api
source share
4 answers

Use Route to differentiate actions. For example:

 [RoutePrefix("api/Admin")] public class Controller : ApiController { [Route("ActionA") [HttpPut] public IHttpActionResult ActionA(int id, ActionAStuff stuff) { // Perform action A return Ok(); } [Route("ActionB") [HttpPut] public IHttpActionResult ActionB(int id, ActionBStuff stuff) { // Perform action B return Ok(); } } 

Then include attribute routing in your webapiconfig.cs

 public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API routes config.MapHttpAttributeRoutes(); // Other Web API configuration not shown. } } 

Finally, in your client, you can distinguish between URIs, as shown below: HTTP (S): /// api / Admin / ActionA

HTTP (s): /// api / Admin / ActionB

+1
source share

For each method, a route prefix should be used for differentiation.

 [Route("ActionA") [HttpPut] public IHttpActionResult ActionA(int id, ActionAStuff stuff) { // Perform action A return Ok(); } 

When we configure a route using the route configuration from config.Routes.MapHttpRoute, it must be correct, as it is added to the stack and used from the stack.

As soon as he finds any entry from the routing table, she will try to execute it. Thus, the best way is to use a route prefix.

+1
source share

You can add the link title to the result of the POST method:

  • To add a custom title to the IHttpActionResult class, you can define an extension method, for example:

     public static class HttpActionResultHeaderExtensions { public static IHttpActionResult AddHeader(this IHttpActionResult action, string headerName, params string[] headerValues) { return new HeaderActionResult(action, headerName, headerValues); } private class HeaderActionResult : IHttpActionResult { private readonly IHttpActionResult action; private readonly Tuple<string, IEnumerable<string>> header; public HeaderActionResult(IHttpActionResult action, string headerName, IEnumerable<string> headerValues) { this.action = action; header = Tuple.Create(headerName, headerValues); } public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) { var response = await action.ExecuteAsync(cancellationToken); response.Headers.Add(header.Item1, header.Item2); return response; } } } 
  • Add route attributes:

     [System.Web.Http.RoutePrefixAttribute("api/stuff")] public class Controller : ApiController { [System.Web.Http.HttpPut] [System.Web.Http.RouteAttribute("ActionA", Name = "ActionA")] public IHttpActionResult ActionA(int id, ActionAStuff stuff) { // your code } [System.Web.Http.HttpPut] [System.Web.Http.RouteAttribute("ActionB", Name = "ActionB")] public IHttpActionResult ActionB(int id, ActionBStuff stuff) { // your code } } 
  • Extend the POST method by adding a header link to the result:

     public IHttpActionResult Post(Stuff stuff) { var id = CreateNewStuff(stuff); var actionALink = this.Url.Link("ActionA", new { id = id }); var actionBLink = this.Url.Link("ActionB", new { id = id }); return CreatedAtRoute("DefaultApi", new { id = id }, id) .AddHeader("Link", $"<{actionALink}>; rel=\"ActionA\"", $"<{actionBLink}>; rel=\"ActionB\""); } 
  • Extend configuration:

     config.MapHttpAttributeRoutes(); config.EnsureInitialized(); 
+1
source share

Web API 2 supports a new type of routing called attribute routing. As the name implies, attribute routing uses attributes to define routes. Attribute routing gives you more control over the URIs in your web interface. You can use Attribute Routing in Web Api to solve your problems. Your controller action should be such

  [Route("ActionA/{id}"] [HttpPut] public IHttpActionResult ActionA(int id, ActionAStuff stuff) { // Perform action A return Ok(); } [HttpPut] [Route("ActionB/{id}"] public IHttpActionResult ActionB(int id, ActionBStuff stuff) { // Perform action B return Ok(); } 

and your http request http: // localhost: 1317 / ActionA / 1 and http: // localhost: 1317 / ActionB / 1

0
source share

All Articles