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类型的数据对于数据的增.删.改.查,提供相对的资源操作,按照请求的类型 ...
随机推荐
- http authorization basic请求代码示例
/** * */ package testJava.java; import java.io.BufferedReader; import java.io.InputStream; import ja ...
- Sqli-labs less 30
Less-30 Less-30与less-29原理是一致的,我们可以看到less-30的sql语句为: 所以payload为: http://127.0.0.1:8080/sqli-labs/Less ...
- [译]如何使用 Docker 组件开发 Django 项目?
原文地址:Django Development With Docker Compose and Machine 以下为译文 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包 ...
- Javascript 正则表达式笔记
\d 元字符 + 量词 \w 常用的字符a-zA-Z0-9 .除回车之外的字符 ?0-1个字符 量词 只有前面是元字符,才变现量词 * 0-n 量词 /^\d+$/ 以字符开头,义字符结尾 [0-9] ...
- (11)nehe教程5---3D空间
3D空间: 我们使用多边形和四边形创建3D物体,在这一课里,我们把三角形变为立体的金子塔形状,把四边形变为立方体. 在上节课的内容上作些扩展,我们现在开始生成真正的3D对象,而不是象前两节课中那样3D ...
- nodejs的require模块及路径
在nodejs中,模块大概可以分为核心模块和文件模块. 核心模块是被编译成二进制代码,引用的时候只需require表示符即可,如(require('net')). 文件模块,则是指js文件.json文 ...
- linux下关于gz和bz2压缩格式的常用操作技巧
.gz和.bz2都是linux下压缩文件的格式,有点类似windows下的.zip和.rar文件..bz2和.gz的区别在于,前者比后者压缩率更高,后者比前者花费更少的时间. 也就是说同一个文件,压缩 ...
- Java-马士兵设计模式学习笔记-观察者模式-模拟Awt Button
一.概述 Java 的Awt是 Observer模式,现用Java自己模拟awt中Button的运行机制 二.代码 1.Test.java import java.text.DateFormat; i ...
- 1.BOM学习
1.bom.html <html> <head> <title>bom演示</title> <script type="text/jav ...
- iOS:核心动画之关键帧动画CAKeyframeAnimation
CAKeyframeAnimation——关键帧动画 关键帧动画,也是CAPropertyAnimation的子类,与CABasicAnimation的区别是: –CABasicAnimation只能 ...