通过NSwag代码生成器下载文件的正确方法是什么(angular 2 typescript)

lam*_*ama 10 typescript swagger-ui .net-core nswag

我尝试通过角度2打字稿客户端下载文件.Swagger UI中生成的链接工作正常,但生成的typescript客户端没有.

控制器看起来像这样:

    [HttpGet("export")]
    [SwaggerResponse((int) HttpStatusCode.OK, Type = typeof(FileContentResult))]
    [ProducesResponseType(typeof(FileResult), (int) HttpStatusCode.OK)]
    [Produces("text/csv")]
    public virtual FileResult Export(int Id, string fileType, CsvFormat format, bool includeHeader)
    {
        .
        .
        .
        FileStreamResult file = new FileStreamResult(s, "text/csv");
        file.FileDownloadName = ts.Name + "." + fileType;

        return file;
    }
Run Code Online (Sandbox Code Playgroud)

Swagger UI:Swagger UI下载

生成的typescript客户端看起来像这样.如您所见,设置了responseText但从未返回.我错过了什么?

protected processRestTimeSeriesExportGet(response: Response): Observable<void> {
    const status = response.status; 

    if (status === 200) {
        const responseText = response.text();
        return Observable.of<void>(<any>null);
    } else if (status !== 200 && status !== 204) {
        const responseText = response.text();
        return throwException("An unexpected server error occurred.", status, responseText);
    }
    return Observable.of<void>(<any>null);
}
Run Code Online (Sandbox Code Playgroud)

最好的祝福

Lee*_*son 18

Eric Gontier 的解决方案非常适用于 Swashbuckle 4 和 NSwag 12。如果您已经升级到 swashbuckle 5,从而升级到 OpenApi 3 和 NSwag 13,那么解决方案就不同了。相反,您需要一个自定义操作过滤器和一个可重用属性来指示内容类型结果:

自定义属性

/// <summary>
/// Indicates swashbuckle should expose the result of the method as a file in open api (see https://swagger.io/docs/specification/describing-responses/)
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class FileResultContentTypeAttribute : Attribute
{
    public FileResultContentTypeAttribute(string contentType)
    {
        ContentType = contentType;
    }

    /// <summary>
    /// Content type of the file e.g. image/png
    /// </summary>
    public string ContentType { get; }
}
Run Code Online (Sandbox Code Playgroud)

操作过滤器

public class FileResultContentTypeOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        var requestAttribute = context.MethodInfo.GetCustomAttributes(typeof(FileResultContentTypeAttribute), false)
            .Cast<FileResultContentTypeAttribute>()
            .FirstOrDefault();

        if (requestAttribute == null) return;

        operation.Responses.Clear();
        operation.Responses.Add("200", new OpenApiResponse
        {
            Content = new Dictionary<string, OpenApiMediaType>
            {
                {
                    requestAttribute.ContentType, new OpenApiMediaType
                    {
                        Schema = new OpenApiSchema
                        {
                            Type = "string",
                            Format = "binary"
                        }
                    }
                }
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

启动文件

services.AddSwaggerGen(options =>
{
    ...
    options.OperationFilter<FileResultContentTypeOperationFilter>();
}
Run Code Online (Sandbox Code Playgroud)

采样控制器

然后用属性注释你的控制器。

[HttpPost]
[Route("{fileName}.csv")]
[FileResultContentType("text/csv")]
public async Task<ActionResult> Generate(string fileName, [FromBody]MyDto myDto)
{
    var fileMemoryStream = GetCsvAsBytes(myDto);
    return File(fileMemoryStream,
        "text/csv", fileName + ".csv");
}
Run Code Online (Sandbox Code Playgroud)

  • 投票,适用于以下堆栈:Swashbuckle.AspNetCore 5.5.1 + netCore 3.1 + Angular 9.1 + NSwag .NET Core NetCore21 命令行工具,工具链 v13.6.2.0 (NJsonSchema v10.1.23.0 (Newtonsoft.Json) v11.0.0.0)) (2认同)

小智 8

找到这个问题的回应:

在启动时添加:

services.AddSwaggerGen(options =>
{   
options.MapType<FileContentResult>(() => new Schema
       {
                Type = "file",
            });
}
Run Code Online (Sandbox Code Playgroud)

对于您的控制器:

[HttpPost()]
    [SwaggerResponse(200, typeof(FileContentResult))]
    [ProducesResponseType(typeof(FileContentResult), 200)]
    public async Task<FileResult> MyMethod(Viewmodel vm)
    {
Run Code Online (Sandbox Code Playgroud)

一个迟到的回应,但对于有同样问题的人......