Last post Mar 25, 2013 09:20 AM by kstreith
Apr 01, 2012 09:08 PM|rstrahl|LINK
using latest CodePlex bits
I'm running into a bunch of headaches with the default HTTP Verb routing. The problem essentially is that if I use HTTP Verb routing to an API controller I seem to be unable to also use custom routing into the same controller without running into method
signature/verb mapping conflicts.
Consider that I have a controller like this:
public class AlbumApiController : ApiController
public IEnumerable<Album> GetAlbums()
var albums = AlbumData.Current.OrderBy(alb => alb.Artist);
public Album GetAlbum(string title)
var album = AlbumData.Current.Where(alb => alb.AlbumName.Contains(title)).SingleOrDefault();
public HttpResponseMessage AlbumArt(string title)
var album = AlbumData.Current
.Where(alb => title.StartsWith(title))
if (album == null)
var content = new ObjectContent<ApiMessageError>
(new ApiMessageError("Album not found"), null);
var resp = new HttpResponseMessage()
Content = content,
StatusCode = HttpStatusCode.NotFound
// kinda silly - we would normally serve this directly
// but hey - it's a demo.
var http = new WebClient();
var imageData = http.DownloadData(album.AlbumImageUrl);
// create response and return
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(imageData);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
Notice that the GetAblum() and AlbumArt() methods have the same signature and both require GET operations.
Also consider that I have these two routes:
title = RouteParameter.Optional,
controller = "AlbumApi",
action = "AlbumArt"
// Verb Routing
title = RouteParameter.Optional,
controller = "AlbumApi"
I can now access:
and that works fine. However, trying to access:
Multiple actions were found that match the request: MusicAlbums.Album GetAlbum(System.String) on type AspNetWebApi.Controllers.AlbumApiController System.Net.Http.HttpResponseMessage AlbumArt(System.String) on type AspNetWebApi.Controllers.AlbumApiController
works - presumably because the image route precedes the Http Verb routing.
The problem here is that there's no way to tell Web API (AFAIK) that you don't want HTTP Verb routing to kick in on a given method.
In previous builds (Beta/post beta) this worked because Http Verb Routing only looked at the GetXXX methods and didn't look explicitly at the [HttpGet] attribute. That would be preferrable IMHO as then there's a way out to tell WebAPI to not include this
method for HttpVerb routing.
Not holding my breath that this will change :-) Soooo... my question is what is the best way to mix RPC style routing and custom routing in such a way that we don't end up with tons of separate controllers?
The only way I could make the above work was basically to configure another controller and set it up for explicit action routing, and then route the image link (and any other more explicit operations) to the second controller. Or I can custom route everything
to a action routed controller.
But logistically this doesn't make sense - my controller behavior should include the image serving because it is part of the Album serving logic so while I can work around this I don't like the way I'm forced to work when using Http Verb routing.
Curious to hear if others are having much luck with HTTP Verb routing in more complex scenarios especially those where child entities/objects are accessed. Any recommendations how that would be best handled using HTTP Verb routing?
+++ Rick ---
Apr 03, 2012 06:11 AM|james-world|LINK
It looks like everything is working as it should.
The [HttpGet] is implicit when no attributes are supplied - it's not that "verb" routing is different in any way - you just genuinely have ambiguity in your methods. The action binding on second route has no way of disambiguating between the two methods
with identical signatures when title is supplied. When you don't supply the title it *can* disambigute because the parameterless method is the only match.
Apr 03, 2012 06:35 AM|rstrahl|LINK
Actually [HttpPost] is implicit when no attributes are applied.
The issue I have isn't that verb routing isn't work - it is. But it is so all-encompassing that it will not mix with custom routing because the verb routing will complain about any methods - even if is a route endpoint - will still have to follow HttpVerb
restrictions (1 verb per method signature). In effect this means you can't mix verb and action routing easily in a single controller.
There's a workaround apparently by using an explicit [HttpVerb(string.Empty)] attribute, but that doesn't sit right with me either.
I think what we need is a way to tell verb routing that a method should not be routed only based on a verb but should be accessible via custom routing or action routing.
Apr 03, 2012 07:32 AM|james-world|LINK
Looking at the implementation of System.Web.Http.Controllers.ApiControllerActionSelector, specifically FindActionsForVerbWorker().
The problem is still the ambiguity in your methods. It doesn't work in the way that you have "verb routing" or "other routing" - it's just an additional rule that adds a method as a candidate for e.g. Get if the method name starts with "Get". Ahead of that
all the methods marked with HttpGet are also candidates. AlbumArt is a candidate for Get because of it's HttpGet attribute. GetAlbum is a candidate because of it's name.
If you want custom behaviour there are ways to do it, you could create your own IHttpActionSelector (and even attach this to the controller descriptor in your own controller factory implementation and carry on using ApiController).
I really don't think there's a problem in WebAPI here.
Apr 03, 2012 08:58 AM|skumar2003|LINK
I agree with James. There is ambiguity in your routes.
As to your other points:
>I think what we need is a way to tell verb routing that a method should not be routed only based on a verb but should be >accessible via custom routing or action routing.
I feel the Web API controllers handle very specific cases. If your use case falls outside the bounds then either roll your own RouteHandler or seperate out the other functionality into a different controller (So the route changes).
Apr 03, 2012 09:43 AM|LittleClive|LINK
I did the following:
I built on this to support areas and subareas too but had to fully implement IHttpControllerFactory rather than using DefaultControllerFactory. One thing to remember is to remove the keys from the route data if you use them otherwise they'll be expected
to be parameters on the controller method, e.g.
May 25, 2012 04:14 PM|ShadowChaser|LINK
I've posted a proposed fix for this in the CodePlex project site for the ASP.NET Web Stack.
If you feel like it, head over to the issue report at
http://aspnetwebstack.codeplex.com/workitem/184 and add your vote/voice to the suggestion.
I had the exact same issue as you - in many scenarios it makes a lot of sense to mix verb and traditional action routing when you want both CRUD behavior along with some specific business actions related to an entity.
Mar 25, 2013 09:20 AM|kstreith|LINK
I've written a blog post that shows how to get both action and verb-based routing working in a single controller without the need for any custom code. http://blog.appliedis.com/2013/03/25/web-api-mixing-traditional-verb-based-routing/