asp.net core 3.0 中使用 swagger

intro

上次更新了 asp.net core 3.0 简单的记录了一下 swagger 的使用,那个项目的 api 比较简单,都是匿名接口不涉及到认证以及 api 版本控制,最近把另外一个 api 项目升级到了 3.0,还是遇到了一些问题,这里单独写一篇文章介绍,避免踩坑。

swagger 基本使用

swagger 服务注册:

services.addswaggergen(option =>
    {
        option.swaggerdoc("sparktodo", new openapiinfo
        {
            version = "v1",
            title = "sparktodo api",
            description = "api for sparktodo",
            contact = new openapicontact() { name = "weihanli", email = "weihanli@outlook.com" }
        });
        
        // include document file
        option.includexmlcomments(path.combine(appcontext.basedirectory, $"{typeof(startup).assembly.getname().name}.xml"), true);
    });

中间件配置:

//enable middleware to serve generated swagger as a json endpoint.
app.useswagger();
//enable middleware to serve swagger-ui (html, js, css etc.), specifying the swagger json endpoint
app.useswaggerui(option =>
{
    option.swaggerendpoint("/swagger/sparktodo/swagger.json", "sparktodo docs");

    option.routeprefix = string.empty;
    option.documenttitle = "sparktodo api";
});

为 swagger 添加 bearer token 认证

services.addswaggergen(option =>
{
    // ...

    // add security definitions
    option.addsecuritydefinition("bearer", new openapisecurityscheme()
    {
        description = "please enter into field the word 'bearer' followed by a space and the jwt value",
        name = "authorization",
        in = parameterlocation.header,
        type = securityschemetype.apikey,
    });
    option.addsecurityrequirement(new openapisecurityrequirement
    {
        { new openapisecurityscheme
        {
            reference = new openapireference()
            {
                id = "bearer",
                type = referencetype.securityscheme
            }
        }, array.empty<string>() }
    });
});

支持多个 apiversion

services.addapiversioning(options =>
    {
        options.assumedefaultversionwhenunspecified = true;
        options.defaultapiversion = apiversion.default;
        options.reportapiversions = true;
    });

services.addswaggergen(option =>
{
    // ...

    option.swaggerdoc("v1", new openapiinfo { version = "v1", title = "api v1" });
    option.swaggerdoc("v2", new openapiinfo { version = "v2", title = "api v2" });

    option.docinclusionpredicate((docname, apidesc) =>
    {
        var versions = apidesc.customattributes()
            .oftype<apiversionattribute>()
            .selectmany(attr => attr.versions);

        return versions.any(v => $"v{v.tostring()}" == docname);
    });

    option.operationfilter<removeversionparameteroperationfilter>();
    option.documentfilter<setversioninpathdocumentfilter>();
});

自定义 api version 相关的 operationfilter:

public class setversioninpathdocumentfilter : idocumentfilter
{
    public void apply(openapidocument swaggerdoc, documentfiltercontext context)
    {
        var updatedpaths = new openapipaths();

        foreach (var entry in swaggerdoc.paths)
        {
            updatedpaths.add(
                entry.key.replace("v{version}", swaggerdoc.info.version),
                entry.value);
        }

        swaggerdoc.paths = updatedpaths;
    }
}

public class removeversionparameteroperationfilter : ioperationfilter
{
    public void apply(openapioperation operation, operationfiltercontext context)
    {
        // remove version parameter from all operations
        var versionparameter = operation.parameters.single(p => p.name == "version");
        operation.parameters.remove(versionparameter);
    }
}

中间件配置:

//enable middleware to serve generated swagger as a json endpoint.
app.useswagger();
//enable middleware to serve swagger-ui (html, js, css etc.), specifying the swagger json endpoint
app.useswaggerui(option =>
{
    option.swaggerendpoint("/swagger/v2/swagger.json", "v2 docs");
    option.swaggerendpoint("/swagger/v1/swagger.json", "v1 docs");

    option.routeprefix = string.empty;
    option.documenttitle = "sparktodo api";
});

最终 swagger 效果

memo

上面的配置来自 https://github.com/weihanli/sparktodo 这个项目,要获取代码可以参考这个项目

reference

  • https://github.com/domaindrivendev/swashbuckle.aspnetcore/tree/master/test/websites/multipleversions/swagger
  • https://github.com/domaindrivendev/swashbuckle.aspnetcore/issues/1295
  • https://github.com/weihanli/sparktodo