電商系統架構總結4(webapi 版本控制)

來源:互聯網
上載者:User

標籤:cat   ant   form   總結   str   closed   sem   ntc   gif   

    為了 順利迭代升級,web api 在維護過程是不斷升級的,但使用者是不能強迫他們每次都跟隨你去升級,這樣會讓使用者不勝其煩。為了保證不同版本的用戶端能同時相容,在web api介面上加入版本控制就很有必要了。

當然,對於我們開發的代碼進資料列版本設定也有利,不至於陷入混亂。版本參數可以放置在請求的url 作為路由參數的一部分,也可以放在header裡。實現的辦法是 實現 IHttpControllerSelector 並在WebApiConfig的註冊方法裡進行替換。

    public class VersionHttpControllerSelector : IHttpControllerSelector    {        private const string VersionKey = "version";        private const string ControllerKey = "controller";        private readonly HttpConfiguration _configuration;        private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _controllers;        private readonly HashSet<string> _duplicates;        public VersionHttpControllerSelector(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);                var controllerName = t.Name.Remove(t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length);                string version = segments[segments.Length - 1];                var key = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version, controllerName);                if (version == "Controllers")                {                    key = String.Format(CultureInfo.InvariantCulture, "{0}", controllerName);                }                // Check for duplicate keys.                if (dictionary.Keys.Contains(key))                {                    _duplicates.Add(key);                }                else                {                    dictionary[key] = new HttpControllerDescriptor(_configuration, t.Name, t);                }            }            foreach (string s in _duplicates)            {                dictionary.Remove(s);            }            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 version and controller variables from the route data.            string version = GetRouteVariable<string>(routeData, VersionKey);            if (string.IsNullOrEmpty(version))            {                version = GetVersionFromHTTPHeaderAndAcceptHeader(request);            }            string controllerName = GetRouteVariable<string>(routeData, ControllerKey);            if (controllerName == null)            {                throw new HttpResponseException(HttpStatusCode.NotFound);            }            // Find a matching controller.            string key = String.Format(CultureInfo.InvariantCulture, "{0}", controllerName);            if (!string.IsNullOrEmpty(version))            {                key = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", version, controllerName);            }            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;        }        private string GetVersionFromHTTPHeaderAndAcceptHeader(HttpRequestMessage request)        {            if (request.Headers.Contains(VersionKey))            {                var versionHeader = request.Headers.GetValues(VersionKey).FirstOrDefault();                if (versionHeader != null)                {                    return versionHeader;                }            }            var acceptHeader = request.Headers.Accept;            foreach (var mime in acceptHeader)            {                if (mime.MediaType == "application/json" || mime.MediaType == "text/html")                {                    var version = mime.Parameters                                     .Where(v => v.Name.Equals(VersionKey, StringComparison.OrdinalIgnoreCase))                                      .FirstOrDefault();                    if (version != null)                    {                        return version.Value;                    }                    return string.Empty;                }            }            return string.Empty;        }    }
View Code

重點是SelectController方法,從http請求裡找出合適版本的controller。我這裡相容了從路由和header裡擷取版本,先從路由裡擷取,沒有再從header裡擷取。

           IHttpRouteData routeData = request.GetRouteData();            if (routeData == null)            {                throw new HttpResponseException(HttpStatusCode.NotFound);            }            // Get the version and controller variables from the route data.            string version = GetRouteVariable<string>(routeData, VersionKey);            if (string.IsNullOrEmpty(version))            {                version = GetVersionFromHTTPHeaderAndAcceptHeader(request);            }
      private string GetVersionFromHTTPHeaderAndAcceptHeader(HttpRequestMessage request)        {            if (request.Headers.Contains(VersionKey))            {                var versionHeader = request.Headers.GetValues(VersionKey).FirstOrDefault();                if (versionHeader != null)                {                    return versionHeader;                }            }            var acceptHeader = request.Headers.Accept;            foreach (var mime in acceptHeader)            {                if (mime.MediaType == "application/json" || mime.MediaType == "text/html")                {                    var version = mime.Parameters                                     .Where(v => v.Name.Equals(VersionKey, StringComparison.OrdinalIgnoreCase))                                      .FirstOrDefault();                    if (version != null)                    {                        return version.Value;                    }                    return string.Empty;                }            }            return string.Empty;        }

WebApiConfig檔案調用代碼如下:

   public static void Register(HttpConfiguration config)        {。。。config.Services.Replace(typeof(IHttpControllerSelector), new VersionHttpControllerSelector((config)));}

web api的定義呢,則從命名空間上區分就可以了。 比如版本號碼為V1的  LoginApiController 的命名空間 為定義為    xxx.WebAPI.Controllers.V1,版本號碼為V2的  LoginApiController 的命名空間 為定義為    xxx.WebAPI.Controllers.V2,如此類推,

用戶端在header裡加上參數 versoin=v1/v2... 就可以指定使用不同版本的api了。

電商系統架構總結4(webapi 版本控制)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.