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

  • 相关阅读:
    NetSuite Batch Process Status
    NetSuite generated bank files and the Bank Reconciliation process
    Global Search file content in Gitlab repositories, search across repositories, search across all files
    FedEx Package Rate Integration with NetSuite direct integrate by WebServices
    git Merge branches
    git tag and NetSuite deployment tracking
    API 读写cookie的方法
    C# 生成缩略图
    解决jquery操作checkbox全选全不选无法勾选问题
    JS读取写入删除Cookie方法
  • 原文地址:https://www.cnblogs.com/Nine4Cool/p/10491505.html
Copyright © 2011-2022 走看看