web*_*ake 3 .net c# sql-server asp.net-mvc asp.net-core
我正在尝试将 sql server 中存储的内容作为 varbinary(max) 流式传输到客户端。我能够使其工作,但是连接将保持打开状态,直到垃圾收集。如果我在返回结果之前处置连接、读取器或蒸汽,则会导致对象处置错误。
我希望避免将数据复制到内存中(因为它可能很大),同时在完成后正确处理对象。实现这两个目标的最佳方法是什么?
如果相关的话,我正在使用 .NET Core 2.0。
更新:这不是其他人的重复(How do I dispose my filestream when Implementing a file download in ASP.NET?),因为我不是问如何处置流,而是问如何处置相关的连接对象。我的问题更多是关于确保连接对象被处置的正确方法
下面的代码成功返回结果,但留下未释放的连接:
public async Task<IActionResult> DownloadFile(Guid FileId)
{
var connection = new SqlConnection(DatabaseService.ConnectionString);
await connection.OpenAsync();
var command = connection.CreateCommand();
command.CommandText = "select FileName, FileContent from Files where FileId=@FileId";
command.CommandType = System.Data.CommandType.Text;
command.Parameters.AddWithValue("@FileId", FileId);
var reader = await command.ExecuteReaderAsync(System.Data.CommandBehavior.SequentialAccess | System.Data.CommandBehavior.SingleRow);
if (!await reader.ReadAsync())
return NotFound();
var attachmentName = Convert.ToString(reader[0]);
var stream = reader.GetStream(1);
var response = File(stream, "application/octet-stream", attachmentName);
return response;
}
Run Code Online (Sandbox Code Playgroud)
下面的代码处理了对象,但无法传输内容,因为它首先被处理
public async Task<IActionResult> DownloadFile(Guid FileId)
{
using (var connection = new SqlConnection(DatabaseService.ConnectionString))
{
await connection.OpenAsync();
using (var command = connection.CreateCommand())
{
command.CommandText = "select FileName, FileContent from Files where FileId=@FileId";
command.CommandType = System.Data.CommandType.Text;
command.Parameters.AddWithValue("@FileId", FileId);
using (var reader = await command.ExecuteReaderAsync(System.Data.CommandBehavior.SequentialAccess | System.Data.CommandBehavior.SingleRow))
{
if (!await reader.ReadAsync())
return NotFound();
var attachmentName = Convert.ToString(reader[0]);
using (var stream = reader.GetStream(1))
{
var response = File(stream, "application/octet-stream", attachmentName);
return response;
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
大卫·布朗的回答给了我信息。我需要使用注册一次性组件HttpContext.Response.RegisterForDispose();。这确保了它在请求完成后被处理。
以下是更新后的代码
public async Task<IActionResult> DownloadFile(Guid FileId)
{
var connection = new SqlConnection(DatabaseService.ConnectionString);
HttpContext.Response.RegisterForDispose(connection);
await connection.OpenAsync();
var command = connection.CreateCommand();
HttpContext.Response.RegisterForDispose(command);
command.CommandText = "select FileName, FileContent from Files where FileId=@FileId";
command.CommandType = System.Data.CommandType.Text;
command.Parameters.AddWithValue("@FileId", FileId);
var reader = await command.ExecuteReaderAsync(System.Data.CommandBehavior.SequentialAccess | System.Data.CommandBehavior.SingleRow);
HttpContext.Response.RegisterForDispose(reader);
if (!await reader.ReadAsync())
return NotFound();
var attachmentName = Convert.ToString(reader[0]);
var stream = reader.GetStream(1);
HttpContext.Response.RegisterForDispose(stream);
var response = File(stream, "application/octet-stream", attachmentName);
return response;
}
Run Code Online (Sandbox Code Playgroud)
如果其他人也有同样的问题,我添加这个答案是为了清楚起见
| 归档时间: |
|
| 查看次数: |
1746 次 |
| 最近记录: |