WebAPI增加Area以支持无限层级同名Controller
原文:WebAPI增加Area以支持无限层级同名Controller
默认实现中不支持同名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
{
/// <summary>
/// Represents a area System.Web.Http.Dispatcher.IHttpControllerSelector instance
/// </summary>
public class AreaHttpControllerSelector : DefaultHttpControllerSelector
{
private readonly HttpConfiguration _configuration;
/// <summary>
/// Lazy 当前程序集中包含的所有IHttpController反射集合,TKey为小写的Controller
/// </summary>
private readonly Lazy<ILookup<string, Type>> _apiControllerTypes;
private ILookup<string, Type> ApiControllerTypes
{
get
{
return this._apiControllerTypes.Value;
}
}
/// <summary>
/// Initializes a new instance of the AreaHttpControllerSelector class
/// </summary>
/// <param name="configuration"></param>
public AreaHttpControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
this._configuration = configuration;
this._apiControllerTypes = new Lazy<ILookup<string, Type>>(this.GetApiControllerTypes);
}
/// <summary>
/// 获取当前程序集中 IHttpController反射集合
/// </summary>
/// <returns></returns>
private ILookup<string, Type> 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);
}
/// <summary>
/// Selects a System.Web.Http.Controllers.HttpControllerDescriptor for the given System.Net.Http.HttpRequestMessage.
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
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));
WebAPI增加Area以支持无限层级同名Controller的更多相关文章
- Java编程:将具有父子关系的数据库表数据转换为树形结构,支持无限层级
在平时的开发工作中,经常遇到这样一个场景,在数据库中存储了具有父子关系的数据,需要将这些数据以树形结构的形式在界面上进行展示.本文的目的是提供了一个通用的编程模型,解决将具有父子关系的数据转换成树形结 ...
- 简单叨叨bootstrap按钮无限层级下拉菜单的实现
0.写在前面的话 最近看书都懈怠了,又正值新项目,虽说并不是忙得不可开交,好吧我老实交待,我就是偷懒了其实,博客也没更.言归正传,对于前端的不熟悉现在确实是个让我头疼的事情,以至于一些功能要在网络上漫 ...
- 自动给 Asp.Net Core WebApi 增加 ApiVersionNeutral
自动给 Asp.Net Core WebApi 增加 ApiVersionNeutral Intro 新增加一个 Controller 的时候,经常忘记在 Controller 上增加 ApiVers ...
- django 无限层级的评论
一.摘要 拓展 django 官方的评论库,为评论提供无限层级的支持. 二.demo演示 访问链接: https://github.com/zmrenwu/django-mptt-comments 下 ...
- MVC5为WebAPI添加命名空间的支持
前言 默认情况下,微软提供的MVC框架模板中,WebAPI路由是不支持Namespace参数的.这导致一些比较大型的项目,无法把WebApi分离到单独的类库中. 本文将提供解决该问题的方案. 微软官方 ...
- 自己定义 ViewGroup 支持无限循环翻页之三(响应回调事件)
大家假设喜欢我的博客,请关注一下我的微博,请点击这里(http://weibo.com/kifile),谢谢 转载请标明出处,再次感谢 ################################ ...
- js treeData 树形数据结构 无限层级(转载)
js实现无限层级树形数据结构(创新算法) 转载:https://blog.csdn.net/Mr_JavaScript/article/details/82817177 由于做项目的需要,把一个线性数 ...
- asp.net MVC5为WebAPI添加命名空间的支持
前言 默认情况下,微软提供的MVC框架模板中,WebAPI路由是不支持Namespace参数的.这导致一些比较大型的项目,无法把WebApi分离到单独的类库中. 本文将提供解决该问题的方案. 微软官方 ...
- SQL查询无限层级结构的所有下级,所有上级
无限层级结构的table1表,Id(主键),ParentId(父级id)查询某个Id的所有下级或所有上级,使用WITH AS,UNION ALL 查询 1.查询Id为1所有的下级 WITH T AS( ...
随机推荐
- Android下载文件提示文件不存在。。。 java.io.FileNotFoundException
遇到这个错误java.io.FileNotFoundException,事实上文件是存在的,把地址复制到手机浏览器都能够直接下载的,但为嘛不能下载呢. Error in downloadBitmap ...
- HTML中DOM对象的属性和方法的层级关系是怎样的?(目录即层次)
HTML中DOM对象的属性和方法的层级关系是怎样的?(目录即层次) 一.总结 一句话总结:目录就是测试题 1.document取得元素(get element)的方式有哪几种? 解答:四种,分别是id ...
- 学习鸟哥的Linux私房菜笔记(3)——基础使用
一.设备文件 设备在Linux中以特殊文件的形式存在 块(block)设备文件 字符(character)设备文件 设备文件所在位置 查看设备类型 二.虚拟控制台及用户身份切换 在系统中有12个虚拟控 ...
- 【BZOJ 1029】[JSOI2007]建筑抢修
[题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1029 [题意] [题解] /* 按照T2升序排 顺序枚举每一个建筑; 如果当前建筑能够 ...
- 基于PCM2912a的USB声卡设计
将近一年时间没有做过硬件了,感觉都不会用Altium Designer软件了.这次做这个USB 声卡有两个目的,其一是复习Altium Designer软件:其二是在业余时间找个事做做,打发一下自己的 ...
- [02]基于webservice权限系统
面前,我们已经介绍过.如何使用cxf建立webservice. 那我们要介绍的这款许可制度表结构. 此权限管理系统分为部门管理.员工管理.角色管理,权限管理,授权的人才和企业管理(这里不涉及) 角色管 ...
- 《iOS8 Swift编程指南》类书图像
终于拿到了样书.虽然已经猜到这将是一本很厚的书(63万字),但要真正看到实体书或者当我吃了一惊: 从以下这张照片看则更直观了.居然比艾伦.J.马库斯的<投资学>(634页)还要厚: 这本书 ...
- UWP 和 WPF 对比
原文:UWP 和 WPF 对比 本文告诉大家 UWP 和 WPF 的不同. 如果在遇到技术选择或者想和小伙伴吹的时候可以让他以为自己很厉害,那么请继续看. 如果在看这文章还不知道什么是 UWP 和 W ...
- Cordova 返回键切换后台
这里需要用到 cordova-plugin-backbutton 这个插件 1.安装插件,命令窗口输入(当前目录是你项目所在的目录) cordova plugin add cordova-plugin ...
- [ACM] POJ 2689 Prime Distance (筛选范围大素数)
Prime Distance Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12811 Accepted: 3420 D ...