zoukankan      html  css  js  c++  java
  • Asp.Net WebApi Swagger终极搭建

    【PS:原文手打,转载说明出处,博客园

    关于为什么用Swagger

      目前稍微有点规模的公司,已经从原先的瀑布流开发到了敏捷开发,实现前后端分离,为此后端工程师只关注写好Api即可,那程序员最讨厌的就是写Api文档了,故而产生了Swagger。

    Swagger原理

      Swagger就是利用反射技术遍历所有Api接口,并且从xml文件中读取注释,在利用Swagger内置的模板组合html显示至客户端实现接口可视化,并且可调用。

    Asp.net WebApi Swagger集成

      1:vs2017,新建web项目,选择WebApi

      2:删除Views、Scripts、Models、fonts、Content、Areas目录

      3:删除RouteConfig.cs、FilterConfig.cs、BundleConfig.cs

      4:删除HomeController.cs

      5:Global.asax中删除异常代码

      6:nuget搜索Swagger,安装 Swashbuckle

      7:右键项目——》属性——》生成——》输出——》勾选XML文档文件——》保存

      8:修改SwaggerConfig.cs

        新增方法,释放c.IncludeXmlComments(GetXmlCommentsPath());的注释(注意:例如返回值为对象,然后又不在同一个项目,则需要多次调用)

    private static string GetXmlCommentsPath()
    {
          return System.String.Format(@"{0}in{项目名称}.XML",
                    System.AppDomain.CurrentDomain.BaseDirectory);
    }

      9:然后在url地址中:例如:http://localhost:port/swagger即可

    Swagger进阶

      1:当有dto项目时,此时dto也需要把注释打到客户端,注意dto项目也参考上面第7点生成xml文件,复制第8点的方法

      2:Swagger新增Header信息,在上方注释的地方加入:c.OperationFilter<HttpHeaderFilter>(); 拷贝下方代码

    public class HttpHeaderFilter : IOperationFilter
            {
                public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
                {
                    
                    if (operation.parameters == null)
                        operation.parameters = new List<Parameter>();
                    var filterPipeline = apiDescription.ActionDescriptor.GetFilterPipeline(); //判断是否添加权限过滤器
                    var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Instance)
                        .Any(filter => filter is ErpFilterAttribute); //判断是否允许匿名方法 
                    //var allowAnonymous = apiDescription.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
                    if (isAuthorized)
                    {
    
                        operation.parameters.Add(new Parameter
                        {
                            name = "AppId",
                            @in = "header",
                            description = "应用ID(机构编号)",
                            required = false,
                            type = "string"
                        });
    
                        operation.parameters.Add(new Parameter
                        {
                            name = "Version",
                            @in = "header",
                            description = "版本号",
                            required = false,
                            type = "string"
                        });
    
                        operation.parameters.Add(new Parameter
                        {
                            name = "Ts",
                            @in = "header",
                            description = "时间戳",
                            required = false,
                            type = "string"
                        });
    
                        operation.parameters.Add(new Parameter
                        {
                            name = "Lang",
                            @in = "header",
                            description = "语言包",
                            required = false,
                            type = "string"
                        });
    
                        operation.parameters.Add(new Parameter
                        {
                            name = "Sign",
                            @in = "header",
                            description = "签名",
                            required = false,
                            type = "string"
                        });
    
                        return;
                    }
                }
            }
    View Code

      3:注释的用法

      注释的用法,在API接口中"///"三斜杠注释的summary为接口名注释,summary下回车<remarks>为备注,注意每个字段的注释必须要全面,否则无法显示完全

      参考代码如下

    /// <summary>
            /// 角色 分页列表
            /// </summary>
            /// <remarks>
            /// Code返回值说明:
            /// 
            ///         错误码地址:http://xxxx.com/
            /// 
            /// </remarks>
            /// <param name="conditionModel">分页查询条件</param>
            /// <returns></returns>
            [HttpGet, Route("api/ClientRoles")]
            public OutputModel<PagingOutputModel<List<BaseRoleDto>>> GetRoleList([FromUri]PagingInputModel conditionModel)
    {
        return null;
    
    }
    View Code

      4:显示控制器注释

        新建:CachingSwaggerProvider.cs,代码如下 注意Mike.Merchant.WebApi.XML需要替换成你本地的工程目录

    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Xml;
    using Swashbuckle.Swagger;
    using System.IO;
    
    namespace Mike.Merchant.WebApi
    {
        public class CachingSwaggerProvider : ISwaggerProvider
        {
            private static ConcurrentDictionary<string, SwaggerDocument> _cache =
                new ConcurrentDictionary<string, SwaggerDocument>();
    
            private readonly ISwaggerProvider _swaggerProvider;
    
            public CachingSwaggerProvider(ISwaggerProvider swaggerProvider)
            {
                _swaggerProvider = swaggerProvider;
            }
    
            public SwaggerDocument GetSwagger(string rootUrl, string apiVersion)
            {
                var cacheKey = string.Format("{0}_{1}", rootUrl, apiVersion);
                SwaggerDocument srcDoc = null;
                //只读取一次
                if (!_cache.TryGetValue(cacheKey, out srcDoc))
                {
                    srcDoc = _swaggerProvider.GetSwagger(rootUrl, apiVersion);
    
                    srcDoc.vendorExtensions = new Dictionary<string, object> { { "ControllerDesc", GetControllerDesc() } };
                    _cache.TryAdd(cacheKey, srcDoc);
                }
                return srcDoc;
            }
    
            /// <summary>
            /// 从API文档中读取控制器描述
            /// </summary>
            /// <returns>所有控制器描述</returns>
            public static ConcurrentDictionary<string, string> GetControllerDesc()
            {
                string xmlpath = string.Format("{0}/bin/Mike.Merchant.WebApi.XML", System.AppDomain.CurrentDomain.BaseDirectory);
                ConcurrentDictionary<string, string> controllerDescDict = new ConcurrentDictionary<string, string>();
                if (File.Exists(xmlpath))
                {
                    XmlDocument xmldoc = new XmlDocument();
                    xmldoc.Load(xmlpath);
                    string type = string.Empty, path = string.Empty, controllerName = string.Empty;
    
                    string[] arrPath;
                    int length = -1, cCount = "Controller".Length;
                    XmlNode summaryNode = null;
                    foreach (XmlNode node in xmldoc.SelectNodes("//member"))
                    {
                        type = node.Attributes["name"].Value;
                        if (type.StartsWith("T:"))
                        {
                            //控制器
                            arrPath = type.Split('.');
                            length = arrPath.Length;
                            controllerName = arrPath[length - 1];
                            if (controllerName.EndsWith("Controller"))
                            {
                                //获取控制器注释
                                summaryNode = node.SelectSingleNode("summary");
                                string key = controllerName.Remove(controllerName.Length - cCount, cCount);
                                if (summaryNode != null && !string.IsNullOrEmpty(summaryNode.InnerText) && !controllerDescDict.ContainsKey(key))
                                {
                                    controllerDescDict.TryAdd(key, summaryNode.InnerText.Trim());
                                }
                            }
                        }
                    }
                }
                return controllerDescDict;
            }
        }
    }
    View Code

        新建:swagger_show.js,代码如下

    var ControllerSummary = function () {
        var urlval = $("#input_baseUrl").val()
        $.ajax({
            type: "get",
            async: true,
            url: urlval,
            dataType: "json",
            success: function (data) {
                var summaryDict = data.ControllerDesc;
                var id, controllerName, strSummary;
                $("#resources_container .resource").each(function (i, item) {
                    id = $(item).attr("id");
                    if (id) {
                        controllerName = id.substring(9);
                        strSummary = summaryDict[controllerName];
                        if (strSummary) {
                            $(item).children(".heading").children(".options").prepend('<li style="color:red;" class="controller-summary" title="' + strSummary + '">' + strSummary + '</li>');
                        }
                    }
                });
            }
        });
    }
    ControllerSummary()
    View Code

        打开SwaggerConfig.cs 代码如下

        注意代码:c.InjectJavaScript(thisAssembly, "Mike.Merchant.WebApi.Scripts.swagger_show.js");

        后面的这个为工程目录.文件夹.js。

    GlobalConfiguration.Configuration
                    .EnableSwagger(c =>
                        {
                            c.SingleApiVersion("v1", "Api文档");
                            c.OperationFilter<HttpHeaderFilter>();
                            c.IncludeXmlComments(GetXmlCommentsPath());
                            //c.IncludeXmlComments(GetDtoXmlCommentsPath());
                            c.CustomProvider((defaultProvider) => new CachingSwaggerProvider(defaultProvider));
                        })
                    .EnableSwaggerUi(c =>
                        {
                            c.DocumentTitle("Api文档");
                            c.InjectJavaScript(thisAssembly, "Mike.Merchant.WebApi.Scripts.swagger_show.js");
                        });
    View Code

    图片展示

     

     

  • 相关阅读:
    JavaScript Array filter() 方法
    Object.assign方法的使用入门
    使用ES6新特性async await进行异步处理
    win10系统怎么设置软件开机启动
    【ES6学习笔记之】Object.assign()高级编程
    如何使用闭包形成计数器
    多次调用settimeout 如何使用单例模式
    在线表单设计器现在已经开源
    VisualStudio2017集成GitHub
    PHP使用curl替代file_get_contents
  • 原文地址:https://www.cnblogs.com/zhoudemo/p/8886442.html
Copyright © 2011-2022 走看看