从WebApi上打开的DbConnection返回流:结束时关闭连接



我正在从SQL数据库中读取varbinary(max)字段作为Stream…我想以文件的形式返回这个流。

我正在使用EF Core,但是EF Core映射需要(或者我不知道更好)将varbinary字段映射到字节数组,这意味着将整个字段读取到内存中,然后创建一个流从WebApi控制器返回。

所以我想知道如何在能够关闭数据阅读器的同时正确返回流。我知道ASP。. NET控制器,当返回流作为文件(与FileStreamResult)关闭流结束,但在这种情况下,我还需要关闭连接(我手动打开)后,流已发送,我不知道如何处理这个。

代码将与以下代码等效(我已经编辑了代码以简化它,可能有拼写错误):

public async Task<IActionResult> GetFile(Guid fileId)
{
var query = @$"SELECT FileBinary
FROM {SchemaName}.{TableName} 
WHERE {GetSqlColumnName(nameof(Id))} = @id";
var idParameter = new SqlParameter("id", fileId) { DbType = DbType.Guid };
await using var command = DbContext.Database.GetDbConnection().CreateCommand();
command.CommandText = query;
command.CommandType = CommandType.Text;
command.Parameters.Add(idParameter);
// DbContext would be the EF context
await DbContext.Database.OpenConnectionAsync().ConfigureAwait(false);
await using var reader = await command.ExecuteReaderAsync(CommandBehavior.SingleRow).ConfigureAwait(false);
await reader.ReadAsync();
var stream = reader.GetStream(0);
return new FileStreamResult(stream, "application/pdf");
}

这段代码似乎工作正常,实际的文件似乎从数据阅读器直接流到http客户端…然而,在这段代码中,打开的数据库连接将在那里保持打开(如果我没有错的话,我听说EF上的dbcontext将从池中重用该连接,但如果它已经打开,它不会试图自己关闭它,从而留下一个"始终打开";连接)。在这一点上我可能是错的(如果我是错的,那么这将解决它,不会有问题)。

如果它实际上是打开的(这是我不想要的),是否有任何方法在流完全发送后关闭它?

根据@ steeve在这篇评论中的想法,我在Stream周围创建了一个包装器,其中包括数据阅读器和连接,并在Stream关闭/处置时关闭/处置它们。

由于代码很长,我在github上创建了一个要点,尽管它是相当简单的代码。

It seems to work fine

最新更新