Cleanly getting a WebAPI action URL

Whenever you need to get the URL of a ASP.NET MVC action, you should use Url.Action (where URL is an instance of UrlHelper), and never hard-code the URL. This way, the URL is dynamically constructed from the available information in the Url.Action parameters and in the route table. If the route is changed, the results of the Url.Action call will change accordingly, and everything will continue to work. The same principles, of course, apply to WebAPI actions.

In Orchard, when you need a MVC UrlHelper, you can just inject it: there is special logic in Orchard.Mvc.MvcModule that can create a UrlHelper instance in almost any situation, including complex cases where the code is running in a background process that has no HttpContext. The equivalent code for WebAPI’s UrlHelper unfortunately doesn’t exist. Building it would be non-trivial, a difficulty being in particular to build or acquire the HttpRequestMessage instance that it needs, outside of a WebAPI controller.

Fortunately, we don’t need to do that. There’s a simpler way, which is simply to use the ASP.NET MVC UrlHelper, which will work just fine on WebAPI actions, even though the routes are in a different table, if you specify the httproute parameter in your route values:

var actionUrl = _url.Action("Content", "Import", new {
httproute = true,
area = "Orchard.ImportExport"
});

This will get the WebAPI controller ImportController’s Content action’s URL (from the Orchard.ImportExport module), using only the MVC UrlHelper.

8 Comments

  • Nice! I'm going to steal the URL to this post and post it as an answer on Orchard Pros and earn myself some more points. Thank you very much. ;-)

  • Ugh. His question is about the other way around: how to generate a URL to an MVC controller action from a WebApi controller. Maybe he could simply inject MVC's UrlHelper. http://orchardpros.net/tickets/4510

  • I needed a way to send client code webapi url's so I can use ajax to get data. I have been looking and posting for a few months on this. I was even encouraged to submit a bug about it.

    https://orchard.codeplex.com/workitem/20937


    That may not be an issue after learning about the MVC UrlHelper, Thanks for posting this.

  • I will preface this comment by saying that I am often wrong, so forgive me if that is the case.

    After doing some tests this is what I found, when using default routes in orchard your sample code above would return a relative URL similar to the following:

    /[area name]/[controller]/[Action]?httproute=True

    So here are a few items I would love to know more about
    1. in orchard the URL should be /api/[area name]/[controller]/[Action], I have not been able to reproduce this using UrlHelper
    2. What is the purpose of the httproute=True?
    3. As a side note, you can urlHelper.RequestContext.HttpContext.Request.Url.Scheme as another parameter to get absolute url if needed, which is cool
    var actionUrl = _url.Action("Content", "Import", new {
    httproute = true,
    area = "Orchard.ImportExport"
    }, _url.RequestContext.HttpContext.Request.Url.Scheme);




  • @Rob: I think this is because there is no WebAPI route in your system that could correspond to this. You should retry either with a route that you know you have, or in the "deployment" branch. See my next post about declaring WebAPI routes.

  • I can see that my route description is incorrect, I am using a default orchard route. My main point was that it comes back with everything pretty much correct except it does not have the api in the url.

    api/{module.name}/{controller}/{id}

  • @Rob: yes, what you are getting back is a regular MVC route, because that's what the system finds, in the absence of a proper WebAPI route that can handle what you're passing in.

  • Ok, got it! Thanks for writing this stuff it is very helpful for those of us that are new to orchard.

Comments have been disabled for this content.