[C #] swagger swagger and used to avoid the pit

@


Develop web api, when writing the document is a painful thing, but there is no documentation other people do not know how to call, so they had to write.

swagger can automatically generate interface documentation, and test interface, greatly emancipated programmer productivity.

1 Installation

By NuGet installation Swashbuckle.
Here Insert Picture Description
After the installation is complete, App_Start folder will be more of a SwaggerConfig.cs file.
Here Insert Picture Description
Rebuild and publish api, open the page http: // localhost: 7001 / swagger ( here note into your host)

Web page is shown below:
Here Insert Picture Description

2 Modify the name and version number

Framed picture above the name and version number can be modified, open SwaggerConfig.cs file, locate the following code:

c.SingleApiVersion("v1", "API.Test");

Modify the parameters, re-publish.

3 Display Description

swagger comments in the code can be read and displayed on the page. In this way, we will only need to code comments in written, you can generate an API documentation available for others to read up.

swagger xml file is generated by the compiler when to read the comments. The default xml file is not generated, it must first modify the configuration.

The first step: Right Project -> Properties -> Build, the XML document file on the hook.
Here Insert Picture Description
Step two: add configuration
add the following configuration in SwaggerConfig.cs file:

GlobalConfiguration.Configuration
    .EnableSwagger(c =>
        {
            c.SingleApiVersion("v2", "测试 API 接口文档");
            // 配置 xml 文件路径
            c.IncludeXmlComments($@"{System.AppDomain.CurrentDomain.BaseDirectory}\bin\API.Test.xml");
        })

Note: When released, XML documents will not be released together, you need to manually copying the directory publishing.

Here Insert Picture Description

4 shows the finished note and the controller

The default display controller is not a comment, you need to write your own.
App_Start the new class SwaggerControllerDescProvider, as follows:

/// <summary>
/// swagger 显示控制器的描述
/// </summary>
public class SwaggerCacheProvider : ISwaggerProvider
{
    private readonly ISwaggerProvider _swaggerProvider;
    private static ConcurrentDictionary<string, SwaggerDocument> _cache = new ConcurrentDictionary<string, SwaggerDocument>();
    private readonly string _xmlPath;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="swaggerProvider"></param>
    /// <param name="xmlpath">xml文档路径</param>
    public SwaggerCacheProvider(ISwaggerProvider swaggerProvider, string xmlpath)
    {
        _swaggerProvider = swaggerProvider;
        _xmlPath = xmlpath;
    }

    public SwaggerDocument GetSwagger(string rootUrl, string apiVersion)
    {
        var cacheKey = string.Format("{0}_{1}", rootUrl, apiVersion);
        //只读取一次
        if (!_cache.TryGetValue(cacheKey, out SwaggerDocument 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()
    {
        ConcurrentDictionary<string, string> controllerDescDict = new ConcurrentDictionary<string, string>();
        if (File.Exists(_xmlPath))
        {
            XmlDocument xmldoc = new XmlDocument();
            xmldoc.Load(_xmlPath);

            string[] arrPath;
            int cCount = "Controller".Length;
            foreach (XmlNode node in xmldoc.SelectNodes("//member"))
            {
                string type = node.Attributes["name"].Value;
                if (type.StartsWith("T:"))
                {
                    arrPath = type.Split('.');
                    string controllerName = arrPath[arrPath.Length - 1];
                    if (controllerName.EndsWith("Controller"))  //控制器
                    {
                        //获取控制器注释
                        XmlNode 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;
    }
}

Further, the new file and arranged swagger.js embedded resources , this is the role of the file and the display controller Note finished. js code as follows:

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

Adding follows SwaggerConfig.cs:

GlobalConfiguration.Configuration
    .EnableSwagger(c =>
        {
            c.CustomProvider((defaultProvider) => new SwaggerCacheProvider(defaultProvider, $@"{System.AppDomain.CurrentDomain.BaseDirectory}\bin\API.Test.xml"));
        })
        .EnableSwaggerUi(c =>
            {
                c.InjectJavaScript(System.Reflection.Assembly.GetExecutingAssembly(), "API.Test.swagger.js"); 
            });

5 the same route, different methods of query parameters

In the actual ASP.NET Web API, the presence is the same route , the same HTTP method , different query parameters of the method, but I am sorry, swagger is not supported, and will direct error.

The following code,

[Route("api/users")]
public IEnumerable<User> Get()
{
    return users;
}

[Route("api/users")]
public IEnumerable<User> Get(int sex)
{
    return users;
}

报错: Multiple operations with path 'api/users' and method 'GET'.

Here Insert Picture Description
May be added as follows SwaggerConfig.cs:

GlobalConfiguration.Configuration
    .EnableSwagger(c =>
        {
            c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
        })

This configuration means that, when faced with such a situation, take the first display method.

This error can be avoided, but only show a number of methods in the swagger. A temporary solution, not recommended. So the only solution is to set a different route. I do not know the problem after the release will not be repaired.

Some fields are ignored Model in 6

Below, when a new user, a User class background requires as a parameter. Click on the right side Model, it shows the properties and comments User class.
Here Insert Picture Description
However, some fields are in fact no need to transfer the caller. For example State, the caller without having to know the existence of these fields.

Marks to these properties [Newtonsoft.Json.JsonIgnore]characteristic, swagger no longer displayed.

Of course, this approach is flawed because web api when data is returned, the default serialization method call is Newtonsoft.Json serialization.

7 pass header

When you call api, some information is on the HTTP Header, for example token. The swagger is also supported.

Create a new features:

public class ApiAuthorizeAttribute : Attribute
{

}

Create a class code as follows:

public class AuthorityHttpHeaderFilter : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        if (operation.parameters == null)
            operation.parameters = new List<Parameter>();

        //判断是否添加权限过滤器

        var isAuthorized = apiDescription.ActionDescriptor.GetCustomAttributes<ApiAuthorizeAttribute>().Any();
        if (isAuthorized)
        {
            operation.parameters.Add(new Parameter { name = "token", @in = "header", description = "令牌", required = false, type = "string" });
        }
    }
}

This code is to tell swagger, if marked on the method encounters a ApiAuthorizeAttributecharacteristic, then add a named tokenparameter in the headermiddle.

Finally you need to register this filter in SwaggerConfig.cs in.

GlobalConfiguration.Configuration
    .EnableSwagger(c =>
        {
            c.OperationFilter<AuthorityHttpHeaderFilter>();
        })

Results are as follows:
Here Insert Picture Description

HTTP error status code 8

We returned a 400 in the method

[Route("api/users")]
public HttpResponseMessage Post([FromBody]User user)
{
    return new HttpResponseMessage()
    {
        Content = new StringContent("新建用户出错", Encoding.UTF8, "application/json"),
        StatusCode = HttpStatusCode.BadRequest
    };
}

However, swagger returned status code is 0.
Here Insert Picture Description
This is because the Contentspecified JSON format, but the incoming contentare not JSON format.

The contentchange JSON format, or mediaTypechange text/plainit.

Guess you like

Origin www.cnblogs.com/gl1573/p/12652708.html