博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WebAPI增加Area以支持无限层级同名Controller
阅读量:6842 次
发布时间:2019-06-26

本文共 4880 字,大约阅读时间需要 16 分钟。

原文:

默认实现中不支持同名Controller,否则在访问时会报HttpError,在网上找到了各种路由自实现,如

在上述地址的帮助下,根据需求,重新编写了AreaHttpControllerSelector,路由原理与上述地址大同小异,均是通过路由匹配拼接FullName,然后匹配最接近的ApiController,而所谓的最接近,就是指如果根据拼接的Name获取到了多个匹配项,则获取命名空间节点数最少的那个ApiController,以保证在多次注册路由规则时,能够按照从繁到简的方式匹配出相应的Controller(需要注意的是AreaHttpControllerSelector是以controller作为结束分割点的),举例如下

假定注册了以下路由匹配规则(controller、action均为WebAPI的路由占用字符)

config.Routes.MapHttpRoute(                name: "DefaultAreaApi",                routeTemplate: "api/{area}/{controller}/{action}/{id}",                defaults: new { id = RouteParameter.Optional }            );            config.Routes.MapHttpRoute(                name: "DefaultApi",                routeTemplate: "api/{controller}/{action}/{id}",                defaults: new { id = RouteParameter.Optional }            );
在Controller目录下存在多层同名且不同层级的Controller,如:

Controller/Area/SameController,对应的命名空间为Controller.Area.SameController

Controller/SameController,对应的命名空间为Controller.SameController

通过api/Area/Same/Get将匹配到Controller/Area/SameController

通过api/Same/Get将匹配到Controller/SameController

相比于参考网址,重新编写的AreaHttpControllerSelector可以支持无限层级的区域,只要命名空间支持,比如

"api/{area1}/{area1}/{area2}/{area3}/{controller}/{action}/{id}"

以下是具体的AreaHttpControllerSelector代码

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Web;using System.Web.Http.Dispatcher;using System.Net.Http;using System.Web.Http;using System.Web.Http.Controllers;using System.Net;namespace WebAPI{    ///     /// Represents a area System.Web.Http.Dispatcher.IHttpControllerSelector instance    ///     public class AreaHttpControllerSelector : DefaultHttpControllerSelector    {        private readonly HttpConfiguration _configuration;        ///         /// Lazy 当前程序集中包含的所有IHttpController反射集合,TKey为小写的Controller        ///         private readonly Lazy
> _apiControllerTypes; private ILookup
ApiControllerTypes { get { return this._apiControllerTypes.Value; } } ///
/// Initializes a new instance of the AreaHttpControllerSelector class /// ///
public AreaHttpControllerSelector(HttpConfiguration configuration) : base(configuration) { this._configuration = configuration; this._apiControllerTypes = new Lazy
>(this.GetApiControllerTypes); } ///
/// 获取当前程序集中 IHttpController反射集合 /// ///
private ILookup
GetApiControllerTypes() { IAssembliesResolver assembliesResolver = this._configuration.Services.GetAssembliesResolver(); return this._configuration.Services.GetHttpControllerTypeResolver() .GetControllerTypes(assembliesResolver) .ToLookup(t => t.Name.ToLower().Substring(0, t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length), t => t); } ///
/// Selects a System.Web.Http.Controllers.HttpControllerDescriptor for the given System.Net.Http.HttpRequestMessage. /// ///
///
public override HttpControllerDescriptor SelectController(HttpRequestMessage request) { HttpControllerDescriptor des = null; string controllerName = this.GetControllerName(request); if (!string.IsNullOrWhiteSpace(controllerName)) { var groups = this.ApiControllerTypes[controllerName.ToLower()]; if (groups != null && groups.Any()) { string endString; var routeDic = request.GetRouteData().Values;//存在controllerName的话必定能取到IHttpRouteData if (routeDic.Count > 1) { StringBuilder tmp = new StringBuilder(); foreach (var key in routeDic.Keys) { tmp.Append('.'); tmp.Append(routeDic[key]); if (key.Equals(DefaultHttpControllerSelector.ControllerSuffix, StringComparison.CurrentCultureIgnoreCase)) {//如果是control,则代表命名空间结束 break; } } tmp.Append(DefaultHttpControllerSelector.ControllerSuffix); endString = tmp.ToString(); } else { endString = string.Format(".{0}{1}", controllerName, DefaultHttpControllerSelector.ControllerSuffix); } //取NameSpace节点数最少的Type var type = groups.Where(t => t.FullName.EndsWith(endString, StringComparison.CurrentCultureIgnoreCase)) .OrderBy(t => t.FullName.Count(s => s == '.')).FirstOrDefault();//默认返回命名空间节点数最少的第一项 if (type != null) { des = new HttpControllerDescriptor(this._configuration, controllerName, type); } } } if (des == null) { throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound, string.Format("No route providing a controller name was found to match request URI '{0}'", request.RequestUri))); } return des; } }}

而用法就是在Global文件的Application_Start方法中替换注册

GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector),                                                   new AreaHttpControllerSelector(                                                       GlobalConfiguration.Configuration));

转载地址:http://xjcul.baihongyu.com/

你可能感兴趣的文章
py2exe的逆向
查看>>
shell 游戏系列 俄罗斯方块
查看>>
DDOS和sql注入网络***实验
查看>>
DDN与×××备份互联
查看>>
Flask最佳实践
查看>>
kafka源码剖析(三)之日志管理-LogManager
查看>>
tcp连接wait连接过多解决
查看>>
EVE模拟器教程之如何设置预配
查看>>
Dell PowerEdge R720xd 上的 Microsoft Exchange 2010 与 R510 上的 Exchange 2007 之间的跨代大PK...
查看>>
A记录、NS记录、CNAME记录的区别和联系
查看>>
nginx搭建支持http和rtmp协议的流媒体服务器之---环境搭建
查看>>
Java 内存分配全面浅析
查看>>
Linux 文件与权限管理
查看>>
2016-12-7 第一次 测试
查看>>
ansible 安装与基本功能的使用
查看>>
AIX引导级别及级别修改
查看>>
获得第一批用户
查看>>
2月第一周网络安全报告:放马站点域名315个
查看>>
大数据,TB、PB、EB,你了解多少?
查看>>
CSS3中的弹性流体盒模型技术详解(一)
查看>>