Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle hierarchical routes in ASP.NET Web API?

Currently I have two controllers

1 - Parent Controller

2 - Child Controller

I access my Parent Controller like this

someurl\parentcontroller

Now I want to access my children controller like this

someurl\parentcontroller\1\childcontroller

This last url should return all the children of a particular parent.

I have this route currently in my global.asax file

routes.MapHttpRoute ("Route1", "{controller}/{id}", new { id = RouteParameter.Optional });

I am not sure how can I achieve my parent\id\child hierarchy.. How should I configure my routes to achieve this? Ideas?

like image 935
Haris Hasan Avatar asked May 28 '12 11:05

Haris Hasan


4 Answers

Configure the routes as below. The {param} is optional (use if you need):

routes.MapHttpRoute(
           name: "childapi",
           routeTemplate: "api/Parent/{id}/Child/{param}",
           defaults: new { controller = "Child", param = RouteParameter.Optional }
  );

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

Then call the child APi as /api/Parent/1/child The parent can be called simple as /api/Parent/

The child controller:

    public class ChildController : ApiController
    {     
        public string Get(int id)
        {
          //the id is id between parent/{id}/child  
          return "value";
        }
        .......
    }
like image 191
Abhijit-K Avatar answered Oct 20 '22 06:10

Abhijit-K


Since Web API 2 you can now use Route Attributes to define custom routing per Method,

[Route("api/customers/{id:guid}/orders")]
public IEnumerable<Order> GetCustomerOrders(Guid id) {
   return new Order[0];
}

You also need to add following line to WebApiConfig.Register() initialization method,

  config.MapHttpAttributeRoutes();

Full article, http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

like image 42
Daniel Halan Avatar answered Oct 20 '22 08:10

Daniel Halan


I wanted to handle this in a more general way, instead of wiring up a ChildController directly with controller = "Child", as Abhijit Kadam did. I have several child controllers and didn't want to have to map a specific route for each one, with controller = "ChildX" and controller = "ChildY" over and over.

My WebApiConfig looks like this:

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

My parent controllers are very standard, and match the default route above. A sample child controller looks like this:

public class CommentController : ApiController
{
    // GET api/product/5/comment
    public string Get(ParentController parentController, string parentId)
    {
        return "This is the comment controller with parent of "
        + parentId + ", which is a " + parentController.ToString();
    }
    // GET api/product/5/comment/122
    public string Get(ParentController parentController, string parentId,
        string id)
    {
        return "You are looking for comment " + id + " under parent "
            + parentId + ", which is a "
            + parentController.ToString();
    }
}
public enum ParentController
{
    Product
}

Some drawbacks of my implementation

  • As you can see, I used an enum, so I'm still having to manage parent controllers in two separate places. It could have just as easily been a string parameter, but I wanted to prevent api/crazy-non-existent-parent/5/comment/122 from working.
  • There's probably a way to use reflection or something to do this on the fly without managing it separetly, but this works for me for now.
  • It doesn't support children of children.

There's probably a better solution that's even more general, but like I said, this works for me.

like image 10
mo. Avatar answered Oct 20 '22 06:10

mo.


An option beyond using default mvc routing is to look at Attribute Routing - https://github.com/mccalltd/AttributeRouting. Although its more work, decorating individual action methods provides a ton of flexibility when you need to design complicated routes. You can also use it in conjunction with standard MVC routing.

like image 5
AlexGad Avatar answered Oct 20 '22 06:10

AlexGad