While discovering the endless depths of the internet I discovered the following project: https://github.com/mccalltd/AttributeRouting/wiki
It introduces Attributes to define locally in the controller how to access the actions. This will undoubtly will create many routes, so my simple question is:
Will defining many routes slow down accessing the web api and/or the website?
The answer to your second question is the easiest: Yes. I can't find the reference, but the current algorithm matches all routes in the route table to find a match. The larger the route table, the slower the match. I'm sure there is a reason for this other
than the diagnostic use I've seen in tools like Glimpse, but again I forget the reference where I first saw this.
In terms of whether using this tool will cause your app to slow down, it depends. If you take this to the extreme and apply an attribute to every action in every controller, then yes, you will have a mess on your hands, especially if you include a lot of
controllers in your application. You could use the
convetion-based routing, which looks to be an attribute per controller class. This is not quite as bad. Also, you could break up your application into multiple, smaller applications. There's typically no reason why an individual controller -- or set of
a few controllers -- couldn't be its own application. Taking this approach, you create more applications, all communicating through shared state (i.e. data storage).
Marked as answer by MartinJ. on May 15, 2012 12:15 PM
A collegue hinted me to create a test project, so I created a new web api, added an extreme amount of routes (10.000), and measured the average call time. Calling the first route took average 5 milliseconds, the route 5000 took average 15 milliseconds and
route 10.000 took 26 milliseconds. This was really basic, no dynamic stuff. I'm really surprised this is not cached in some way.. I guess I can implement caching myself, as I know by now that Asp.net is highly extensible, I just don't know where yet. :)
I'm struggling with designing the service. We have an existing service (wcf web api, highly dynamic UriTemplates, each method had an attribute describing which uri is used to access it), which I want to port now to asp.net web api. My intermediate solution
was to map the existing uris to routes, but I'm afraid this will cause performance impacts later. I tried to stuff all methods into a "{controller}/{id}" and "{controller}/{id}/{subcontroller}/{subid}" pattern, but this was really painful with some methods
and extending the service is rather difficult this way, so it's no real option either.
This project seems to be a nice solution between generic routes and specific definitions.
Splitting up into several applications is not an option, as we develop a larger software suite which is backed by a web service. This is hosted in Azure, and we want out of cost reasons the entire service in one web application.
I also need a way to figure out at run time by reflection which route I have to take for a method, because I want to create a client for different languages and systems automatically.
Anyway, your response answered my initial question, so I'll mark it as the answer. But any more helpful comments are welcome. :)
I forgot to mention that a similar attributed routing mechanism exists in
WebApiContrib. This one is designed specifically for Web API and seems a little simpler. You may be able to extend this to fit your needs.
MartinJ.
A collegue hinted me to create a test project, so I created a new web api, added an extreme amount of routes (10.000), and measured the average call time. Calling the first route took average 5 milliseconds, the route 5000 took average 15 milliseconds and
route 10.000 took 26 milliseconds. This was really basic, no dynamic stuff. I'm really surprised this is not cached in some way.. I guess I can implement caching myself, as I know by now that Asp.net is highly extensible, I just don't know where yet. :)
Thanks for the performance numbers. That's interesting, as I thought I had read that the time to identify a route was always the same. That may have been because the article I read used Glimpse or something similar to identify all matching routes, which
would have loaded all routes every time.
MartinJ.
I'm struggling with designing the service. We have an existing service (wcf web api, highly dynamic UriTemplates, each method had an attribute describing which uri is used to access it), which I want to port now to asp.net web api. My intermediate solution
was to map the existing uris to routes, but I'm afraid this will cause performance impacts later. I tried to stuff all methods into a "{controller}/{id}" and "{controller}/{id}/{subcontroller}/{subid}" pattern, but this was really painful with some methods
and extending the service is rather difficult this way, so it's no real option either.
What caused the pain? You could always create new controllers and follow a more resource-per-controller approach. This is still somewhat limiting with the lack of Areas, but it might help. Do you have an existing URI space in production that you must continue
to maintain? Could you not potentially alter your URI structure and use 301 responses to push clients to use the new URIs? Pretty URIs are nice, but they can really kill you if you try to maintain too many. I'm not sure if that's a problem for you or not.
MartinJ.
I also need a way to figure out at run time by reflection which route I have to take for a method, because I want to create a client for different languages and systems automatically.
The upcoming release of Web API should include a help page that might offer you a solution to generating or allowing clients to know how to consume your API. See the
roadmap.
I hope that helps. I'm looking for the link to the sample showing a message handler as an Area mechanism, but I can't find it at this time. That might alleviate some of the routing pain, but I doubt it would help much. I'm working on another approach using
nested HttpServer instances with their own configurations. Once selected, you wouldn't be able to fall through as the current routing infrastructure allows, but you would at least have a hierarchical selection mechanism that should keep your route tables small.
I'll post a link once I've had a chance to try it out.
Thanks for the performance numbers. That's interesting, as I thought I had read that the time to identify a route was always the same. That may have been because the article I read used Glimpse or something similar to identify all matching routes, which would
have loaded all routes every time.
Just to be sure that I didn't do any bollocks, here is what I did:
// Register 10.000 routes
for (int i = 0; i < 10000; i++)
routes.MapHttpRoute("Testroute" + i, "api/test" + i, new { controller = "Values", action = "Get", id = i });
// call service 5.000 times and count times
var sw = new Stopwatch();
double sum = 0.0;
for (int i = 0; i < 5000; ++i)
{
sw.Restart();
client.GetAsync("http://localhost:61463/api/test9999").Wait();
sw.Stop();
sum += sw.ElapsedMilliseconds;
}
Console.WriteLine(sum / 5000);
panesofglass
What caused the pain?
I don't want to go too detailed into our product, so here's an analogy. We have a controller that handles houses. Each house can have rooms, so we have "api/houses/{house_id}/rooms/{room_id}" (sub controller approach, like I mentioned). A house always has
one roof, which I'd map to "api/houses/{house_id}/roof". The roof just has a get and update mechanism. So according to my approach I'd have to create a Sub-Controller for the roof alone, instead of just having "GetRoof" inside the house controller. Adding
it there and using the ActionName-Attribute will faill with an ambigious method call. You can also have images of houses, so "api/houses/{house_id}/images/{image_id}". But we need an easy way to get a primary image, like "api/houses/{house_id}/images/primary",
and this again wouldn't fit in the mentioned generic routes.
panesofglass
Do you have an existing URI space in production that you must continue to maintain? Could you not potentially alter your URI structure and use 301 responses to push clients to use the new URIs?
Luckyly I'm free to change the buildup of the URI as I need, but I'm not able to change easily the buildup of the methods (like getting a primary image, mentioned before). But the 301 response is a good hint, which I'll add to my auto generated client. :)
panesofglass
Pretty URIs are nice, but they can really kill you if you try to maintain too many. I'm not sure if that's a problem for you or not.
I really like pretty URIs, but they're not most important to me. What mostly matters to me is that it's error prone to extend the service, so collegues don't accidently get any problems or have to remember any specific things to do. Adding routes manually
is one such thing, which can easily be forgot, or replaced other routes without noticing.
panesofglass
The upcoming release of Web API should include a help page that might offer you a solution to generating or allowing clients to know how to consume your API.
New features are always great... but only when you're able to use them. And an upcoming release is not available. :) I can't wait for such things to be released, I have to make the best of what I can use now.
MartinJ.
Member
249 Points
83 Posts
Creating many routes - Performance penalty?
May 15, 2012 07:27 AM|LINK
Hello!
While discovering the endless depths of the internet I discovered the following project: https://github.com/mccalltd/AttributeRouting/wiki
It introduces Attributes to define locally in the controller how to access the actions. This will undoubtly will create many routes, so my simple question is:
Will defining many routes slow down accessing the web api and/or the website?
panesofglass
Participant
758 Points
242 Posts
Re: Creating many routes - Performance penalty?
May 15, 2012 11:22 AM|LINK
The answer to your second question is the easiest: Yes. I can't find the reference, but the current algorithm matches all routes in the route table to find a match. The larger the route table, the slower the match. I'm sure there is a reason for this other than the diagnostic use I've seen in tools like Glimpse, but again I forget the reference where I first saw this.
In terms of whether using this tool will cause your app to slow down, it depends. If you take this to the extreme and apply an attribute to every action in every controller, then yes, you will have a mess on your hands, especially if you include a lot of controllers in your application. You could use the convetion-based routing, which looks to be an attribute per controller class. This is not quite as bad. Also, you could break up your application into multiple, smaller applications. There's typically no reason why an individual controller -- or set of a few controllers -- couldn't be its own application. Taking this approach, you create more applications, all communicating through shared state (i.e. data storage).
MartinJ.
Member
249 Points
83 Posts
Re: Creating many routes - Performance penalty?
May 15, 2012 12:14 PM|LINK
First, thank you for your response. :)
A collegue hinted me to create a test project, so I created a new web api, added an extreme amount of routes (10.000), and measured the average call time. Calling the first route took average 5 milliseconds, the route 5000 took average 15 milliseconds and route 10.000 took 26 milliseconds. This was really basic, no dynamic stuff. I'm really surprised this is not cached in some way.. I guess I can implement caching myself, as I know by now that Asp.net is highly extensible, I just don't know where yet. :)
I'm struggling with designing the service. We have an existing service (wcf web api, highly dynamic UriTemplates, each method had an attribute describing which uri is used to access it), which I want to port now to asp.net web api. My intermediate solution was to map the existing uris to routes, but I'm afraid this will cause performance impacts later. I tried to stuff all methods into a "{controller}/{id}" and "{controller}/{id}/{subcontroller}/{subid}" pattern, but this was really painful with some methods and extending the service is rather difficult this way, so it's no real option either.
This project seems to be a nice solution between generic routes and specific definitions.
Splitting up into several applications is not an option, as we develop a larger software suite which is backed by a web service. This is hosted in Azure, and we want out of cost reasons the entire service in one web application.
I also need a way to figure out at run time by reflection which route I have to take for a method, because I want to create a client for different languages and systems automatically.
Anyway, your response answered my initial question, so I'll mark it as the answer. But any more helpful comments are welcome. :)
panesofglass
Participant
758 Points
242 Posts
Re: Creating many routes - Performance penalty?
May 15, 2012 01:47 PM|LINK
I forgot to mention that a similar attributed routing mechanism exists in WebApiContrib. This one is designed specifically for Web API and seems a little simpler. You may be able to extend this to fit your needs.
Thanks for the performance numbers. That's interesting, as I thought I had read that the time to identify a route was always the same. That may have been because the article I read used Glimpse or something similar to identify all matching routes, which would have loaded all routes every time.
What caused the pain? You could always create new controllers and follow a more resource-per-controller approach. This is still somewhat limiting with the lack of Areas, but it might help. Do you have an existing URI space in production that you must continue to maintain? Could you not potentially alter your URI structure and use 301 responses to push clients to use the new URIs? Pretty URIs are nice, but they can really kill you if you try to maintain too many. I'm not sure if that's a problem for you or not.
The upcoming release of Web API should include a help page that might offer you a solution to generating or allowing clients to know how to consume your API. See the roadmap.
I hope that helps. I'm looking for the link to the sample showing a message handler as an Area mechanism, but I can't find it at this time. That might alleviate some of the routing pain, but I doubt it would help much. I'm working on another approach using nested HttpServer instances with their own configurations. Once selected, you wouldn't be able to fall through as the current routing infrastructure allows, but you would at least have a hierarchical selection mechanism that should keep your route tables small. I'll post a link once I've had a chance to try it out.
MartinJ.
Member
249 Points
83 Posts
Re: Creating many routes - Performance penalty?
May 15, 2012 02:18 PM|LINK
Just to be sure that I didn't do any bollocks, here is what I did:
// Register 10.000 routes for (int i = 0; i < 10000; i++) routes.MapHttpRoute("Testroute" + i, "api/test" + i, new { controller = "Values", action = "Get", id = i }); // call service 5.000 times and count times var sw = new Stopwatch(); double sum = 0.0; for (int i = 0; i < 5000; ++i) { sw.Restart(); client.GetAsync("http://localhost:61463/api/test9999").Wait(); sw.Stop(); sum += sw.ElapsedMilliseconds; } Console.WriteLine(sum / 5000);I don't want to go too detailed into our product, so here's an analogy. We have a controller that handles houses. Each house can have rooms, so we have "api/houses/{house_id}/rooms/{room_id}" (sub controller approach, like I mentioned). A house always has one roof, which I'd map to "api/houses/{house_id}/roof". The roof just has a get and update mechanism. So according to my approach I'd have to create a Sub-Controller for the roof alone, instead of just having "GetRoof" inside the house controller. Adding it there and using the ActionName-Attribute will faill with an ambigious method call. You can also have images of houses, so "api/houses/{house_id}/images/{image_id}". But we need an easy way to get a primary image, like "api/houses/{house_id}/images/primary", and this again wouldn't fit in the mentioned generic routes.
Luckyly I'm free to change the buildup of the URI as I need, but I'm not able to change easily the buildup of the methods (like getting a primary image, mentioned before). But the 301 response is a good hint, which I'll add to my auto generated client. :)
I really like pretty URIs, but they're not most important to me. What mostly matters to me is that it's error prone to extend the service, so collegues don't accidently get any problems or have to remember any specific things to do. Adding routes manually is one such thing, which can easily be forgot, or replaced other routes without noticing.
New features are always great... but only when you're able to use them. And an upcoming release is not available. :) I can't wait for such things to be released, I have to make the best of what I can use now.