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}\bin\{项目名称}.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

图片展示

 

 

 

 

 

 

posted @ 2018-04-19 21:47  随风ˇ止步  阅读(1071)  评论(0编辑  收藏  举报