是否可以在 ASP .NET Core 中使用 Swashbuckle 在 Swagger 2.0 和 Open API 3 格式中公开相同的 Swagger JSON?

Is it possible to expose the same Swagger JSON in both Swagger 2.0 and Open API 3 formats with Swashbuckle in ASP .NET Core?

我们有一个仅适用于 Swagger 2.0 JSON 格式的遗留应用程序。对于其他所有内容,我们希望使用 Open API 格式。

Swashbuckle .NET Core 是否有任何方法可以在不同的 URL 下以不同的格式公开 JSON?看起来 UseSwagger 方法选项中的 SerializeAsV2 属性 对于所有端点都是全局的。

基本上,我希望以下端点包含不同格式的相同 API 数据。

/swagger/v1/openapi/swagger.json
/swagger/v1/swagger2/swagger.json

您可以将OpenAPI文档序列化为V2,自行服务。以SwaggerMiddleware为参考:

第一次注册SwaggerGenerator:

services.AddTransient<SwaggerGenerator>();

然后注入SwaggerGenerator并构建文档。从端点或控制器提供服务。您可以将版本作为路径参数来决定服务哪个版本。

app.UseEndpoints(e =>
{
    // ...
    e.MapGet("/swagger/{documentName}/swagger.{version}.json", context =>
    {
        var documentName = context.Request.RouteValues.GetValueOrDefault("documentName", null) as string;
        var version = context.Request.RouteValues.GetValueOrDefault("version", null) as string;
        if (documentName is null || version is null)
        {
            context.Response.StatusCode = StatusCodes.Status400BadRequest;
            return Task.CompletedTask;
        }

        // inject SwaggerGenerator
        var swaggerGenerator = context.RequestServices.GetRequiredService<SwaggerGenerator>();
        var doc = swaggerGenerator.GetSwagger(documentName);

        // serialize the document as json
        using var writer = new StringWriter(CultureInfo.InvariantCulture);
        var serializer = new OpenApiJsonWriter(writer);
        if (version == "v2")
        {
            doc.SerializeAsV2(serializer);
        }
        else
        {
            doc.SerializeAsV3(serializer);
        }
        var json = writer.ToString();

        // serve it as json
        context.Response.ContentType = MediaTypeNames.Application.Json;
        return context.Response.WriteAsync(json, new UTF8Encoding(false));
    });
});

当您访问 /swagger/v1/openapi.v2.json 时,您将获得序列化为 v2 的 OpenAPI 文档。

{
  "swagger": "2.0",
  "info": {
    "title": "ApiPlayground",
    "version": "1.0"
  },
  "paths": { ... }
}

/swagger/v1/openapi.v3.json 将为您提供序列化为 v3 的文档:

{
  "openapi": "3.0.1",
  "info": {
    "title": "ApiPlayground",
    "version": "1.0"
  },
  "paths": { ... },
  "components": { ... }
}

另一种方法是拆分请求管道:

// serve v3 from /swagger/v1/swagger.json
app.UseSwagger(o => o.RouteTemplate = "swagger/{documentName}/swagger.json");

// serve v2 from /swagger2/v1/swagger.json
app.Map("/swagger2", swaggerApp => 
    swaggerApp.UseSwagger(options => {
        // note the dropped prefix "swagger/"
        options.RouteTemplate = "{documentName}/swagger.json";
        options.SerializeAsV2 = true;
    })
);