c# - 解压 SQL Blob 内容并在 PushStreamContent .NET Core 中返回答案
问题描述
我正在.NET Core 服务中开发一个新的 API,新的 API 应该从 SQL 表中读取一个 BLOB,使用 DeflateStream 解压缩它。然后将其返回(流式传输)给客户端。
为了不消耗太多内存。我正在返回类型和PushStreamContent的响应,以便我可以将 sql 流直接复制到响应流中,而无需将 blob 加载到内存中。所以我最终得到了类似的东西。
return this.ResponseMessage(new HttpResponseMessage
{
Content = new PushStreamContent(async (outStream, httpContent, transportContext) =>
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();
using (SqlCommand command = new SqlCommand(query, connection))
{
// The reader needs to be executed with the SequentialAccess behavior to enable network streaming
// Otherwise ReadAsync will buffer the entire BLOB into memory which can cause scalability issues or even OutOfMemoryExceptions
using (SqlDataReader reader = await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess))
{
if (await reader.ReadAsync() && !(await reader.IsDBNullAsync(0)))
{
using (Stream streamToDecompress = reader.GetStream(0))
using (Stream decompressionStream = new DeflateStream(streamToDecompress, CompressionMode.Decompress))
{
// This copyToAsync will take for ever
await decompressionStream.CopyToAsync(outStream);
outStream.close();
return;
}
}
throw new Exception("Couldn't retrieve blob");
}
}
}
},
"application/octet-stream")
});
这里的问题是,将 deflateStream 复制到响应输出流的步骤需要永远如代码中所述。尽管我尝试了相同的确切方法,但是将流写入文件而不是将其复制到 resp 流,它就像一个魅力。
所以你们能帮我解决这个问题吗??使用 PushStreamContent 我错了吗?我应该使用不同的方法吗?问题是我不想将整个 Blob 加载到内存中,我想读取它并即时解压缩它。SqlClient 支持流blob,我想利用它。
解决方案
这是 PushStreamContent 中的一个死锁,我不假装理解。但我复制了它并改变了
await decompressionStream.CopyToAsync(outStream);
至
decompressionStream.CopyTo(outStream);
解决它。
这是完整的复制品:
public ResponseMessageResult Get()
{
var data = new string[] { "value1", "value2" };
var jsonData = Newtonsoft.Json.JsonConvert.SerializeObject(data);
var msSource = new MemoryStream(Encoding.UTF8.GetBytes(jsonData));
var msDest = new MemoryStream();
var compressionStream = new DeflateStream(msDest, CompressionMode.Compress);
msSource.CopyTo(compressionStream);
compressionStream.Close();
var compressedBytes = msDest.ToArray();
var query = "select @bytes buf";
var connectionString = "server=localhost;database=tempdb;integrated security=true";
return this.ResponseMessage(new HttpResponseMessage
{
Content = new PushStreamContent(async (outStream, httpContent, transportContext) =>
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();
using (SqlCommand command = new SqlCommand(query, connection))
{
command.Parameters.Add("@bytes", SqlDbType.VarBinary, -1).Value = compressedBytes;
// The reader needs to be executed with the SequentialAccess behavior to enable network streaming
// Otherwise ReadAsync will buffer the entire BLOB into memory which can cause scalability issues or even OutOfMemoryExceptions
using (SqlDataReader reader = await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess))
{
if (await reader.ReadAsync() && !(await reader.IsDBNullAsync(0)))
{
using (Stream streamToDecompress = reader.GetStream(0))
{
//var buf = new MemoryStream();
//streamToDecompress.CopyTo(buf);
//buf.Position = 0;
using (Stream decompressionStream = new DeflateStream(streamToDecompress, CompressionMode.Decompress))
{
// This copyToAsync will take for ever
//await decompressionStream.CopyToAsync(outStream);
decompressionStream.CopyTo(outStream);
outStream.Close();
return;
}
}
}
throw new Exception("Couldn't retrieve blob");
}
}
}
},
"application/octet-stream")
});
}
推荐阅读
- node.js - 填充后猫鼬调用子方法
- c# - “Mountain”没有实现接口成员“IBiome.height”
- amazon-web-services - 根据 JSON 请求输入抛出特定状态代码 - API Gateway 端点
- python - 在 Python 中为嵌套对象(DynamoDB 和表)使用 Mock
- julia - Julia 中的 UnitRange 类型是什么意思?
- spring - Spring MVC 4 发送错误 400 以响应 AJAX POST
- python - 现在如何通过在聊天中提及来获取用户 ID?
- ios - 调用协议扩展初始化程序
- r - ggplot 使色标范围成为数据范围的子集
- ios - IOS语音识别/控制