• ASP.NET Web API编程——版本控制


    版本控制

     

    版本控制的方法有很多,这里提供一种将Odata与普通web api版本控制机制统一的方法,但也可以单独控制,整合控制与单独控制主要的不同是:整合控制通过VersionControllerSelector来选择控制器过滤器,而不是直接选择控制器。

     采用此机制来控制版本,应按照如下规则命名控制器:

    自定义标识符+版本+Controller

    自定义标识符:能体现控制器含义的字符串

    版本:表示版本的字符串,例如:V1,V1.0;不建议使用V1.0这样的写法,因为这样控制器名称会相当怪异,如果表示小版本号,那么可以使用V1D0,这种写法,即用一个字母代替句号。

    命名空间对应了项目文件的组织形式,控制器的命名空间为:

    1 Odata版本控制

    扩展DefaultHttpControllerSelector

    public class ODataVersionControllerSelector : DefaultHttpControllerSelector
    {
            public Dictionary<string, string> RouteVersionSuffixMapping { get; set; }
    
            public ODataVersionControllerSelector(HttpConfiguration configuration)
                : base(configuration)
            {
                if (RouteVersionSuffixMapping == null)
                {
                    RouteVersionSuffixMapping = new Dictionary<string, string>();
                }
            }
    
            public override string GetControllerName(HttpRequestMessage request)
            {
                var controllerName = base.GetControllerName(request);
                if (string.IsNullOrEmpty(controllerName))
                {
                    return controllerName;
                }
    
                var routeName = request.ODataProperties().RouteName;
                if (string.IsNullOrEmpty(routeName))
                {
                    return controllerName;
                }
    
                var mapping = GetControllerMapping();
    
                if (!RouteVersionSuffixMapping.ContainsKey(routeName))
                {
                    return controllerName;
                }
    
                var versionControllerName = controllerName + RouteVersionSuffixMapping[routeName];
                return mapping.ContainsKey(versionControllerName)
                    ? versionControllerName
                    : controllerName;
            }
    }

    修改WebApiConfig.Register方法

    public static class WebApiConfig
    {
      public static void Register(HttpConfiguration config)
      {
          ......
    
          //odata路由
                config.MapODataServiceRoute(
                               routeName: "V1OdataRouteVersioning",
                               routePrefix: "Odata/V1",
                               model: GetEdmModel());
                config.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
                config.AddODataQueryFilter();
    
                config.Services.Replace(typeof(IHttpControllerSelector), new ODataVersionControllerSelector (config));
                var controllerSelector = config.Services.GetService(typeof(IHttpControllerSelector)) as ODataVersionControllerSelector ;
           controllerSelector.RouteVersionSuffixMapping.Add("V1OdataRouteVersioning", "V1");
    
            ......
      }
    }
    
    private static IEdmModel GetEdmModel()
    {
      ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
      #region Publication
      var publicationsSet = builder.EntitySet<Publication>("Publications").EntityType.Collection;
      var getPublicationsFunction = publicationsSet.Function("GetPublications").Returns<PublicationDTO>();
      getPublicationsFunction.Parameter<int>("userId");
    
       publicationsSet.Action("AddPublication").Returns<int>().Parameter<PublicationAddBindingModel>("publicationAddBM");
      publicationsSet.Action("DeletePublication").Returns<IHttpActionResult>().Parameter<PublicationDelBindingModel>("publicationDelBM");
       #endregion
    
      builder.Namespace = "Service";
      return builder.GetEdmModel();
    }

    2 普通Api版本控制

    扩展IHttpControllerSelector

    public class NormalVersionControllerSelector : IHttpControllerSelector
    {
            private const string Version = "version";
            private const string ControllerKey = "controller";
    
            private readonly HttpConfiguration _configuration;
            private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _controllers;
            private readonly HashSet<string> _duplicates;
    
            public NormalVersionControllerSelector(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);
    
                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);
    
                    //去掉HY_WebApi.V1.Controllers.KeyController中的HY_WebApi.
                    //去掉HY_WebApi.HYDB.V1.Controllers.HYSearchController中的HY_WebApi.HYDB.
                    //因此,保留V1.Controllers.KeyController这三部分
                    //键值格式如:V1.Controllers.KeyController
                    string[] items = t.FullName.Split(new char[]{'.'},StringSplitOptions.RemoveEmptyEntries);
                    int count = items.Count();
                    var key = string.Format("{0}.{1}.{2}", items[count - 3], items[count - 2], items[count - 1]);
    
                    // Check for duplicate keys.
                    if (dictionary.ContainsKey(key))
                    {
                        _duplicates.Add(key);
                    }
                    else
                    {
                        dictionary[key] = new HttpControllerDescriptor(_configuration, t.Name, t);  
                    }
                }
    
                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 version = GetRouteVariable<string>(routeData, Version);
                if (version == null)
                {
                    throw new HttpResponseException(HttpStatusCode.NotFound);
                }
    
                string controllerName = GetRouteVariable<string>(routeData, ControllerKey);
                if (controllerName == null)
                {
                    throw new HttpResponseException(HttpStatusCode.NotFound);
                }
    
                // 匹配控制器
                string key = String.Format("{0}.Controllers.{1}{2}Controller", version, controllerName,version);
    
                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;
            }
        }
    }

    修改WebApiConfig.Register方法

    public static class WebApiConfig
    {
            public static void Register(HttpConfiguration config)
            {
    
              ......
    
            // Web API 路由
                config.Routes.MapHttpRoute(
                    name: "defaultRoute",
                    routeTemplate: "api/{version}/{controller}/{action}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
                config.Services.Replace(typeof(IHttpControllerSelector), new NormalVersionControllerSelector(config));
     
            ......
    
         }
    }

    3 同时支持Odata,与普通Web Api版本控制

     

    扩展DefaultHttpControllerSelector

    public class VersionControllerSelector : DefaultHttpControllerSelector
    {
            public Dictionary<string, string> RouteVersionSuffixMapping { get; set; }
            private HttpConfiguration configuration;
            public VersionControllerSelector(HttpConfiguration configuration)
                : base(configuration)
            {
                this.configuration = configuration;
                if (RouteVersionSuffixMapping == null)
                {
                    RouteVersionSuffixMapping = new Dictionary<string, string>();
                }
            }
            public override string GetControllerName(HttpRequestMessage request)
            {
                return SelectController(request).ControllerName;
            }
    
            public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
            {
                var routeName = request.ODataProperties().RouteName;
    
                if (!string.IsNullOrWhiteSpace(routeName))
                {//odata路由
                    var selector = new ODataVersionControllerSelector(configuration);
                    selector.RouteVersionSuffixMapping = RouteVersionSuffixMapping;
                    return selector.SelectController(request);
                }
                else
                {//普通路由
                    var selector = new NormalVersionControllerSelector(configuration);
                    return selector.SelectController(request);
                }
            }
    }
    
    修改WebApiConfig.Register方法
    public static class WebApiConfig
    
            public static void Register(HttpConfiguration config)
            {
            // Web API 路由
                config.Routes.MapHttpRoute(
                    name: "defaultRoute",
                    routeTemplate: "api/{version}/{controller}/{action}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                //odata路由
                config.MapODataServiceRoute(
                               routeName: "V1OdataRouteVersioning",
                               routePrefix: "Odata/V1",
                               model: GetEdmModel());
                config.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
                config.AddODataQueryFilter();
    
                config.Services.Replace(typeof(IHttpControllerSelector), new VersionControllerSelector(config));
                var controllerSelector = config.Services.GetService(typeof(IHttpControllerSelector)) as VersionControllerSelector;
                controllerSelector.RouteVersionSuffixMapping.Add("V1OdataRouteVersioning", "V1");
        }
    }
    

    其中GetEdmModel()方法与前述方法相同。

  • 相关阅读:
    K-lord #1
    P1220 关路灯 (区间DP)
    P1136 迎接仪式 (动态规划)
    P1063 能量项链 (区间DP)
    444 D. Ratings and Reality Shows
    P1896 [SCOI2005]互不侵犯King
    P1841 [JSOI2007]重要的城市
    P1134 阶乘问题
    P1414 又是毕业季II
    P1450 [HAOI2008]硬币购物
  • 原文地址:https://www.cnblogs.com/hdwgxz/p/7856619.html
Copyright © 2020-2023  润新知