gpt4 book ai didi

c# - 在 ASP.NET Core 中流式传输内存中生成的文件

转载 作者:太空宇宙 更新时间:2023-11-03 18:01:52 25 4
gpt4 key购买 nike

在互联网上搜索了几个小时后,我对如何解决 ASP.NET Core 2.x 的问题迷失了方向。

我正在即时生成 CSV(可能需要几分钟),然后尝试将其发送回客户端。许多客户端在我开始发送响应之前超时,因此我尝试将文件流式传输回它们(立即响应 200 响应)并异步写入流。 PushStreamContent 似乎可以做到这一点以前在 ASP 中,但我不确定如何构建我的代码,以便异步完成 CSV 生成并立即返回 HTTP 响应。

[HttpGet("csv")]
public async Task<FileStreamResult> GetCSV(long id)
{
// this stage can take 2+ mins, which obviously blocks the response
var data = await GetData(id);
var records = _csvGenerator.GenerateRecords(data);

// using the CsvHelper Nuget package
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
var csv = new CsvWriter(writer);

csv.WriteRecords(stream, records);
await writer.FlushAsync();

return new FileStreamResult(stream, new MediaTypeHeaderValue("text/csv))
{
FileDownloadName = "results.csv"
};
}

如果您向此 Controller 方法发出请求,则在整个 CSV 完成生成之前您将一无所获,然后您最终得到响应,此时大多数客户端请求已超时。

我尝试将 CSV 生成代码包装在 Task.Run() 中但这也没有帮助我的问题。

最佳答案

没有 PushStreamContext一种内置于 ASP.NET Core 的类型。但是,您可以 build your own FileCallbackResult 它做同样的事情。此 example code应该这样做:

public class FileCallbackResult : FileResult
{
private Func<Stream, ActionContext, Task> _callback;

public FileCallbackResult(MediaTypeHeaderValue contentType, Func<Stream, ActionContext, Task> callback)
: base(contentType?.ToString())
{
if (callback == null)
throw new ArgumentNullException(nameof(callback));
_callback = callback;
}

public override Task ExecuteResultAsync(ActionContext context)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
var executor = new FileCallbackResultExecutor(context.HttpContext.RequestServices.GetRequiredService<ILoggerFactory>());
return executor.ExecuteAsync(context, this);
}

private sealed class FileCallbackResultExecutor : FileResultExecutorBase
{
public FileCallbackResultExecutor(ILoggerFactory loggerFactory)
: base(CreateLogger<FileCallbackResultExecutor>(loggerFactory))
{
}

public Task ExecuteAsync(ActionContext context, FileCallbackResult result)
{
SetHeadersAndLog(context, result, null);
return result._callback(context.HttpContext.Response.Body, context);
}
}
}

用法:
[HttpGet("csv")]
public IActionResult GetCSV(long id)
{
return new FileCallbackResult(new MediaTypeHeaderValue("text/csv"), async (outputStream, _) =>
{
var data = await GetData(id);
var records = _csvGenerator.GenerateRecords(data);
var writer = new StreamWriter(outputStream);
var csv = new CsvWriter(writer);
csv.WriteRecords(stream, records);
await writer.FlushAsync();
})
{
FileDownloadName = "results.csv"
};
}

请记住 FileCallbackResult具有与 PushStreamContext 相同的限制: 如果回调中发生错误,Web 服务器没有好的方法通知客户端该错误。您所能做的就是传播异常,这将导致 ASP.NET 提前关闭连接,因此客户端会收到“连接意外关闭”或“下载中止”错误。这是因为 HTTP 在正文开始流式传输之前首先在 header 中发送错误代码。

关于c# - 在 ASP.NET Core 中流式传输内存中生成的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56458452/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com