【Swagger】初级使用

Swagger自动生成在线文档


前言:记一次Swagger的简单使用,包含添加语言汉化、控制器注释、HTTP请求头添加

完整示例
完整示例

1、新建项目WebApi,并添加nuget包引用:Swashbuckle 和 Swagger.Net.UI

需要添加的两个nuget包​​​​​​

2、删除Swagger.Net包等多余文件

1、此包是Swagger.Net.UI包添加时附带的依赖项,由于与Swashbuckle功能重复,所以需要删除

2、删除SwaggerUi文件夹及下属文件,资源文件已重复存在,直接删除这个文件夹

3、删除App_Start文件夹中SwaggerNet.cs文件,此文件与WebApiConfig.cs功能重复,并可能产生冲突

3、配置SwaggerConfig.cs文件

SwaggerConfig文件中配置信息如下

 /// <summary>
        /// 注册Swagger
        /// </summary>
        public static void Register()
        {
            var thisAssembly = typeof(SwaggerConfig).Assembly;
            var xmlFile = string.Format("{0}/bin/ZTcms.WebApi.xml", System.AppDomain.CurrentDomain.BaseDirectory);

            GlobalConfiguration.Configuration
                .EnableSwagger(c =>
                    {
                        // 用于启用和设置Swagger的配置信息。
                        c.SingleApiVersion("v1", "ZTcms.WebApi");
                        //获取项目指定路径下xml文件
                        c.IncludeXmlComments(xmlFile);
                        //c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
                        //用于Controller控制器的注释信息展示
                        c.CustomProvider((defaultProvider) => new SwaggerExtensions(defaultProvider, xmlFile));
                        //用于请求头过滤器加载
                        c.OperationFilter<SwaggerHeaderFilter>();
                    })
                .EnableSwaggerUi(c =>
                    {
                        //路径规则,项目命名空间.文件夹名称.js文件名称
                        c.InjectJavaScript(thisAssembly, "ZTcms.WebApi.Scripts.swaggerui.swagger_lang.js");
                    });
        }

代码写完后,右击解决方案的当前项目属性,在生成栏目中,生成XML文档文件

生成项目模块XML文件

此时,已经可以运行程序看到swagger的界面(localhost:端口号/swagger)

4、设置语言汉化

新建JS文件:swagger_lang.js,内容如下

'use strict';
window.SwaggerTranslator = {
    _words: [],

    translate: function () {
        var $this = this;
        $('[data-sw-translate]').each(function () {
            $(this).html($this._tryTranslate($(this).html()));
            $(this).val($this._tryTranslate($(this).val()));
            $(this).attr('title', $this._tryTranslate($(this).attr('title')));
        });
    },

    setControllerSummary: function () {
        $.ajax({
            type: "get",
            async: true,
            url: $("#input_baseUrl").val(),
            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").first().prepend('<li style="font-weight: bolder;color:#ff5722;font-size: 15px;" class="controller-summary" title="' + strSummary + '">' + strSummary + '</li>');
                        }
                    }
                });
            }
        });
    },
    _tryTranslate: function (word) {
        return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word;
    },

    learn: function (wordsMap) {
        this._words = wordsMap;
    }
};


/* jshint quotmark: double */
window.SwaggerTranslator.learn({
    "Warning: Deprecated": "警告:已过时",
    "Implementation Notes": "实现备注",
    "Response Class": "响应类",
    "Status": "状态",
    "Parameters": "参数",
    "Parameter": "参数",
    "Value": "值",
    "Description": "描述",
    "Parameter Type": "参数类型",
    "Data Type": "数据类型",
    "Response Messages": "响应消息",
    "HTTP Status Code": "HTTP状态码",
    "Reason": "原因",
    "Response Model": "响应模型",
    "Request URL": "请求URL",
    "Response Body": "响应体",
    "Response Code": "响应码",
    "Response Headers": "响应头",
    "Hide Response": "隐藏响应",
    "Headers": "头",
    "Try it out!": "试一下!",
    "Show/Hide": "显示/隐藏",
    "List Operations": "显示操作",
    "Expand Operations": "展开操作",
    "Raw": "原始",
    "can't parse JSON.  Raw result": "无法解析JSON. 原始结果",
    "Model Schema": "模型架构",
    "Model": "模型",
    "apply": "应用",
    "Username": "用户名",
    "Password": "密码",
    "Terms of service": "服务条款",
    "Created by": "创建者",
    "See more at": "查看更多:",
    "Contact the developer": "联系开发者",
    "api version": "api版本",
    "Response Content Type": "响应Content Type",
    "fetching resource": "正在获取资源",
    "fetching resource list": "正在获取资源列表",
    "Explore": "浏览",
    "Show Swagger Petstore Example Apis": "显示 Swagger Petstore 示例 Apis",
    "Can't read from server.  It may not have the appropriate access-control-origin settings.": "无法从服务器读取。可能没有正确设置access-control-origin。",
    "Please specify the protocol for": "请指定协议:",
    "Can't read swagger JSON from": "无法读取swagger JSON于",
    "Finished Loading Resource Information. Rendering Swagger UI": "已加载资源信息。正在渲染Swagger UI",
    "Unable to read api": "无法读取api",
    "from path": "从路径",
    "server returned": "服务器返回",
    //自定义

});
$(function () {
    window.SwaggerTranslator.translate();
    window.SwaggerTranslator.setControllerSummary();
});

重要,文件保存后,需要右击JS文件,选择属性,在属性窗口中,设置生成操作为:嵌入的资源

最后在SwaggerConfig配置文件中,注册JS脚本(可参考上面SwaggerConfig文件图示)

 c.InjectJavaScript(thisAssembly, "ZTcms.WebApi.Scripts.swaggerui.swagger_lang.js");

至此,Swagger运行后,即可显示汉化版本的部分词语转换

5、Controller控制器注释添加

新建扩展文件(类):SwaggerExtensions.cs,内容如下

  /// <summary>
    /// Swagger控制器汉化
    /// </summary>
    public class SwaggerExtensions:ISwaggerProvider
    {
        private readonly ISwaggerProvider _swaggerProvider;
        private static ConcurrentDictionary<string, SwaggerDocument> _cache = new ConcurrentDictionary<string, SwaggerDocument>();
        private readonly string _xml;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="swaggerProvider"></param>
        /// <param name="xml">xml文档路径</param>
        public SwaggerExtensions(ISwaggerProvider swaggerProvider, string xml)
        {
            _swaggerProvider = swaggerProvider;
            _xml = xml;
        }

        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 ConcurrentDictionary<string, string> GetControllerDesc()
        {
            string xmlpath = _xml;
            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;
        }

然后再SwaggerConfig文件中,添加配置信息(可参考上面SwaggerConfig文件图示)

//用于Controller控制器的注释信息展示
                        c.CustomProvider((defaultProvider) => new SwaggerExtensions(defaultProvider, xmlFile));

此时,控制器的注释字符,将显示在Swagger接口列表界面中(参考上面Swagger完整示例图片)

6、添加HTTP请求头

首先添加过滤器文件:SwaggerHeaderFilter.cs,内容如下

/// <summary>
    /// 在Swagger中 实现 自定义 HTTP Header
    /// </summary>
    public class SwaggerHeaderFilter : IOperationFilter
    {
        /// <summary>
        /// WebAPI配合过滤器验证权限
        /// </summary>
        /// <param name="operation"></param>
        /// <param name="schemaRegistry"></param>
        /// <param name="apiDescription"></param>
        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 IAuthorizationFilter); //判断是否允许匿名方法 
            var allowAnonymous = apiDescription.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
            if (isAuthorized && !allowAnonymous)
            {
                //系统相关
                operation.parameters.Add(new Parameter { name = "userid", @in = "header", description = "Authorization-用户ID", required = false, type = "integer" });
                operation.parameters.Add(new Parameter { name = "token", @in = "header", description = "Authorization-token", required = false, type = "string" });
                //operation.parameters.Add(new Parameter { name = "sign", @in = "header", description = "Authorization-sign", required = false, type = "string" });
                //operation.parameters.Add(new Parameter { name = "ip", @in = "header", description = "Authorization-ip地址", required = false, type = "string" });
            }
        }
    }

注意:需要继承IOperationFilter接口

然后再SwaggerConfig文件中,添加此过滤器配置信息(可参考上面SwaggerConfig文件图示)

//用于请求头过滤器加载
                        c.OperationFilter<SwaggerHeaderFilter>();

在需要启用请求头信息处,需要添加方法标签[Authorize],方法如下所示

  /// <summary>
    /// 商家处理模块
    /// </summary>
    public class MerchantsController : ApiBaseController
    {
        /// <summary>
        /// 测试商家1
        /// </summary>
        /// <returns></returns>
        [Authorize]
        public ResultModel Test(int MerchantId)
        {
            return new ResultModel()
            {
                IsSuccess = true,
                Message = "OK"
            };
        }
        /// <summary>
        /// 测试商家2
        /// </summary>
        /// <returns></returns>
        [Authorize]
        public string Test2(int MerchantId)
        {
            return "OK";
        }


    }

注意:ApiBaseController类为ApiController接口的实现,是我在项目自定义的公共控制器,只有继承此接口,才可呗筛选出显示在接口文档中

7、简单的自定义了一下界面样式

在swagger_lang.js文件中,修改函数,如下所示

8、至此,整个Swagger大致搭建完成,已经满足简单小型项目使用,本次体验参考了部分网上相关资料。特此罗列(排名不分先后),表示尊敬

  1. https://blog.csdn.net/sinat_16998945/article/details/84307028
  2. https://blog.csdn.net/HorseRoll/article/details/89095667
  3. https://www.cnblogs.com/dukang1991/p/5627673.html
  4. https://blog.csdn.net/weixin_38319645/article/details/88627321
  5. https://blog.csdn.net/qq_31868147/article/details/88782130
  6. https://blog.csdn.net/weixin_34082789/article/details/93803474

版权声明:本文为weixin_41072161原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。