我们的ASP.NET MVC端点是另一个第三方HTTP端点的代理,它返回大约400MB的动态生成的XML文档。
是否有一种方法可以让ASP.NET MVC流动"流"第三方直接向我们的终端用户做出响应" minimal"缓冲?
目前,ASP.NET System.Web.Mvc.Controller.File()似乎将整个文件作为响应加载到内存中。 除了内存使用量的跳跃之外,我不确定如何确认这一点?
System.Web.Mvc.Controller.File(
IIS AppPool内存使用量增加400MB,然后由垃圾收集重新声明。
如果我们可以避免System.Web.Mvc.Controller.File()将整个400MB字符串加载到内存中,通过流式传输几乎直接"这将是很好的。来自回复, 有可能吗?
模拟c#linqpad代码大致与此类似
public class MyResponseItem {
public Stream myStream;
public string metadata;
}
void Main()
{
Stream stream = MyEndPoint();
//now let user download this XML as System.Web.Mvc.FileResult
System.Web.Mvc.ActionResult fileResult = System.Web.Mvc.Controller.File(stream, "text/xml");
fileResult.Dump();
}
Stream MyEndPoint() {
MyResponseItem myResponse = GetStreamFromThirdParty("https://www.google.com");
return myResponse.myStream;
}
MyResponseItem GetStreamFromThirdParty(string fullUrl)
{
MyResponseItem myResponse = new MyResponseItem();
System.Net.WebResponse webResponse = System.Net.WebRequest.Create(fullUrl).GetResponse();
myResponse.myStream = webResponse.GetResponseStream();
return myResponse;
}
答案 0 :(得分:5)
您可以通过不缓冲来减少内存占用,只需将流直接复制到输出流,快速n'这里有一个肮脏的例子:
public async Task<ActionResult> Download()
{
using (var httpClient = new System.Net.Http.HttpClient())
{
using (
var stream = await httpClient.GetStreamAsync(
"https://ckannet-storage.commondatastorage.googleapis.com/2012-10-22T184507/aft4.tsv.gz"
))
{
Response.ContentType = "application/octet-stream";
Response.Buffer = false;
Response.BufferOutput = false;
await stream.CopyToAsync(Response.OutputStream);
}
return new HttpStatusCodeResult(200);
}
}
如果您想减少占用空间,可以设置较低的缓冲区大小CopyToAsync(Stream, Int32)
重载,默认为81920字节。
答案 1 :(得分:0)
我对代理下载的要求还需要确保也可以转发源ContentType(或您需要的任何标头)。 (例如,如果我在http://techslides.com/sample-webm-ogg-and-mp4-video-files-for-html5中代理下载视频,则需要让用户看到相同的浏览器-视频播放器屏幕,因为他们直接打开链接,但不能跳转到文件下载/硬编码的ContentType)
基于@devlead +另一则帖子https://stackoverflow.com/a/30164356/4684232的回答,我对回答的范围进行了调整以满足自己的需要。如果有人有同样的需求,这是我经过调整的代码。
public async Task<ActionResult> Download(string url)
{
using (var httpClient = new System.Net.Http.HttpClient())
{
using (var response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
{
response.EnsureSuccessStatusCode();
using (var stream = await response.Content.ReadAsStreamAsync())
{
Response.ContentType = response.Content.Headers.ContentType.ToString();
Response.Buffer = false;
Response.BufferOutput = false;
await stream.CopyToAsync(Response.OutputStream);
}
}
return new HttpStatusCodeResult(200);
}
}
p.s。 HttpCompletionOption.ResponseHeadersRead是重要的性能关键。如果没有它,GetAsync将一直等到整个源响应流都被下载为止,这要慢得多。