环境:VS2012 .net 4.0
参考:
http://aspnet.codeplex.com/SourceControl/changeset/view/dd207952fa86#Samples/WebApi/NamespaceControllerSelector/NamespaceHttpControllerSelector.cs
http://www.cnblogs.com/xwgli/p/4457628.html
想在WebApi中对Api进行分类管理,各类下可能存在同名的Api,对Controller,可以在注册路由时指定namespace,但WebApi不支持。
目前国内对这块的需求好像不是特别大,只有一篇文章介绍了如何自动对多区域的Api进行注册。
搜索MSDN,发现官方早已给出了解决方法:将此类的实现加入到项目中,并在初始化 Web API 路由时进行替换,在设置路由模板的时候,加入相应的 {namespace} 参数即可。
以下是我的实验过程。
1.为api建立独立的目录。
eg:
Apis/Admin
Apis/Public
2.分另添加一个MemberApi做为试验
3.在App_Start中增加一个类,代码如下,直接Copy即可
public class NamespaceHttpControllerSelector : IHttpControllerSelector { private const string NamespaceKey = "namespace"; private const string ControllerKey = "controller"; private readonly HttpConfiguration _configuration; private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _controllers; private readonly HashSet<string> _duplicates; public NamespaceHttpControllerSelector(HttpConfiguration config) { _configuration = config; _duplicates = new HashSet<string>(StringComparer.OrdinalIgnoreCase); _controllers = new Lazy<Dictionary<string, HttpControllerDescriptor>>(InitializeControllerDictionary); } private Dictionary<string, HttpControllerDescriptor> InitializeControllerDictionary() { var dictionary = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase); // Create a lookup table where key is "namespace.controller". The value of "namespace" is the last // segment of the full namespace. For example: // MyApplication.Controllers.V1.ProductsController => "V1.Products" IAssembliesResolver assembliesResolver = _configuration.Services.GetAssembliesResolver(); IHttpControllerTypeResolver controllersResolver = _configuration.Services.GetHttpControllerTypeResolver(); ICollection<Type> controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver); foreach (Type t in controllerTypes) { var segments = t.Namespace.Split(Type.Delimiter); // For the dictionary key, strip "Controller" from the end of the type name. // This matches the behavior of DefaultHttpControllerSelector. var controllerName = t.Name.Remove(t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length); var key = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", segments[segments.Length - 1], controllerName); // Check for duplicate keys. if (dictionary.Keys.Contains(key)) { _duplicates.Add(key); } else { dictionary[key] = new HttpControllerDescriptor(_configuration, t.Name, t); } } // Remove any duplicates from the dictionary, because these create ambiguous matches. // For example, "Foo.V1.ProductsController" and "Bar.V1.ProductsController" both map to "v1.products". foreach (string s in _duplicates) { dictionary.Remove(s); } return dictionary; } // Get a value from the route data, if present. private static T GetRouteVariable<T>(IHttpRouteData routeData, string name) { object result = null; if (routeData.Values.TryGetValue(name, out result)) { return (T)result; } return default(T); } public HttpControllerDescriptor SelectController(HttpRequestMessage request) { IHttpRouteData routeData = request.GetRouteData(); if (routeData == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } // Get the namespace and controller variables from the route data. string namespaceName = GetRouteVariable<string>(routeData, NamespaceKey); if (namespaceName == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } string controllerName = GetRouteVariable<string>(routeData, ControllerKey); if (controllerName == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } // Find a matching controller. string key = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", namespaceName, controllerName); HttpControllerDescriptor controllerDescriptor; if (_controllers.Value.TryGetValue(key, out controllerDescriptor)) { return controllerDescriptor; } else if (_duplicates.Contains(key)) { throw new HttpResponseException( request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Multiple controllers were found that match this request.")); } else { throw new HttpResponseException(HttpStatusCode.NotFound); } } public IDictionary<string, HttpControllerDescriptor> GetControllerMapping() { return _controllers.Value; } }
4.修改WebApiConfig.cs内容
public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{namespace}/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config)); } }