MVC API 中如何应用Area

原文的标题:

ASP.NET MVC & WebAPI


原文的内容:

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:
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:

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:
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:

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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值