WebApi路由及版本控制

    public class WebApiControllerSelector : 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 WebApiControllerSelector(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.ToLower());

                // 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;
        }

        // 取路由相应值
        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);
            }

            //从Route中读取命名空间名称和控制器名称
            string controllerName = GetRouteVariable<string>(routeData, ControllerKey).ToLower();
            if (controllerName == null)
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }

            HttpControllerDescriptor controllerDescriptor;
            //获取版本号
            var version = GetVersionFromAcceptHeaderVersion(request);
            var versionedControllerName = string.Concat(controllerName, version).ToLower();
            string versionkey = versionedControllerName;
            //寻找匹配项
            HttpControllerDescriptor versionedControllerDescriptor;


            //如果命名空间名称为空,调用BaseRoute,反之采用DefaultApi
            string namespaceName = GetRouteVariable<string>(routeData, NamespaceKey);
            string key = controllerName;
            if (namespaceName != null)
            {
                key = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", namespaceName, controllerName);
                versionkey = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", namespaceName, versionedControllerName);
                if (_controllers.Value.TryGetValue(key, out controllerDescriptor))
                {
                    if (_controllers.Value.TryGetValue(versionkey, out versionedControllerDescriptor))
                    {
                        return versionedControllerDescriptor;
                    }

                    return controllerDescriptor;
                }
                else if (_duplicates.Contains(key))
                {
                    throw new HttpResponseException(
                        request.CreateErrorResponse(HttpStatusCode.InternalServerError,
                        "该请求有多个控制器匹配,请检查路由配置"));
                }
                else
                {
                    throw new HttpResponseException(HttpStatusCode.NotFound);
                }
            }
            else
            {
                var basecontroller = _controllers.Value.Where(p => p.Key.ToLower().EndsWith(key));
                if (basecontroller.Any())
                {
                    if (basecontroller.Count() > 1)
                    {
                        throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.InternalServerError,"该请求有多个控制器匹配,请检查路由配置"));
                    }
                    controllerDescriptor = basecontroller.FirstOrDefault().Value;
                    var baseVersioncontroller = _controllers.Value.Where(p => p.Key.ToLower().EndsWith(versionkey));
                    if (baseVersioncontroller.Any())
                    {
                        return baseVersioncontroller.FirstOrDefault().Value;
                    }
                    return controllerDescriptor;
                }
                else
                {
                    throw new HttpResponseException(HttpStatusCode.NotFound);
                }
            }
        }

        public IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
        {
            return _controllers.Value;
        }

        /// <summary>
        /// 添加版本控制
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private string GetVersionFromAcceptHeaderVersion(HttpRequestMessage request)
        {
            var acceptHeader = request.Headers.Accept;
            if (acceptHeader.Any())
            {
                var format = acceptHeader.First();
                format.MediaType = JsonMediaTypeFormatter.DefaultMediaType.MediaType;
            }
            var heads = HttpContext.Current.Request.Headers;
            if (heads.AllKeys.Contains("Version"))
            {
                return heads.GetValues("Version").FirstOrDefault();
            }
            return "1";
        }
    }
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{namespace}/{id}/{controller}/{subid}/{action}",
                defaults: new { subid = RouteParameter.Optional, action = RouteParameter.Optional }
            );
            config.Routes.MapHttpRoute(
                name: "AllApi",
                routeTemplate: "api/{namespace}/{controller}",
                defaults: new { }
            );
            config.Services.Replace(typeof(IHttpControllerSelector), new WebApiControllerSelector(config));

 

posted @ 2016-02-21 15:31  徐航  阅读(1595)  评论(0编辑  收藏  举报