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( ...
随机推荐
- C/C++ 笔试、面试题目大汇总2
http://www.cnblogs.com/fangyukuan/archive/2010/09/18/1830493.html 一.找错题 试题1: void test1() { charstri ...
- 安装 Visual Studio,连接中国区 Azure
中国数据中心 目前,中国区 Azure 有两个数据中心,在位置字段中显示为“中国北部”和“中国东部”. 在 Azure 上创建应用程序的区别 在中国区 Azure 上开发应用程序与在境外 Azure ...
- 一题多解(五) —— topK(数组中第 k 大/小的数)
根据对称性,第 k 大和第 k 小,在实现上,是一致的,我们就以第 k 小为例,进行说明: 法 1 直接排序(sort(A, A+N)),当使用一般时间复杂度的排序算法时,其时间复杂度为 O(N2) ...
- SpringBoot使用jsp作为视图模板&常规部署
springboot其实并不推荐使用jsp作为视图模板,其默认采用Thymeleaf作为模板,出于对其没有研究,故考虑目前阶段仍然使用jsp作为视图模板.下面就展开实践案例过程: 1.首先创建一个js ...
- 详解Qt,并举例说明动态编译(shared)和静态编译(static)以及debug and release 编译版本区别(可产生静态版的Debug版本,需要把-release 改为 –debug-and-release)
作为初入Qt学习的新人,花了整整一两天时间,对Qt编译版本等问题进行了一步步探索,首先感谢网站博客中文章,开始也不是很明白一些几个问题: 1.Qt版本问题 作为初学者,可能下载时这么多版本,如何选择呢 ...
- jQuery中的Deferred和promise
promise:http://www.alloyteam.com/2014/05/javascript-promise-mode/ 1 jQuery 中的 Deferred 和 Promises : ...
- WPF UserControl 的绑定事件、属性、附加属性
原文:WPF UserControl 的绑定事件.属性.附加属性 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Vblegend_2013/arti ...
- iText 制作PDF
前言 由于在MVC项目中需要使用PDF,所以自己抽空也来看看itext,以便于丰富自己的知识吧.在此也简单的记录一下,说不定以后可能还用的到. 在此您可以下载你想使用的版本http://sourcef ...
- 1 Task的简单实用
Task是thread和threadpool两者结合的产物,吸收了二者的优点 进一步添加了一些新的 优秀的功能. using System; using System.Threading.Tasks ...
- 2 DDD理论学习2 领域
一个领域本质上可以理解为就是一个问题域,只要是同一个领域,那问题域就相同. 所以,只要我们确定了系统所属的领域,那这个系统的核心业务,即要解决的关键问题.问题的范围边界就基本确定了. 领域首先要拆分成 ...