ASP.NET MVC 4 WebAPI. Support Areas in HttpControllerSelector
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的更多相关文章
- 给Asp.Net MVC及WebApi添加路由优先级
一.为什么需要路由优先级 大家都知道我们在Asp.Net MVC项目或WebApi项目中注册路由是没有优先级的,当项目比较大.或有多个区域.或多个Web项目.或采用插件式框架开发时,我们的路由注册很可 ...
- 【转载】为ASP.NET MVC及WebApi添加路由优先级
路由方面的: 转载地址:http://www.jb51.net/article/73417.htm Author:lijiao 这是一个对Asp.Net Mvc的一个很小的功能拓展,小项目可能不太需要 ...
- (转)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的创建与执行 ...
- AJAX跨域调用ASP.NET MVC或者WebAPI服务
关于AJAX跨域调用ASP.NET MVC或者WebAPI服务的问题及解决方案 作者:陈希章 时间:2014-7-3 问题描述 当跨域(cross domain)调用ASP.NET MVC或者ASP. ...
- AJAX跨域调用ASP.NET MVC或者WebAPI服务的解决方案
问题描述 当跨域(cross domain)调用ASP.NET MVC或者ASP.NET Web API编写的服务时,会发生无法访问的情况. 重现方式 使用模板创建一个最简单的ASP.NET Web ...
- ASP.NET MVC对WebAPI接口操作(添加,更新和删除)
昨天<怎样操作WebAPI接口(显示数据)>http://www.cnblogs.com/insus/p/5670401.html 既有使用jQuery,也有使作HttpClient来从数 ...
- 关于AJAX跨域调用ASP.NET MVC或者WebAPI服务的问题及解决方案
作者:陈希章 时间:2014-7-3 问题描述 当跨域(cross domain)调用ASP.NET MVC或者ASP.NET Web API编写的服务时,会发生无法访问的情况. 重现方式 使用模 ...
- ASP.NET MVC 4 WebAPI Simple Sample
// Controllers.cs namespace Microshaoft.WebApi.Controllers { using Microshaoft.WebApi.Models; using ...
- Asp.Net MVC part6 WebAPI
两种web服务SOAP风格:基于方法,产品是WebServiceREST风格:基于资源,产品是WebAPI可以返回json.xml类型的数据对于数据的增.删.改.查,提供相对的资源操作,按照请求的类型 ...
随机推荐
- 一张思维导图说明jQuery的AJAX请求机制
比文字描述清晰多了吧?而且越是复杂的逻辑,思维导图的作用就越大,同时对阅读源码也是一种快捷的方法. 看不清楚的话可以右键,在新标签页中打开图片,或者保存本地.
- 通过 Mesos、Docker 和 Go,使用 300 行代码创建一个分布式系统
[摘要]虽然 Docker 和 Mesos 已成为不折不扣的 Buzzwords ,但是对于大部分人来说它们仍然是陌生的,下面我们就一起领略 Mesos .Docker 和 Go 配合带来的强大破坏力 ...
- LA 4727
Integers 1, 2, 3,..., n are placed on a circle in the increasing order as in the following figure. W ...
- Quant面试准备5本书
Heard on The Street: Quantitative Questions from Wall Street Job Interviews - Timothy Falcon Crack F ...
- Android 4.4KitKat AudioRecord 流程分析
Android是架构分为三层: 底层 Linux Kernel 中间层 主要由C++实现 (Android 60%源码都是C++实现) 应用层 主要由JAVA开发的应用程序 应用程序执行 ...
- java基础知识回顾之抽象类
/* 抽象类: 抽象:笼统,模糊,看不懂!不具体. 特点: 1,方法只有声明没有实现时,该方法就是抽象方法,需要被abstract修饰. 抽象方法必须定义在抽象类中.该类必须也被abstract修饰. ...
- 【poj2478-Farey Sequence】递推求欧拉函数-欧拉函数的几个性质和推论
http://poj.org/problem?id=2478 题意:给定一个数x,求<=x的数的欧拉函数值的和.(x<=10^6) 题解:数据范围比较大,像poj1248一样的做法是不可行 ...
- python爬煎蛋妹子图
# python3 # jiandan meizi tu import urllib import urllib.request as req import os import time import ...
- PHP组合模式
一.组合模式简述 1.组合定义了一个单根继承体系,使具有不同职责的集合可以并肩工作 2.如果想像对待单个对象一样对待组合对象,那么组合模式十分有用 3.组合模式不能很好地在关系数据库中保存数据,但却非 ...
- x11vnc
http://cisight.com/how-to-setup-vnc-server-remote-desktop-in-ubuntu-11-10-oneiric/ Install VNC serve ...