MVC5为WebAPI添加命名空间的支持1
前言
默认情况下,微软提供的MVC框架模板中,WebAPI路由是不支持Namespace参数的。这导致一些比较大型的项目,无法把WebApi分离到单独的类库中。
本文将提供解决该问题的方案。
微软官方曾经给出过一个关于WebAPI支持Namespace的扩展,其主要内容就是自定义实现了IHttpControllerSelector接口,通过路由配置时替换掉MVC中自带的DefaultHttpControllerSelector达到WebAPI支持Namespace的目的。但是经过我的测试,效果并不好。这就就不贴微软官方的源码了。
解决方案
下面我介绍一下我的解决方案。
首先看一下我自定义的目录结构,如下图:
首先定义一个类,名字可以随意,我这里命名为ZhuSirNamespaceHttpControllerSelector,他继承自MVC框架默认的DefaultHttpControllerSelector类,该继承类主要目的是在请求URI到达WebAPI路由时检索我们指定的命名空间的WebAPI控制器。下面是ZhuSirNamespaceHttpControllerSelector类的源代码,可直接复制到你自己的项目中就可以用:

/// <summary>
/// 扩展自DefaultHttpControllerSelector类的控制器选择器,目前在用
/// </summary>
public class ZhuSirNamespaceHttpControllerSelector : DefaultHttpControllerSelector
{
private const string NamespaceRouteVariableName = "namespaces";
private readonly HttpConfiguration _configuration;
private readonly Lazy<ConcurrentDictionary<string, Type>> _apiControllerCache; public ZhuSirNamespaceHttpControllerSelector(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 data = request.GetRouteData();
IEnumerable<string> keys = _apiControllerCache.Value.ToDictionary<KeyValuePair<string, Type>, string, Type>(t => t.Key,
t => t.Value, StringComparer.CurrentCultureIgnoreCase).Keys.ToList(); if (!data.Values.TryGetValue(NamespaceRouteVariableName, out namespaceName))
{
return from k in keys
where k.EndsWith(string.Format(".{0}{1}", controllerName,
DefaultHttpControllerSelector.ControllerSuffix), StringComparison.CurrentCultureIgnoreCase)
select k;
} string[] namespaces = (string[])namespaceName;
return from n in namespaces
join k in keys on string.Format("{0}.{1}{2}", n, controllerName,
DefaultHttpControllerSelector.ControllerSuffix).ToLower() equals k.ToLower()
select k;
} 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("无法通过API路由匹配到您所请求的URI '{0}'",
new object[] { request.RequestUri })));
}
IEnumerable<string> fullNames = GetControllerFullName(request, controllerName);
if (fullNames.Count() == 0)
{
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
string.Format("无法通过API路由匹配到您所请求的URI '{0}'",
new object[] { request.RequestUri })));
} if (this._apiControllerCache.Value.TryGetValue(fullNames.First(), out type))
{
return new HttpControllerDescriptor(_configuration, controllerName, type);
}
throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.NotFound,
string.Format("无法通过API路由匹配到您所请求的URI '{0}'",
new object[] { request.RequestUri })));
}
}

第二步,需要我们配置WebAPI路由设置,添加{ namespaces }片段变量,同时也可以直接为其设置默认值,然后替换掉原MVC框架中的DefaultHttpControllerSelector选额器为我们之前扩展的ZhuSirNamespaceHttpControllerSelector选额器。这里需要注意片段变量的变量名namespaces一定要与我们ZhuSirNamespaceHttpControllerSelector中定义的NamespaceRouteVariableName字符串常量的值一致。下面贴出WebApiConfig的源码:

public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//配置检查Api控制后缀为ApiController
//var suffix = typeof(MicrosoftNamespaceHttpControllerSelector)
// .GetField("ControllerSuffix", BindingFlags.Static | BindingFlags.Public);
//if (suffix != null)
//{
// suffix.SetValue(null, "ApiController");
//} // Web API 配置和服务
// 将 Web API 配置为仅使用不记名令牌身份验证。
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); // 对 JSON 数据使用混合大小写。
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); // Web API 路由
config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}/{namespaces}",
defaults: new { id = RouteParameter.Optional ,namespaces = new[] { "ZhuSir.HMS.WebApi.ApiControllers" } }
); config.Services.Replace(typeof(IHttpControllerSelector), new ZhuSirNamespaceHttpControllerSelector(config));
}
}

如上源码。我们替换了原MVC框架的DefaultHttpControllerSelector为ZhuSirNamespaceHttpControllerSelector,并且指定了默认的namespaces为ZhuSir.HMS.WebApi.ApiControllers。大体意思就是当URL为 http://XXX/api/testApi时,WebApi路由将在ZhuSir.HMS.WebApi.ApiControllers命名空间下寻找名称为testApi的WebAPI控制器的Get方法。
当然,WebAPI控制器除了集成字ApiController意外还要注意命名规范,都需要以Controller结尾,为了不让API控制器与MVC控制器重名,我都以ApiController结尾。下面贴出testAPI的源码:

namespace ZhuSir.HMS.WebApi.ApiControllers
{
public class TestApiController : ApiController
{
[HttpGet]
public string Gettest()
{
return "测试数据";
}
}
}

测试
程序Debug,录入URL: http://localhost:4541/api/TestApi,得到如下结果:
可以看出,WebAPI路由成功访问到了其他类库中的WebAPI控制器。
MVC5为WebAPI添加命名空间的支持1的更多相关文章
- MVC5为WebAPI添加命名空间的支持
前言 默认情况下,微软提供的MVC框架模板中,WebAPI路由是不支持Namespace参数的.这导致一些比较大型的项目,无法把WebApi分离到单独的类库中. 本文将提供解决该问题的方案. 微软官方 ...
- asp.net MVC5为WebAPI添加命名空间的支持
前言 默认情况下,微软提供的MVC框架模板中,WebAPI路由是不支持Namespace参数的.这导致一些比较大型的项目,无法把WebApi分离到单独的类库中. 本文将提供解决该问题的方案. 微软官方 ...
- 为Asp.net WebApi 添加跨域支持
Nuget安装包:microsoft.aspnet.webapi.cors 原文地址:https://www.asp.net/web-api/overview/security/enabling-cr ...
- IDEA02 利用Maven创建Web项目、为Web应用添加Spring框架支持、bean的创建于获取、利用注解配置Bean、自动装配Bean、MVC配置
1 环境版本说明 Jdk : 1.8 Maven : 3.5 IDEA : 专业版 2017.2 2 环境准备 2.1 Maven安装及其配置 2.2 Tomcat安装及其配置 3 详细步骤 3.1 ...
- WebAPI增加Area以支持无限层级同名Controller
原文:WebAPI增加Area以支持无限层级同名Controller 微软的WebAPI默认实现逻辑 默认实现中不支持同名Controller,否则在访问时会报HttpError,在网上找到了各种路由 ...
- 为 ASP.NET Core (6.0)服务应用添加ApiKey验证支持
这个代码段演示了如何为一个ASP.NET Core项目中添加Apikey验证支持. 首先,通过下面的代码创建项目 dotnet new webapi -minimal -o yourwebapi 然后 ...
- deerlet-redis-client添加集群支持,邀请各路大神和菜鸟加入。
引言 经过几周的修改,deerlet已经添加了对于redis集群的支持,策略与memcached客户端一样,采用一致性Hash.不过目前Hash的算法取自Java自带的String类型的HashCod ...
- Intellij IDEA14 下添加ExtJS提示支持
前言: 虽然Interlij IDEA比起Eclipse对待EXT更为支持,但自己上手后总不能达到Intellij 开发ExtJS 应用指南(http://blog.csdn.net/s4640368 ...
- yum安装的Nginx添加第三方模块支持tcp
需求:生产有个接口是通过socket通信.nginx1.9开始支持tcp层的转发,通过stream实现的,而socket也是基于tcp通信. 实现方法:Centos7.2下yum直接安装的nginx, ...
随机推荐
- C#多线程读写同一文件处理
在多线程访问读写同一个文件时,经常遇到异常:“文件正在由另一进程使用,因此该进程无法访问此文件”. 多线程访问统一资源的异常, 解决方案1,保证读写操作单线程执行,可以使用lock 解决方案2,使用S ...
- 【转】windows下mongodb安装与使用整理
转自 :http://www.cnblogs.com/lecaf/archive/2013/08/23/mongodb.html 一.首先安装mongodb 1.下载地址:http://www.mon ...
- @Param注解在Mybatis中的使用 以及传递参数的三种方式
第一种: Dao层的方法 public User selectUser(String name,String password); 对应的Mapper.xml <select id=" ...
- 细说SQL Server中的加密【转】
简介 加密是指通过使用密钥或密码对数据进行模糊处理的过程.在SQL Server中,加密并不能替代其他的安全设置,比如防止未被授权的人访问数据库或是数据库实例所在的Windows系统,甚至是数据库所在 ...
- C#如何判断线程池中所有的线程是否已经完成(转)
其 实很简单用ThreadPool.RegisterWaitForSingleObject方法注册一个定时检查线程池的方法,在检查线程的方法内调用 ThreadPool.GetAvailableThr ...
- 用 .NET Memory Profiler 跟踪.net 应用内存使用情况--基本应用篇(转)
.net 框架号称永远不会发生内存泄漏,原因是其引入了内存回收的机制.但实际应用中,往往我们分配了对象但没有释放指向该对象的引用,导致对象永远无法释放.最 常见的情况就是给对象添加了事件处理函数,但当 ...
- Gas Station leetcode java
题目: There are N gas stations along a circular route, where the amount of gas at station i is gas[i]. ...
- ORM数据库框架 SQLite ORMLite MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- iOS中的多线程 NSOperation
在ios中,使用多线程有三种方式,分别是:NSThread.NSOperation和NSOperationQueue.GCD,在本节,主要讲解一下NSOperation的使用. NSOperation ...
- android Logger 一二三
我们在开发Android应用的过程中可以很方便地使用Log信息来调试程序,这都归功于Android的Logger驱动为用户层提供的Log支持.无论是底层的源代码还是上层的应用,我们都可以使用Logge ...