WebAPI增加Area以支持无限层级同名Controller
来源:互联网 发布:php 常用魔术方法 编辑:程序博客网 时间:2024/05/01 19:07
微软的WebAPI默认实现逻辑
默认实现中不支持同名Controller,否则在访问时会报HttpError,在网上找到了各种路由自实现,如
给ASP.net Web API的Controller分类
搭建MVC及WebAPI项目框架时碰到的问题集合
在上述地址的帮助下,根据需求,重新编写了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
- 无限层级的组织机构
- 增加切片层级
- 数据库绑定TreeView,无限层级
- Mvc4 WebApi 支持jsonp
- webapi 支持namespace
- MVC WebApi 路由设置(自定义) 分区Area
- Java编程:将具有父子关系的数据库表数据转换为树形结构,支持无限层级
- CAN (Controller Area Network) BUS
- sql 用户名增加,同名的不增加
- TreeView绑定无限层级关系类
- 不用递归,C#实现无限层级树
- springmvc同名参数绑定支持
- 无限增加附件文本框!
- 无限增加附件文本框!
- 无限级分类 增加
- 启用 mvc webapi 支持 session
- WebApi JSONP的支持 c#
- 老二牛车Axure夜话:中继器系列视频教程之中继器可折叠菜单
- 更改windows系统的快捷键方法
- 使用jqzoom插件时
- Android与设计模式——组合(Composite)模式
- switch-case语句用法
- WebAPI增加Area以支持无限层级同名Controller
- 概述
- Linux启动过程详解
- sqlmap源码阅读之optparse
- C语言中文件操作
- pthread_create如何传递两个参数以上的参数
- Perl 单词边界
- 网络传输过程简析
- 通过WebService上传文件