• Abp中SwaggerUI的多个接口文档配置说明


    对外提供的接口在实际生成过程中,可能是需要一个接口版本的,比如说v1,manage。效果如下:
     
     
    在swagger中怎么实现呢?
    1. 添加SwaggerVersionHelper.cs
     public class SwaggerVersionHelper
        {
            public static bool ResolveVersionSupportByRouteConstraint(ApiDescription apiDesc, string targetApiVersion)
            {
    
                var attr = apiDesc.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<VersionedRoute>().FirstOrDefault();
                if (attr == null)
                {
                    if (targetApiVersion == "manage")
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
    
    
                
                    int targetVersion;
                    targetApiVersion = targetApiVersion.TrimStart('v');
    
                    if (attr.Version != 0 && int.TryParse(targetApiVersion, out targetVersion))
                    {
                        return attr.Version == targetVersion;
                    };
    
                    return false;
             }
        }    
    View Code
     
    2. 添加VersionedRoute.cs
    [AttributeUsage(AttributeTargets.All)]
    public class VersionedRoute : Attribute
    {
    public VersionedRoute(string name, int version)
    {
    Name = name;
    Version = version;
    }
     
    public string Name { get; set; }
    public int Version { get; set; }
    }
    View Code
     
    3. swagger配置多版本接口说明文档。
     
    4. 在Controller中添加VersionedRoute特性。
     
    上面个四个步骤配置好之后,就实现了接口多版本发布了。
     
    最后还有一个问题,就是我想发布v1, v2...这些版本的接口的时候,一般来说不同的版本之间接口Controller的命名空间不同,但是ControllerName是一样的,并且AbpHttpControllerSelector在解析路由的时候是忽略命名空间的,那么错误就来了:Swagger不能准确的去解析多个一样的Controller。
     
     
    解决办法:
    添加一个ControllerSelector,他的作用就是通过命名空间来区分不同的Controller。
    1. 添加一个NamespaceHttpControllerSelector.cs。
    public class NamespaceHttpControllerSelector : AbpHttpControllerSelector, ISingletonDependency
    {
    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 NamespaceHttpControllerSelector(HttpConfiguration config, DynamicApiControllerManager dynamicApiControllerManager)
    : base(config, dynamicApiControllerManager)
    {
    _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 spacename = segments[segments.Length - 1];
    if (new Regex("v\d+").IsMatch(spacename))
    {
    var key = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", segments[segments.Length - 1], controllerName);
     
    // Check for duplicate keys.
    if (dictionary.Keys.Contains(key))
    {
    _duplicates.Add(key);
    }
    else
    {
    dictionary[key] = new HttpControllerDescriptor(_configuration, t.Name, t);
    }
    }
    else
    {
    dictionary[controllerName] = 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;
    }
     
    // 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 override 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 namespaceName = GetRouteVariable<string>(routeData, NamespaceKey);
    if (namespaceName == null)
    {
    return base.SelectController(request);
    }
     
    string controllerName = GetRouteVariable<string>(routeData, ControllerKey);
    if (controllerName == null)
    {
    return base.SelectController(request);
    }
     
     
    if (!new Regex("v\d+").IsMatch(namespaceName))
    {
    return base.SelectController(request);
    }
     
    // Find a matching controller.
    string key = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", namespaceName, 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 override IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
    {
    return _controllers.Value;
    }
     
    public void UseThis()
    {
    _configuration.Services.Replace(typeof(IHttpControllerSelector), this);
    }
    }
     
    View Code
    2. 在WebApi中配置这个ControllerSelector。
     
  • 相关阅读:
    转】主流PHP框架间的比较(Zend Framework,CakePHP,CodeIgniter,Symfony,ThinkPHP,FleaPHP)
    总结 沉寂了大半年后的又一次
    xampp phpmyadmin产生403错误的解决办法
    Codeigniter 去除URL中的index.php
    【分享】C#中abstract与virtual的区别
    SQL Server 中使用Convert来取得datetime数据类型样式(全)
    Visual Studio 2012 RTM全系列简体中文正式版(附注册码)
    VS2008的Web.config、XML文件无法高亮显示的问题解决方案
    循环类里面的每一个属性
    Eclipse 打开已存在的Android项目的问题
  • 原文地址:https://www.cnblogs.com/sessionliang/p/6688372.html
Copyright © 2020-2023  润新知