在 ASP.NET Web API 2 中,ByteRangeStreamContent returns 与来自 Azure 存储的流一起使用时不正确的数据
In ASP.NET Web API 2, ByteRangeStreamContent returns incorrect data when used with a stream from Azure Storage
给出这样的范围请求:
curl -r 0-16 https://example.com/api/blob/mobydick.txt -o moby0.txt -D -
我们得到:
Call me Ishmael.
但是像这样的范围请求:
curl -r 16-32 https://example.com/api/blob/mobydick.txt -o moby1.txt -D -
我们仍然得到:
Call me Ishmael.
这是使用以下代码(经过编辑以删除获取 blob、考虑范围不 headers 或范围 open-ended 等的请求):
Stream myBlobStream = await myBlob.OpenReadAsync();
HttpResponseMessage message = Request.CreateResponse(HttpStatusCode.PartialContent);
message.Content = new ByteRangeStreamContent(myBlobStream , range, myBlob.Properties.ContentType);
return message;
在我看到的示例中,似乎没有必要手动查找或设置流的位置,因为(据我了解)这应该由 ByteRangeStreamContent 处理。当我尝试手动将流的 Position 设置为 Range 的开头时,结果不一致;有时我最终得到一个 one-byte 文本文件,有时整个文件从范围的开头开始(即忽略范围的结尾)。
至少现在,我已经通过 returning ByteArrayContent 而不是 ByteRangeStreamContent 解决了这个问题。
// Including my setup of the range values this time:
var range = Request.Headers.Range;
long chunkLength = 2500000;
long? beginRange = range.Ranges.First().From;
long? endRange = range.Ranges.First().To;
if (endRange == null)
{
if ((beginRange + chunkLength) > myBlob.Properties.Length)
{
endRange = myBlob.Properties.Length - 1;
}
else
{
endRange = beginRange + chunkLength;
}
}
var blobStreamPosition = beginRange.Value;
// Set the stream position
blobStream.Position = blobStreamPosition;
int bytesToRead = (int)(endRange - blobStreamPosition + 1);
// Using BinaryReader for convenience
BinaryReader binaryReader = new BinaryReader(blobStream);
byte[] blobByteArray = binaryReader.ReadBytes(bytesToRead);
message.Content = new ByteArrayContent(blobByteArray);
// Don't forget that now you have to set the content range header yourself:
message.Content.Headers.ContentRange = new ContentRangeHeaderValue(blobStreamPosition, endRange.Value, myBlob.Properties.Length);
message.Content.Headers.ContentType = new MediaTypeHeaderValue(myBlob.Properties.ContentType);
binaryReader.Dispose();
blobStream.Dispose();
老实说,我不知道这个解决方案中可能潜伏着什么问题;如果不出意外,该字节数组意味着它可能应该包含对部分响应大小的限制 return。我宁愿使用 ByteRangeStreamContent,但这似乎对我们有用。
我们遇到了同样的问题。
WebAPI 2 似乎使用了与标准框架库不同的 System.Net.Http 版本。如果我们专门使用 System.Net.Http 的 4.0.0.0 版本,那么使用
ByteRangeStreamContent 工作正常。使用 4.2.0.0(带有 WebAPI 2 的版本)时,无论范围如何,流总是从头开始,并且还输出太多字节(根据 Fiddler)。
为了解决这个问题,我们添加了
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
到<configuration>
中的<runtime>
属性在Web.config中。
给出这样的范围请求:
curl -r 0-16 https://example.com/api/blob/mobydick.txt -o moby0.txt -D -
我们得到:
Call me Ishmael.
但是像这样的范围请求:
curl -r 16-32 https://example.com/api/blob/mobydick.txt -o moby1.txt -D -
我们仍然得到:
Call me Ishmael.
这是使用以下代码(经过编辑以删除获取 blob、考虑范围不 headers 或范围 open-ended 等的请求):
Stream myBlobStream = await myBlob.OpenReadAsync();
HttpResponseMessage message = Request.CreateResponse(HttpStatusCode.PartialContent);
message.Content = new ByteRangeStreamContent(myBlobStream , range, myBlob.Properties.ContentType);
return message;
在我看到的示例中,似乎没有必要手动查找或设置流的位置,因为(据我了解)这应该由 ByteRangeStreamContent 处理。当我尝试手动将流的 Position 设置为 Range 的开头时,结果不一致;有时我最终得到一个 one-byte 文本文件,有时整个文件从范围的开头开始(即忽略范围的结尾)。
至少现在,我已经通过 returning ByteArrayContent 而不是 ByteRangeStreamContent 解决了这个问题。
// Including my setup of the range values this time:
var range = Request.Headers.Range;
long chunkLength = 2500000;
long? beginRange = range.Ranges.First().From;
long? endRange = range.Ranges.First().To;
if (endRange == null)
{
if ((beginRange + chunkLength) > myBlob.Properties.Length)
{
endRange = myBlob.Properties.Length - 1;
}
else
{
endRange = beginRange + chunkLength;
}
}
var blobStreamPosition = beginRange.Value;
// Set the stream position
blobStream.Position = blobStreamPosition;
int bytesToRead = (int)(endRange - blobStreamPosition + 1);
// Using BinaryReader for convenience
BinaryReader binaryReader = new BinaryReader(blobStream);
byte[] blobByteArray = binaryReader.ReadBytes(bytesToRead);
message.Content = new ByteArrayContent(blobByteArray);
// Don't forget that now you have to set the content range header yourself:
message.Content.Headers.ContentRange = new ContentRangeHeaderValue(blobStreamPosition, endRange.Value, myBlob.Properties.Length);
message.Content.Headers.ContentType = new MediaTypeHeaderValue(myBlob.Properties.ContentType);
binaryReader.Dispose();
blobStream.Dispose();
老实说,我不知道这个解决方案中可能潜伏着什么问题;如果不出意外,该字节数组意味着它可能应该包含对部分响应大小的限制 return。我宁愿使用 ByteRangeStreamContent,但这似乎对我们有用。
我们遇到了同样的问题。
WebAPI 2 似乎使用了与标准框架库不同的 System.Net.Http 版本。如果我们专门使用 System.Net.Http 的 4.0.0.0 版本,那么使用 ByteRangeStreamContent 工作正常。使用 4.2.0.0(带有 WebAPI 2 的版本)时,无论范围如何,流总是从头开始,并且还输出太多字节(根据 Fiddler)。
为了解决这个问题,我们添加了
<dependentAssembly>
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
到<configuration>
中的<runtime>
属性在Web.config中。