我在Mininal API应用程序中映射了以下路由:

app.MapGet("api/test", async Task<Results<PushStreamHttpResult, NotFound>> (bool fail) => {
    if (fail) return TypedResults.NotFound();
    return TypedResults.Stream(stream => WriteToStream(stream), "text/plain");
}).WithSummary("Test Streaming results");

async Task WriteToStream(Stream stream) {
    // do the writing... not needed for sample code
}

我找不到一种方法来在swagger/OpenAPI UI和模式中为这个TypedResults类型生成适当的文档.我可以对其他结果类型执行此操作:

app.MapGet("api/thisworks", async Task<
    Results<
        Ok<ApiResult>,
        BadRequest<ApiResult>,
        NotFound<ApiResult>>> () => { ... }

它为许多这样的返回类型生成适当的文档,例如:

Proper swagger return types documentation

有没有一种方法可以自动实现TypedResults.Stream/PushStreamHttpResult的相同功能?

推荐答案

swagger docs人开始:

ApiExplorer(Swashbakle构建在其上的ASP.NET核心元数据组件)默认情况下不呈现FileResult类型,因此您需要使用Products属性显式地告诉它:

[HttpGet("{fileName}")]
[Produces("application/octet-stream", Type = typeof(FileResult))]
public FileResult GetFile(string fileName)

PushStreamHttpResult也是文件结果,似乎同样的规则也适用于它,因此您可以使用Produces调用,例如:

app.MapGet("api/test", async Task<Results<PushStreamHttpResult, NotFound>> (bool fail) =>
    .WithSummary("Test Streaming results")
    .Produces(200, contentType: "text/plain" )

如果所有PushStreamHttpResult个都是纯文本,那么您可以try 使用操作Filter将其自动化:

// sample implementation, adjust for production
public sealed class PushStreamHttpResultFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        var returnType = context.MethodInfo.ReturnType;

        if (ContainsPushStream(returnType))
        {
            // adds plain text only if no 200 are defined
            operation.Responses.TryAdd("200", new OpenApiResponse
            {
                Content = new Dictionary<string, OpenApiMediaType>
                {
                    ["text/plain"] = new OpenApiMediaType()
                    {
                        Schema = new OpenApiSchema()
                    }
                }
            });
        }

        bool ContainsPushStream(Type type)
        {
            if (type == typeof(PushStreamHttpResult))
                return true;
            if (!type.IsConstructedGenericType)
                return false;
            if (type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(Task<>))
                return ContainsPushStream(type.GetGenericArguments()[0]);
            return type.GetGenericArguments().Any(t => t == typeof(PushStreamHttpResult));
        }
    }
}

并将其添加到过滤器中:

builder.Services.AddSwaggerGen(o =>
{
    o.OperationFilter<PushStreamHttpResultFilter>();
});

Csharp相关问答推荐

利用.NET 8中的AddStandardResilienceDeliveries和AddStandardHedgingDeliveries实现Resiliency

如何使用XmlSerializer反序列化字符串数组?

. NET 8控制台应用程序DI错误无法解析Microsoft. Extension. Logging. ILoggerFactory类型的服务'''

如何注册实现同一接口的多个服务并注入到控制器构造函数中

使用C#中的SDK在Microsoft Graph API上使用SubscribedSkus的问题

WPF DataGrid中的三维数据

为什么AggregateException的Catch块不足以处理取消?

如何使用.NET6WPF打印车票?

.NET 8 DI GetServices<;对象&>不工作

当试图限制EF Select 的列时,如何避免重复代码?

为什么我可以用硬编码的集合而不是变量来设置没有setter的IList属性的值?

在Docker容器中运行API项目时,无法本地浏览到index.html

泛型参数在.NET 8 AOT中没有匹配的批注

如何允许数组接受多个类型?

升级后发出SWITCH语句

使用动态键从请求体反序列化JSON

在Unity C#中按键点击错误的参数

实例化列表时的集合表达式是什么?

反编译源代码时出现奇怪的字符

同时通过多个IEumable<;T&>枚举