WebAPI StreamContent与PushStreamContent

我正在实施一个MVC4 + WebAPI版本的BluImp jQuery File

Upload,在我初次尝试时都可以很好地工作,但是Im试图确保在下载非常大的文件(〜2GB)的同时充分利用内存。

我已阅读Filip

Woj在PushStreamContent上的文章,并尽我所能实现了这一点(删除异步部分-

也许这是问题所在?)。当我运行测试并观看TaskManager时,我并没有看到明智的内存使用差异,而是试图了解响应处理方式之间的差异。

这是我的StreamContent版本:

private HttpResponseMessage DownloadContentNonChunked()

{

var filename = HttpContext.Current.Request["f"];

var filePath = _storageRoot + filename;

if (File.Exists(filePath))

{

HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);

response.Content = new StreamContent(new FileStream(filePath, FileMode.Open, FileAccess.Read));

response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")

{

FileName = filename

};

return response;

}

return ControllerContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, "");

}

这是我的PushStreamContent版本:

public class FileDownloadStream

{

private readonly string _filename;

public FileDownloadStream(string filePath)

{

_filename = filePath;

}

public void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)

{

try

{

var buffer = new byte[4096];

using (var video = File.Open(_filename, FileMode.Open, FileAccess.Read))

{

var length = (int)video.Length;

var bytesRead = 1;

while (length > 0 && bytesRead > 0)

{

bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));

outputStream.Write(buffer, 0, bytesRead);

length -= bytesRead;

}

}

}

catch (HttpException ex)

{

return;

}

finally

{

outputStream.Close();

}

}

}

private HttpResponseMessage DownloadContentChunked()

{

var filename = HttpContext.Current.Request["f"];

var filePath = _storageRoot + filename;

if (File.Exists(filePath))

{

var fileDownload = new FileDownloadStream(filePath);

var response = Request.CreateResponse();

response.Content = new PushStreamContent(fileDownload.WriteToStream, new MediaTypeHeaderValue("application/octet-stream"));

response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")

{

FileName = filename

};

return response;

}

return ControllerContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, "");

}

我的问题是为什么两种方法的内存使用量没有太大差异?另外,我已经下载了适用于StreamContent类型的PDB,并且可以看到对缓冲区大小的引用等(请参见下文),因此我想确切地知道PushStreamContent在StreamContent之上和之外正在做什么。我已经检查了MSDN上的Type信息,但本文对解释的解释有点小!

namespace System.Net.Http

{

/// <summary>

/// Provides HTTP content based on a stream.

/// </summary>

[__DynamicallyInvokable]

public class StreamContent : HttpContent

{

private Stream content;

private int bufferSize;

private bool contentConsumed;

private long start;

private const int defaultBufferSize = 4096;

/// <summary>

/// Creates a new instance of the <see cref="T:System.Net.Http.StreamContent"/> class.

/// </summary>

/// <param name="content">The content used to initialize the <see cref="T:System.Net.Http.StreamContent"/>.</param>

[__DynamicallyInvokable]

[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]

public StreamContent(Stream content)

: this(content, 4096)

{

}

回答:

关于这两种方法的内存使用情况,对于StreamContent和PushStreamContent,Web

API不会缓冲响应。以下代码快照来自WebHostBufferPolicySelector。源代码

    /// <summary>

/// Determines whether the host should buffer the <see cref="HttpResponseMessage"/> entity body.

/// </summary>

/// <param name="response">The <see cref="HttpResponseMessage"/>response for which to determine

/// whether host output buffering should be used for the response entity body.</param>

/// <returns><c>true</c> if buffering should be used; otherwise a streamed response should be used.</returns>

public virtual bool UseBufferedOutputStream(HttpResponseMessage response)

{

if (response == null)

{

throw Error.ArgumentNull("response");

}

// Any HttpContent that knows its length is presumably already buffered internally.

HttpContent content = response.Content;

if (content != null)

{

long? contentLength = content.Headers.ContentLength;

if (contentLength.HasValue && contentLength.Value >= 0)

{

return false;

}

// Content length is null or -1 (meaning not known).

// Buffer any HttpContent except StreamContent and PushStreamContent

return !(content is StreamContent || content is PushStreamContent);

}

return false;

}

另外,PushStreamContent适用于需要将数据“推”到流中的场景,当StreamContent从流中“拉”数据时。因此,对于当前的文件下载情况,使用StreamContent应该可以。

以下示例:

// Here when the response is being written out the data is pulled from the file to the destination(network) stream

response.Content = new StreamContent(File.OpenRead(filePath));

// Here we create a push stream content so that we can use XDocument.Save to push data to the destination(network) stream

XDocument xDoc = XDocument.Load("Sample.xml", LoadOptions.None);

PushStreamContent xDocContent = new PushStreamContent(

(stream, content, context) =>

{

// After save we close the stream to signal that we are done writing.

xDoc.Save(stream);

stream.Close();

},

"application/xml");

以上是 WebAPI StreamContent与PushStreamContent 的全部内容, 来源链接: utcz.com/qa/424237.html

回到顶部