解决Web API路由配置支持Area及命名空间参数

Posted youguess

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解决Web API路由配置支持Area及命名空间参数相关的知识,希望对你有一定的参考价值。

解决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() }
            );

        }
    }

 

以上是关于解决Web API路由配置支持Area及命名空间参数的主要内容,如果未能解决你的问题,请参考以下文章

WebAPI HelpPage支持area

WebAPI HelpPage支持area

Asp.Net MVC及Web API框架配置会碰到的几个问题及解决方案 (精髓)

Vue配置路由和传参方式及路由守卫!

vue路由传参及解决vue路由传参页面刷新参数丢失问题

在 Web API 中管理版本