解决Web API路由配置支持Area及命名空间参数
首先创建一个新的HttpControllerSelector类
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Web; using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Http.Dispatcher; namespace _1_解决MVC的Controller和Web_API的Controller类名不能相同的问题.App_Start.webExt { public class NamespaceHttpControllerSelector : DefaultHttpControllerSelector { private const string NamespaceRouteVariableName = "namespaceName"; 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 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; } //get the defined namespace 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("No route providing a controller name was found to match request 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("No route providing a controller name was found to match request 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("No route providing a controller name was found to match request URI ‘{0}‘", new object[] { request.RequestUri }))); } } }
其次,在全局webApi配置文件中添加
//为了让WebApi也支持NameSpace config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config));
public static class WebApiConfig { public static void Register(HttpConfiguration config) { //是为了让WebApi的控制器自动匹配ApiController var suffix = typeof(DefaultHttpControllerSelector).GetField("ControllerSuffix", BindingFlags.Static | BindingFlags.Public); if (suffix != null) suffix.SetValue(null, "ApiController"); //为了让WebApi也支持NameSpace config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config)); // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
最后,在区域在配置webApi路径
GlobalConfiguration.Configuration.Routes.MapHttpRoute( this.AreaName + "Api", "api/" + this.AreaName + "/{controller}/{action}/{id}", new { action = RouteParameter.Optional, id = RouteParameter.Optional, namespaceName = new string[] { string.Format("_1_解决MVC的Controller和Web_API的Controller类名不能相同的问题.Areas.{0}.Controllers", this.AreaName) } }, null //new { action = new StartWithConstraint() } );
public class shopAreaRegistration : AreaRegistration { public override string AreaName { get { return "shop"; } } public override void RegisterArea(AreaRegistrationContext context) { context.MapRoute( "shop_default", "shop/{controller}/{action}/{id}", new { action = "Index", id = UrlParameter.Optional }, new string [] { "_1_解决MVC的Controller和Web_API的Controller类名不能相同的问题.Areas.shop.Controllers" } ); GlobalConfiguration.Configuration.Routes.MapHttpRoute( this.AreaName + "Api", "api/" + this.AreaName + "/{controller}/{action}/{id}", new { action = RouteParameter.Optional, id = RouteParameter.Optional, namespaceName = new string[] { string.Format("_1_解决MVC的Controller和Web_API的Controller类名不能相同的问题.Areas.{0}.Controllers", this.AreaName) } }, null //new { action = new StartWithConstraint() } ); } }