This article was written for ASP.NET MVC 4 RC (Release Candidate). If you are still using Beta version of ASP.NET MVC 4 then you have to read the previous article.

HttpControllerFactory was deleted in ASP.NET MVC 4 RC. Actually, it was replaced by two interfaces: IHtttpControllerActivator and IHttpControllerSelector.

Unfortunately DefaultHttpControllerSelector still doesn't support Areas by default. To support it you have to write your HttpControllerSelector from scratch. To be honest, I will derive my selector from DefaultHttpControllerSelector.

In this post I will show you how you can do it.

AreaHttpControllerSelector

First of all, you have to derive your class from DefaultHttpControllerSelector class:

public class AreaHttpControllerSelector : DefaultHttpControllerSelector
{
private readonly HttpConfiguration _configuration; public AreaHttpControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
_configuration = configuration;
}
}

In the constructor mentioned above I called the base constructor and stored the HttpConfiguration. We will use it a little bit later.

My code will use two constants:

private const string ControllerSuffix = "Controller";
private const string AreaRouteVariableName = "area";

You can understand why we need first one by name. The second one contains the name of the variable which we will use to specify area name in Routes collection.

Somewhere we have to store all of the API controllers.

private Dictionary<string, Type> _apiControllerTypes;

private Dictionary<string, Type> ApiControllerTypes
{
get { return _apiControllerTypes ?? (_apiControllerTypes = GetControllerTypes()); }
} private static Dictionary<string, Type> GetControllerTypes()
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies(); var types = assemblies.SelectMany(a => a.GetTypes().Where(t => !t.IsAbstract && t.Name.EndsWith(ControllerSuffix) && typeof(IHttpController).IsAssignableFrom(t)))
.ToDictionary(t => t.FullName, t => t); return types;
}

Method GetControllerTypes takes all the API controllers types from all of your assemblies, and store it inside the dictionary, where the key is FullName of the type and value is the type itself.
Of course we will set this dictionary only once. And then just use it.

Now we are ready to implement one of the important method:

public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
return GetApiController(request) ?? base.SelectController(request);
}

In that method I try to take the HttpControllerDescriptor from method GetApiController and if it return null then call the base method.

And additional methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
private static string GetAreaName(HttpRequestMessage request)
{
    var data = request.GetRouteData();
 
    if (!data.Values.ContainsKey(AreaRouteVariableName))
    {
        return null;
    }
 
    return data.Values[AreaRouteVariableName].ToString().ToLower();
}
 
private Type GetControllerTypeByArea(string areaName, string controllerName)
{
    var areaNameToFind = string.Format(".{0}.", areaName.ToLower());
    var controllerNameToFind = string.Format(".{0}{1}", controllerName, ControllerSuffix);
 
    return ApiControllerTypes.Where(t => t.Key.ToLower().Contains(areaNameToFind) && t.Key.EndsWith(controllerNameToFind, StringComparison.OrdinalIgnoreCase))
            .Select(t => t.Value).FirstOrDefault();
}
 
private HttpControllerDescriptor GetApiController(HttpRequestMessage request)
{
    var controllerName = base.GetControllerName(request);
 
    var areaName = GetAreaName(request);
    if (string.IsNullOrEmpty(areaName))
    {
        return null;
    }
 
    var type = GetControllerTypeByArea(areaName, controllerName);
    if (type == null)
    {
        return null;
    }
 
    return new HttpControllerDescriptor(_configuration, controllerName, type);
}

Method GetAreaName just takes area name from HttpRequestMessage.

Method GetControllerTypeByArea are tries to find the controller in the ApiControllerTypes by full name of the controller where the full name contains area's name surrounded by "." (e.g. ".Admin.") and ends with controller name + controller suffix (e.g. UsersController).

And if a controller type found then method GetApiController will create and return back HttpControllerDescriptor.

So, my AreaHttpControllerSelector is ready to be registered in my application.

Registering AreaHttpControllerSelector

The next thing you have to do is to say to your application to use this controller selector instead of DefaultHttpControllerSelector. And fortunately it is really easy - just add one additional line to the end of Application_Start method in Glogal.asax file:

1
2
3
4
5
protected void Application_Start()
{
    // your default code
            GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new AreaHttpControllerSelector(GlobalConfiguration.Configuration));
}

That's all.

Using AreaHttpControllerSelector

If you did everything right, now you can forget about that "nightmare" code mentioned above. And just start to use it!

You have to add new HttpRoute to your AreaRegistration.cs file:

1
2
3
4
5
6
7
8
9
10
public override void RegisterArea(AreaRegistrationContext context)
{
    context.Routes.MapHttpRoute(
        name: "Admin_Api",
        routeTemplate: "api/admin/{controller}/{id}",
        defaults: new { area = "admin", id = RouteParameter.Optional }
    );
 
    // other mappings
}

Or just use one global route in your Global.asax like:

1
2
3
4
5
routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{area}/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

 

ASP.NET MVC 4 WebAPI. Support Areas in HttpControllerSelector的更多相关文章

  1. 给Asp.Net MVC及WebApi添加路由优先级

    一.为什么需要路由优先级 大家都知道我们在Asp.Net MVC项目或WebApi项目中注册路由是没有优先级的,当项目比较大.或有多个区域.或多个Web项目.或采用插件式框架开发时,我们的路由注册很可 ...

  2. 【转载】为ASP.NET MVC及WebApi添加路由优先级

    路由方面的: 转载地址:http://www.jb51.net/article/73417.htm Author:lijiao 这是一个对Asp.Net Mvc的一个很小的功能拓展,小项目可能不太需要 ...

  3. (转)ASP.NET Mvc 2.0 - 1. Areas的创建与执行

    转自:http://www.cnblogs.com/terrysun/archive/2010/04/13/1711218.html ASP.NET Mvc 2.0 - 1. Areas的创建与执行 ...

  4. AJAX跨域调用ASP.NET MVC或者WebAPI服务

    关于AJAX跨域调用ASP.NET MVC或者WebAPI服务的问题及解决方案 作者:陈希章 时间:2014-7-3 问题描述 当跨域(cross domain)调用ASP.NET MVC或者ASP. ...

  5. AJAX跨域调用ASP.NET MVC或者WebAPI服务的解决方案

    问题描述 当跨域(cross domain)调用ASP.NET MVC或者ASP.NET Web API编写的服务时,会发生无法访问的情况. 重现方式 使用模板创建一个最简单的ASP.NET Web ...

  6. ASP.NET MVC对WebAPI接口操作(添加,更新和删除)

    昨天<怎样操作WebAPI接口(显示数据)>http://www.cnblogs.com/insus/p/5670401.html 既有使用jQuery,也有使作HttpClient来从数 ...

  7. 关于AJAX跨域调用ASP.NET MVC或者WebAPI服务的问题及解决方案

      作者:陈希章 时间:2014-7-3 问题描述 当跨域(cross domain)调用ASP.NET MVC或者ASP.NET Web API编写的服务时,会发生无法访问的情况. 重现方式 使用模 ...

  8. ASP.NET MVC 4 WebAPI Simple Sample

    // Controllers.cs namespace Microshaoft.WebApi.Controllers { using Microshaoft.WebApi.Models; using ...

  9. Asp.Net MVC part6 WebAPI

    两种web服务SOAP风格:基于方法,产品是WebServiceREST风格:基于资源,产品是WebAPI可以返回json.xml类型的数据对于数据的增.删.改.查,提供相对的资源操作,按照请求的类型 ...

随机推荐

  1. mysql死锁,等待资源,事务锁,Lock wait timeout exceeded; try restarting transaction解决

    前面已经了解了InnoDB关于在出现锁等待的时候,会根据参数innodb_lock_wait_timeout的配置,判断是否需要进行timeout的操作,本文档介绍在出现锁等待时候的查看及分析处理: ...

  2. ZOJ2923 Calculate Roads(SPFA上的dp)

    算是学了图dp后的第一次应用吧.题目其实真的是非常不严谨,什么都没说,基本靠猜,而且严格来说数据应该会有爆int的,不过不管那么多啦,思路对了就好- -0 #include<iostream&g ...

  3. WAMP error: Forbidden You don't have permission to access /{you_app_name} on this server

    Forbidden You don't have permission to access /{you_app_name}on this server. 需要修改两处: wamp\bin\apache ...

  4. 传说中的WCF(8):玩转消息协定

    Message翻译成中文,相信各位不陌生,是啊,就是消息,在WCF中也有消息这玩意儿,不知道你怎么去理解它.反正俺的理解,就像我们互发短信一个道理,通讯的双方就是服务器与客户端,说白了吧,就是二者之间 ...

  5. 编程实现linux下的shell

    /************************************************************************* > File Name: Kris_shel ...

  6. linq 常用语句

    自己练习的 switch (productDataAnalysisQuery.DataType) { : var data = (from hp in GPEcontext.hbl_product j ...

  7. Newtonsoft.Json.dll

    代码 using System; DoNet2.0 需要借助于Newtonsoft.Json.dll using System.IO; using System.Text; using Newtons ...

  8. unity 脚本(自定义组件)的事件触发关系

  9. Eclipse中WEB项目自动部署到Tomcat

    原因 很长时间没用Eclipse了,近期由于又要用它做个简单的JSP项目,又要重新学习了,虽然熟悉的很快,但记忆总是很模糊,偶尔犯错,以前很少写博客,现在感觉还是很有必要的,编程中每个人对于犯过的错误 ...

  10. VS2010/MFC编程入门之四(MFC应用程序框架分析)

    VS2010/MFC编程入门之四(MFC应用程序框架分析)-软件开发-鸡啄米 http://www.jizhuomi.com/software/145.html   上一讲鸡啄米讲的是VS2010应用 ...