using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;
using System.Web.Http.Routing;

namespace ZQNB.Common.Web.Api
{
//针对WebApi的扩展
//目的是为了让WebApi支持命名空间的筛选
//程序启动时,替换IHttpControllerSelector选择器
//GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(GlobalConfiguration.Configuration));

public static class HttpRouteCollectionEx
{
public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, string[] namespaces)
{
return routes.MapHttpRoute(name, routeTemplate, defaults, null, null, namespaces);
}
public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler, string[] namespaces)
{
if (routes == null)
{
throw new ArgumentNullException("routes");
}
var routeValue = new HttpRouteValueDictionary(new { Namespace = namespaces });//设置路由值
var route = routes.CreateRoute(routeTemplate, new HttpRouteValueDictionary(defaults), new HttpRouteValueDictionary(constraints), routeValue, handler);
routes.Add(name, route);
return route;
}
}

public class NamespaceHttpControllerSelector : DefaultHttpControllerSelector
{
private const string NamespaceRouteVariableName = "Namespace";
private readonly HttpConfiguration _configuration;
private readonly Lazy<ConcurrentDictionary<string, Type>> _apiControllerCache;

public NamespaceHttpControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
_configuration = configuration;
_apiControllerCache = new Lazy<ConcurrentDictionary<string, Type>>(new Func<ConcurrentDictionary<string, Type>>(InitializeApiControllerCache));
}

private ConcurrentDictionary<string, Type> InitializeApiControllerCache()
{
IAssembliesResolver assembliesResolver = this._configuration.Services.GetAssembliesResolver();
var types = this._configuration.Services.GetHttpControllerTypeResolver().GetControllerTypes(assembliesResolver).ToDictionary(t => t.FullName, t => t);

return new ConcurrentDictionary<string, Type>(types);
}

public IEnumerable<string> GetControllerFullName(HttpRequestMessage request, string controllerName)
{
object namespaceName;
var apiControllerKeys = Enumerable.Empty<string>();
string[] namespaces = null;
var data = request.GetRouteData();
IEnumerable<string> allApiControllers = _apiControllerCache.Value.ToDictionary(t => t.Key,
t => t.Value, StringComparer.CurrentCultureIgnoreCase).Keys.ToList();
namespaces = (string[]) this.GetRouteValue(NamespaceRouteVariableName, data);

if (namespaces != null && namespaces.Any())
{
var area = (string) this.GetRouteValue("area", data);
if (!string.IsNullOrEmpty(area))
{
for (int i = 0; i < namespaces.Length; i++)
{
if (namespaces[i].Contains("{area}"))
{
namespaces[i] = namespaces[i].Replace("{area}", area);
}
}
}

return from n in namespaces
join k in allApiControllers on
string.Format("{0}.{1}{2}", n, controllerName, DefaultHttpControllerSelector.ControllerSuffix)
.ToLower() equals k.ToLower()
select k;
}
//get the defined namespace
return allApiControllers.Where(
k =>
k.EndsWith(
string.Format(".{0}{1}", controllerName, DefaultHttpControllerSelector.ControllerSuffix),
StringComparison.CurrentCultureIgnoreCase));
}

private object GetRouteValue(string key, IHttpRouteData httpRouteData)
{
object value;
if (httpRouteData.Route.DataTokens != null &&
httpRouteData.Route.DataTokens.TryGetValue(key, out value))
{
if (value != null)
{
return value;
}

}
if (httpRouteData.Values != null && httpRouteData.Values.TryGetValue(key, out value))
{
if (value != null)
{
return value;
}
}
return null;
}

public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
Type type;
if (request == null)
{
throw new ArgumentNullException("request");
}
string controllerName = this.GetControllerName(request);
if (string.IsNullOrEmpty(controllerName))
{
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
string.Format("No route providing a controller name was found to match request URI '{0}'", new object[] { request.RequestUri })));
}
IEnumerable<string> fullNames = GetControllerFullName(request, controllerName);
var enumerable = fullNames as string[] ?? fullNames.ToArray();
if (!enumerable.Any())
{
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
string.Format("No route providing a controller name was found to match request URI '{0}'", new object[] { request.RequestUri })));
}

//如果能匹配上多个,排除优先选择不在限制内的命名空间
if (this._apiControllerCache.Value.TryGetValue(enumerable.First(), out type))
{
return new HttpControllerDescriptor(_configuration, controllerName, type);
}
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
string.Format("No route providing a controller name was found to match request URI '{0}'", new object[] { request.RequestUri })));
}
}
}

最后Global

//设置我们自己的 ControllerFactory
ControllerBuilder.Current.SetControllerFactory(new NbDefaultControllerFactory(CoreServiceProvider.Current.GetAllInstances<IControllerProvider>()));
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(GlobalConfiguration.Configuration));

WebApi支持命名空间重名问题的更多相关文章

  1. MVC5为WebAPI添加命名空间的支持

    前言 默认情况下,微软提供的MVC框架模板中,WebAPI路由是不支持Namespace参数的.这导致一些比较大型的项目,无法把WebApi分离到单独的类库中. 本文将提供解决该问题的方案. 微软官方 ...

  2. asp.net MVC5为WebAPI添加命名空间的支持

    前言 默认情况下,微软提供的MVC框架模板中,WebAPI路由是不支持Namespace参数的.这导致一些比较大型的项目,无法把WebApi分离到单独的类库中. 本文将提供解决该问题的方案. 微软官方 ...

  3. MVC5为WebAPI添加命名空间的支持1

    前言 默认情况下,微软提供的MVC框架模板中,WebAPI路由是不支持Namespace参数的.这导致一些比较大型的项目,无法把WebApi分离到单独的类库中. 本文将提供解决该问题的方案. 微软官方 ...

  4. partial修饰符,可以让同类命名空间下出现重名

    public partial class Person { } public partial class Person { } partial修饰符,可以让同类命名空间下出现重名,两个类其实是一个类, ...

  5. 在IE中,JS方法名和input的name重名时,调用该方法无效

    在IE中,JS方法名和input的name重名时,调用该方法无效.提示:网页错误详细信息 用户代理: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1 ...

  6. 规避Javascript多人开发函数和变量重名问题

    函数和变量重名始终是一个令人头痛的问题,先讲变量吧,相信了解JS的朋友都知道,在JS中 是没有块级作用域的只有函数作用域,也就是说那些以大括号为界定符的代码块是管不住其中定义 的变量的作用域的,举例: ...

  7. JS重名解决方案

    一个页面如果引用多个JS,或者像ASP.NET MVC,一个视图包含多个子视图,每个子视图有自己的JS,那么变量.函数的重名冲突机会将会大增. 如何解决? 这里有一个方案: 1.用类来封装子页的JS代 ...

  8. 4.4 ROS节点名称重名

    4.4 ROS节点名称重名 场景:ROS 中创建的节点是有名称的,C++初始化节点时通过API:ros::init(argc,argv,"xxxx");来定义节点名称,在Pytho ...

  9. js方法入参或局部变量和全局变量重名,用来赋值全局变量会失败

    今天遇到个bug,最后终于知道原因了,js方法入参和全局变量重名,用入参赋值全局变量失败,就是说方法入参不能和全局变量重名. 现在下面的例子也说明,局部变量和全局变量不可以同名不光是入参,只要同名赋值 ...

随机推荐

  1. SuperSlidev2.1滑动门

    1.引用jQuery.js 和 jquery.SuperSlide.js 因为SuperSlide是基于jQuery的插件,所以前提必须先引用jQuery,再引用SuperSlide <head ...

  2. Hibernate总结2 API和配置文件

    1,Configuration 配置 获取config配置文件的方法 Configuration cfg = new Configuration(); cfg.下面的方法 configure() co ...

  3. mysql中判断记录是否存在方法比较

    我这里总结了判断记录是否存在的常用方法: sql语句:select count(*) from tablename; 然后读取count(*)的值判断记录是否存在.对于这种方法性能上有些浪费,我们只是 ...

  4. BZOJ 1040 【ZJOI2008】 骑士

    Description Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火 ...

  5. Linux execve函数簇用法

    exec函数簇实现的功能都是用一个新程序替换原来的程序,替换的内容包括堆栈段,代码段,进程控制器PCD,但是原进程的PID保持不变 int execl(const char *path, const ...

  6. Linux设置环境变量(解决许多命令找不到)

    不知道服务器被谁给改坏了,许多命令都不能使用找不到,但是可以在/usr/bin/,/usr/local/bin等里面找到源程序,当时首先想到的就是环境变量,因为Windows在设置了环境变量之后就可以 ...

  7. Vue系列:通过vue-router如何传递参数

    使用vue-router 来实现webapp的页面跳转,有时候需要传递参数,做法如下: 参考文献:http://router.vuejs.org/en/named.html  主要有以下几个步骤: ( ...

  8. WebPack系列:Webpack编译的代码如何在tomcat中使用时静态资源路径不对的问题如何解决

    问题:     使用webpack+vue做前端,使用tomcat提供api,然后npm run build之后需要将编译,生成如下文件: |   index.html \---appserver   ...

  9. Spring MVC 前后端 Json 方式交互和处理

    众所周知,在mvc中,数据是在各个层次之间进行流转是一个不争的事实. 而这种流转,也就会面临一些困境,这些困境,是由于数据在不同世界中的表现形式不同而造成的.   数据在页面上是一个扁平的,不带数据类 ...

  10. C#调用百度静态地图

    来深圳一年多了,感觉深圳的IT氛围确实比长沙好,工作和生活节奏比较快,适合于学习.来深后一直在现在所在的公司,部门从开始4个人,发展到现在10来人了,感觉还是不错的. 发现自己很少写博客了,倒不是学得 ...