zoukankan      html  css  js  c++  java
  • WebApi 自定义版本选择器

    using Manjinba.Communication.Common.Logging;
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Reflection;
    using System.Web.Http;
    using System.Web.Http.Controllers;
    using System.Web.Http.Dispatcher;
    using System.Web.Http.Routing;

    namespace Manjinba.Communication.WebApi.Selector
    {
    /// <summary>
    /// 版本控制选择器
    /// </summary>
    public class VersionControllerSelector : IHttpControllerSelector
    {
    // Fields
    private readonly HttpConfiguration _configuration;
    private readonly Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>> _controllerInfoCache;
    private readonly Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>> _actionInfoCache;
    private const string ControllerKey = "controller";
    private const string ActionKey = "action";
    private const string DefaultVersion = "v1_2"; //默认版本号,因为之前的api我们没有版本号的概念
    private const string DefaultNamespaces = "Manjinba.Communication.WebApi"; //为了演示方便,这里就用到一个命名空间
    private const string RouteVersionKey = "version"; //路由规则中Version的字符串
    private const string DictKeyFormat = "{0}.{1}";
    private const string ActionDictKeyFormat = "{0}.{1}.{2}";
    private readonly HashSet<string> _duplicates;
    // Methods
    /// <summary>
    /// 初始化
    /// </summary>
    /// <param name="configuration"></param>
    public VersionControllerSelector(HttpConfiguration configuration)
    {
    if (configuration == null)
    {
    throw new ArgumentNullException("configuration");
    }
    this._controllerInfoCache = new Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>>(new Func<ConcurrentDictionary<string, HttpControllerDescriptor>>(this.InitializeControllerInfoCache));
    this._actionInfoCache = new Lazy<ConcurrentDictionary<string, HttpControllerDescriptor>>(new Func<ConcurrentDictionary<string, HttpControllerDescriptor>>(this.InitializeActionInfoCache));
    this._configuration = configuration;
    this._duplicates = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
    }
    /// <summary>
    /// 获取和筛选控制器路由映射
    /// </summary>
    /// <returns></returns>
    public virtual IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
    {
    var controllerMapping = new Dictionary<string, HttpControllerDescriptor>();
    foreach (var p in _controllerInfoCache.Value)
    {
    var controllerKey = p.Key?.Split('.')?.Count() > 1 ? p.Key.Split('.')[1] : p.Key.Split('.').FirstOrDefault();
    if (!controllerMapping.Keys.Any(a => a.Equals(controllerKey, StringComparison.OrdinalIgnoreCase)))
    {
    controllerMapping.Add(controllerKey, p.Value);
    }
    }
    return controllerMapping;
    }
    /// <summary>
    /// 获取控制器名称
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    public virtual string GetControllerName(HttpRequestMessage request)
    {
    if (request == null)
    {
    throw new ArgumentNullException("request");
    }
    IHttpRouteData routeData = request.GetRouteData();
    if (routeData == null)
    {
    throw new ArgumentNullException("routeData");
    }
    object str = null;
    routeData.Values.TryGetValue(ControllerKey, out str);
    return str.ToString();
    }
    /// <summary>
    /// 获取路由映射
    /// </summary>
    /// <returns></returns>
    private ConcurrentDictionary<string, HttpControllerDescriptor> InitializeControllerInfoCache()
    {
    ConcurrentDictionary<string, HttpControllerDescriptor> dictionary = new ConcurrentDictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
    var assemblies = _configuration.Services.GetAssembliesResolver();//解析程序集
    var controllerResolver = _configuration.Services.GetHttpControllerTypeResolver();
    var controllerTypes = controllerResolver.GetControllerTypes(assemblies);
    foreach (var t in controllerTypes)
    {
    if (t.Namespace.Contains(DefaultNamespaces)) //符合NameSpace规则
    {
    var segments = t.Namespace.Split(Type.Delimiter);
    var version = t.Namespace.Equals(DefaultNamespaces, StringComparison.OrdinalIgnoreCase) ?
    DefaultVersion : segments[segments.Length - 1];
    var controllerName = t.Name.Remove(t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length);
    var key = string.Format(DictKeyFormat, version, controllerName);
    if (!dictionary.ContainsKey(key))
    {
    dictionary.TryAdd(key, new HttpControllerDescriptor(_configuration, t.Name, t));
    }
    else
    {
    _duplicates.Add(key);
    }
    }
    }
    return dictionary;
    }
    /// <summary>
    /// 获取路由映射
    /// </summary>
    /// <returns></returns>
    private ConcurrentDictionary<string, HttpControllerDescriptor> InitializeActionInfoCache()
    {
    ConcurrentDictionary<string, HttpControllerDescriptor> dictionary = new ConcurrentDictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
    var assemblies = _configuration.Services.GetAssembliesResolver();//解析程序集
    var controllerResolver = _configuration.Services.GetHttpControllerTypeResolver();
    var controllerTypes = controllerResolver.GetControllerTypes(assemblies);
    foreach (var t in controllerTypes)
    {
    if (t.Namespace.Contains(DefaultNamespaces)) //符合NameSpace规则
    {
    var segments = t.Namespace.Split(Type.Delimiter);
    var version = t.Namespace.Equals(DefaultNamespaces, StringComparison.OrdinalIgnoreCase) ?
    DefaultVersion : segments[segments.Length - 1];
    var controllerName = t.Name.Remove(t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length);
    var methodTypes = t.GetMethods().Where(w =>
    "JsonResult`1".Equals(w.GetRuntimeBaseDefinition()?.ReturnParameter?.ParameterType?.Name)
    || "Task`1".Equals(w.GetRuntimeBaseDefinition()?.ReturnParameter?.ParameterType?.Name)
    )?.ToList();
    foreach (var method in methodTypes)
    {
    var key = string.Format(ActionDictKeyFormat, version, controllerName, method.Name);
    if (!dictionary.ContainsKey(key))
    {
    dictionary.TryAdd(key, new HttpControllerDescriptor(_configuration, t.Name, t));
    }
    }
    }
    }
    return dictionary;
    }
    /// <summary>
    /// 定位控制器
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    public virtual HttpControllerDescriptor SelectController(HttpRequestMessage request)
    {
    if (request == null)
    {
    throw new ArgumentNullException("request");
    }
    IHttpRouteData routeData = request.GetRouteData();
    if (routeData.Values.Keys.Count == 1 && routeData.Values.Keys.FirstOrDefault().Equals("MS_SubRoutes"))
    {
    return new DefaultHttpControllerSelector(_configuration).SelectController(request);
    }
    string version = GetRouteVariable<string>(routeData, RouteVersionKey);
    if (version == null)
    {
    version = DefaultVersion;
    }
    else
    {
    version = version.Replace('.', '_');
    if (version.Equals("api", StringComparison.OrdinalIgnoreCase))
    {
    version = "V1_2";
    }
    }
    string controllerName = GetRouteVariable<string>(routeData, ControllerKey);
    var actionName = GetRouteVariable<string>(routeData, ActionKey);
    if (controllerName.Equals("search", StringComparison.OrdinalIgnoreCase))
    {
    version = "V1_4";
    }
    if (controllerName.Equals("api", StringComparison.OrdinalIgnoreCase))
    {
    if (actionName.Equals("search", StringComparison.OrdinalIgnoreCase))
    {
    version = "V1_4";
    controllerName = "Search";
    }
    else
    {
    controllerName = "IMMessage";
    }
    }
    if (controllerName.Equals("Agreement", StringComparison.OrdinalIgnoreCase) || controllerName.Equals("Help", StringComparison.OrdinalIgnoreCase)
    || controllerName.Equals("App", StringComparison.OrdinalIgnoreCase))
    {
    return new DefaultHttpControllerSelector(_configuration).SelectController(request);
    }
    if (controllerName == null)
    {
    throw new HttpResponseException(HttpStatusCode.NotFound);
    }
    var key = string.Empty;
    var isMatched = false;// 路由是否匹配到
    var isToLowerMatchStart = false;
    version = version.ToUpper();
    try
    {
    var versionList = GetAllVersion();
    if (versionList != null && !versionList.Contains(version))// 如果请求的版本号不在版本列表中,则从最后版本向老版本追溯
    {
    isToLowerMatchStart = true;
    }
    foreach (var v in versionList)
    {
    if (v.Equals(version))
    {
    isToLowerMatchStart = true;
    }
    if (isToLowerMatchStart)// 只往更老版本追溯
    {
    // 匹配控制器
    key = string.Format(DictKeyFormat, v, controllerName);
    var actionKey = string.Format(ActionDictKeyFormat, v, controllerName, actionName);
    HttpControllerDescriptor controllerDescriptor;
    if (_actionInfoCache.Value.TryGetValue(actionKey, out controllerDescriptor))
    {
    if (_controllerInfoCache.Value.TryGetValue(key, out controllerDescriptor))
    {
    isMatched = true;
    return controllerDescriptor;
    }
    }
    else
    {
    continue;
    }
    }
    }
    }
    catch (Exception e)
    {
    LogHelper.GetLog().Error(e.Message + e.StackTrace);
    throw new HttpResponseException(
    request.CreateErrorResponse(HttpStatusCode.InternalServerError,
    "Multiple controllers were found that match this request."));
    }
    if (!isMatched && _duplicates.Contains(key))
    {
    throw new HttpResponseException(
    request.CreateErrorResponse(HttpStatusCode.InternalServerError,
    "Multiple controllers were found that match this request."));
    }
    else
    {
    throw new HttpResponseException(HttpStatusCode.NotFound);
    }
    }
    /// <summary>
    /// Get a value from the route data, if present.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="routeData"></param>
    /// <param name="name"></param>
    /// <returns></returns>
    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);
    }
    /// <summary>
    /// 获取当前执行程序控制层的所有版本号
    /// </summary>
    /// <returns></returns>
    private static List<string> GetAllVersion()
    {
    var versionList = new List<string>();
    var assembly = Assembly.GetExecutingAssembly();
    if (assembly != null)
    {
    var types = assembly.GetTypes();
    foreach (var t in types)
    {
    if (t.FullName.StartsWith("Manjinba.Communication.WebApi.Controllers.V") || t.FullName.StartsWith("Manjinba.Communication.WebApi.Controllers.api.V"))
    {
    var cversion = t.Namespace.Substring(t.Namespace.LastIndexOf('.') + 1);
    if (!versionList.Contains(cversion))
    {
    versionList.Add(t.Namespace.Substring(t.Namespace.LastIndexOf('.') + 1));
    }
    }
    }
    versionList.Sort();
    versionList.Reverse();
    }
    return versionList;
    }
    }
    }

    using Manjinba.Communication.WebApi.Filters;
    using Manjinba.Communication.WebApi.Selector;
    using System.Configuration;
    using System.Web.Http;
    using System.Web.Http.Cors;
    using System.Web.Http.Dispatcher;

    namespace Manjinba.Communication.WebApi
    {
    /// <summary>
    /// WebApi配置
    /// </summary>
    public static class WebApiConfig
    {
    /// <summary>
    /// 注册
    /// </summary>
    /// <param name="config"></param>
    public static void Register(HttpConfiguration config)
    {

    config.Formatters.JsonFormatter.SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings()
    {
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore
    };

    //以下跨域请求在Nginx中配置  跨域访问可在WebApiConfig中配置,也可以在Web.config中全局配置
    //config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
    //var allowOrigins = ConfigurationManager.AppSettings["cors_allowOrigins"] ?? "*";
    //var allowHeaders = ConfigurationManager.AppSettings["cors_allowHeaders"];
    //var allowMethods = ConfigurationManager.AppSettings["cors_allowMethods"];
    //var globalCors = new EnableCorsAttribute(allowOrigins, allowHeaders, allowMethods);
    //config.EnableCors(globalCors);
    config.MapHttpAttributeRoutes();

    #if !DEBUG

    // ActionFilterAttribute
    config.Filters.Add(new ApiSecurityFilter());
    #endif

    config.Filters.Add(new ValidateModelFilter());
    config.Routes.MapHttpRoute(
    name: "VersionApi",
    routeTemplate: "{version}/{controller}/{action}",
    defaults: new { id = RouteParameter.Optional }
    );

    config.Filters.Add(new ValidateModelFilter());
    config.Routes.MapHttpRoute(
    name: "SimpleApi",
    routeTemplate: "{controller}/{action}",
    defaults: new { id = RouteParameter.Optional }
    );

    config.Filters.Add(new ValidateModelFilter());
    config.Routes.MapHttpRoute(
    name: "DefaultVersionApi",
    routeTemplate: "{version}/api/{controller}/{action}",
    defaults: new { id = RouteParameter.Optional }
    );

    //版本信息在Uri中
    config.Services.Replace(typeof(IHttpControllerSelector), new VersionControllerSelector(config));
    }
    }
    }

  • 相关阅读:
    opensuse的一些软件使用
    love2d新闻
    好用的在线工具收集
    POJ2531 Network Saboteur 枚举||随机化
    Acdream Path 动态规划
    Acdream Xor 简单数学
    POJ2676 Sudoku 搜索
    Acdream 1015 Double Kings 搜索
    Acdream Multiplication 基础题
    Acdream Cut 贪心
  • 原文地址:https://www.cnblogs.com/Nine4Cool/p/10491505.html
Copyright © 2011-2022 走看看