来自第三方的C#流响应,最小缓冲
我们的ASP.NET MVC端点是另一个第三方HTTP端点的代理,它返回动态生成的大约400MB XML文档 ASP.NET MVC是否有一种方法可以通过“最小”缓冲将第三方响应直接“流”给端点的用户 目前,它看起来像是ASP.NET System.Web.Mvc.Controller.File()将整个文件作为响应加载到内存中。 除了内存使用量的激增,我不知道如何确认这一点 System.Web.Mvc.Controller.File( IIS AppPool内存使用量增加了400MB,之后垃圾收集会重新声明 如果我们可以避免System.Web.Mvc.Controller.File()将整个400MB字符串加载到内存中,通过从传入的响应中“几乎直接”流式传输,这将是一件好事, 可能吗 模拟c#linqpad代码大致如下来自第三方的C#流响应,最小缓冲,c#,asp.net-mvc,C#,Asp.net Mvc,我们的ASP.NET MVC端点是另一个第三方HTTP端点的代理,它返回动态生成的大约400MB XML文档 ASP.NET MVC是否有一种方法可以通过“最小”缓冲将第三方响应直接“流”给端点的用户 目前,它看起来像是ASP.NET System.Web.Mvc.Controller.File()将整个文件作为响应加载到内存中。 除了内存使用量的激增,我不知道如何确认这一点 System.Web.Mvc.Controller.File( IIS AppPool内存使用量增加了400MB,之后垃
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;
}
您可以通过不缓冲而直接将流复制到输出流来减少内存占用,这里有一个快速的例子:
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);
}
}
公共异步任务下载()
{
使用(var httpClient=new System.Net.Http.httpClient())
{
使用(
var stream=await httpClient.GetStreamAsync(
"https://ckannet-storage.commondatastorage.googleapis.com/2012-10-22T184507/aft4.tsv.gz"
))
{
Response.ContentType=“应用程序/八位字节流”;
Response.Buffer=false;
Response.BufferOutput=false;
wait stream.CopyToAsync(Response.OutputStream);
}
返回新的HttpStatusCodeResult(200);
}
}
如果您想进一步减少占用空间,可以使用
CopyToAsync(流、, Int32)
重载,默认值为81920字节。我对代理下载的要求还需要确保源ContentType(或您需要的任何标题)也可以转发。(例如,如果我在中代理下载视频,我需要让用户在直接打开链接时看到相同的浏览器视频播放器屏幕,但不要跳转到文件下载/硬编码内容类型)
根据@devlead+另一篇帖子的回答,我调整了答案上的lil以满足我的需要。这是我调整后的代码,以防有人有同样的需要
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);
}
}
公共异步任务下载(字符串url)
{
使用(var httpClient=new System.Net.Http.httpClient())
{
使用(var response=wait-httpClient.GetAsync(url,HttpCompletionOption.ResponseHeadersRead))
{
response.EnsureSuccessStatusCode();
使用(var stream=await response.Content.ReadAsStreamAsync())
{
Response.ContentType=Response.Content.Headers.ContentType.ToString();
Response.Buffer=false;
Response.BufferOutput=false;
wait stream.CopyToAsync(Response.OutputStream);
}
}
返回新的HttpStatusCodeResult(200);
}
}
p、 s.HttpCompletionOption.ResponseHeadersRead是重要的性能关键。如果没有它,GetAsync将等待整个源响应流的下载,这要慢得多。非常感谢Matias,复制到response.OutputStream就可以了。它看起来像System.Web.Mvc.Controller.File()是罪魁祸首,试图将一切载入记忆