I am trying to add some WebAPI support to my asp.net 4 RC site, and wish to put it into an area. I have seen that someone managed to get this running on the beta (here) ,
ASP.NET MVC 4 doesn't support WebAPI in Areas.
It is possible to extend DefaultHttpControllerSelector
to do this, but you should carefully read this excellent (and short) article: ASP.NET MVC 4 RC: Getting WebApi and Areas to play nicely. It works great.
I've successfully tested this solution with portable areas (MVCContrib). Basically, you have to:
PortableAreaRegistration.RegisterArea()
method): you can copy the static class into the PA project but I suggest to put it into a shared project.DefaultHttpControllerSelector
) into the host project.Add to Global.asax App_Start() the following line:
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new AreaHttpControllerSelector(GlobalConfiguration.Configuration));
There is one caveat with the implementation of AreaHttpControllerSelector
: the area name must correspond to the ApiController's namespace. For example, this is my PortableAreaRegistration
class:
namespace PortableAreasSample.MembershipArea
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MvcContrib.PortableAreas;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
public class MembershipRegistration : PortableAreaRegistration
{
public override void RegisterArea(System.Web.Mvc.AreaRegistrationContext context, IApplicationBus bus)
{
// GET /MembershipArea/GetAllUsers
context.MapHttpRoute("MembershipApi",
AreaName + "/{controller}/{id}",
new { area=AreaName, controller = "GetAllUsers", id = RouteParameter.Optional });
}
public override string AreaName
{
get { return "MembershipArea"; }
}
}
}
Just for completion, the following attributes exists, which could help people out of a bind (who won't follow eric's advice above...)
[Route ("api/interesting/{id?}")]
[RoutePrefix("api/interesting")]
http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2
Make sure you register the API route before the default route, else the default route will greedily capture everything!
Supporting areas in the web API URLs
You simply have to register the Web API route.
But this route must be registered before the other routes. If not, the requests to the web API will be mistakenly handled as if they were an MVC action.
When you're using areas, you must take into account that the registration for the areas routes is usually done before the registration of the non-area routes. I.e, in Global.asax Application_Start
you have these lines of code, in this order:
AreaRegistration.RegisterAllAreas();
// ...
RouteConfig.RegisterRoutes(RouteTable.Routes);
The first method call will invoke the RegisterArea
method of every found xxxAreaRegistration
class. And, inside this configuration you'll usually have something like this:
context.MapRoute(
"AreaName_default",
"AreaName/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
If you want to have Web API controllers inside this area, you must add the Web API route before this one, like so:
context.Routes.MapHttpRoute("AreaName_WebApiRoute",
"AreaName/Api/{controller}/{id}",
new { id = RouteParameter.Optional });
In this case, I'm assuming that you want to invoke your API controllers using an url like this: /AreaName/Api/ControllerName/Id
.
I usually store the Web API controllers inside an Api
folder inside the area folder, but it doesn't matter where you put them. Take into account that the API controllers will be found wherever they are and, if you use the same name for them in different areas, you'll get conflicts: they're found by the class name, not by the fully qualified (namespaced) name.
In few words: there's no real support for areas, but you can include them in their own folders inside the areas, and make them available on URL's which look like the ones of MVC controllers inside areas.
Supporting route namespaces
What if you want to have Web API controllers with the same name in different areas? If you really want to give real support for areas to Web API controllers, you have to implement and register a custom IHttpControllerSelector.
You have a good explanation, and a sample implementation here: ASP.NET Web API: Using Namespaces to Version Web APIs
This sample uses namespaces for versioning, but the code can be slightly modified to support areas namespaces.
You can put Api controllers in any folder you like, you don't need to create an Area like you did for MVC. What I usually do is create a subfolder 'Api' inside 'Controllers' folder of MVC site. Just register routes for your Api controllers and it will work.