zoukankan      html  css  js  c++  java
  • 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));
  • 相关阅读:
    bzoj 3744: Gty的妹子序列 主席树+分块
    bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树
    bzoj 3041: 水叮当的舞步 迭代加深搜索 && NOIP RP++
    约瑟夫问题例题小结
    bzoj 3594: [Scoi2014]方伯伯的玉米田 dp树状数组优化
    人生第一场CTF的解题报告(部分)
    ZOJ 3811 Untrusted Patrol【并查集】
    POJ 2112: Optimal Milking【二分,网络流】
    Codeforces Round #277 (Div. 2 Only)
    POJ 2195 Going Home【最小费用流 二分图最优匹配】
  • 原文地址:https://www.cnblogs.com/xuhang/p/5204999.html
Copyright © 2011-2022 走看看