Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
来自第三方的C#流响应,最小缓冲_C#_Asp.net Mvc - Fatal编程技术网

来自第三方的C#流响应,最小缓冲

来自第三方的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,之后垃

我们的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代码大致如下

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()是罪魁祸首,试图将一切载入记忆