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. python日期格式化与绘图

    画一个量随着时间变化的曲线是经常会遇到的需求,比如画软件用户数的变化曲线.画随时间变化的曲线主要用到的函数是matplotlib.pyplot.plot_date(date,num).由于其第一个变量 ...

  2. ef操作类

    基于Hi博客的类库 20160811 using Model; using System; using System.Collections.Generic; using System.Data.En ...

  3. 自己封装的操作DOM方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. ie6-ie8中不支持opacity透明度的解决方法

    ie6-ie8中是不支持的,需要加上下面这句话:filter: alpha(opacity=70);此外这种效果不能用ietester中的ie6测试,因为ietester的ie6这样写也是不透明的,但 ...

  5. Codevs 1910递归函数

    1910 递归函数  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题目描述 Description 对于一个递归函数w(a, b, c). 如果a <= ...

  6. 将函数传给webworker

    var zWorker = function (func,cb){ var node = document.createElement('script'),workerId='worker' + Da ...

  7. 【转】让Bootstrap 3兼容IE8浏览器

    FROM : http://www.ijophy.com/2014/05/bootstrap3-compatible-with-ie8.html 最近在研究Bootstrap(官方,Github)这个 ...

  8. QT 网络编程一

    QT如果要进行网络编程首先需要在.pro中添加如下代码:QT += network 在头文件中包含相关头文件 #include <QHostInfo> #include <QNetw ...

  9. NOI2018准备Day4

    上午9点20至11点50就做出了一道题,一个很基础的二分挡住了,原因是浮点数精度问题的处理,现在还搞不懂,为什么用double存进去两位小数过不了,用double存进去两位小数再*100再/100就能 ...

  10. JSP 和 ASP.NET 谁能主宰未来【转】

    随着计算机行业的发展,以后到底谁才是 web 网站开发的主宰者呢? 1. 说说JSP.(本人工作中用的最多的就是JSP) JSP. JavaServer Pages 是Java技术的一部分,可以说是J ...