【问题标题】:The request was aborted error while writing to request stream写入请求流时请求中止错误
【发布时间】:2017-09-15 20:01:57
【问题描述】:
public HttpWebResponse PushFileToWistia(byte[] contentFileByteArray, string fileName)
    {
        StringBuilder postDataBuilder = new StringBuilder();
        postDataBuilder.Append("I am appending all the wistia config and setting here");
        byte[] postData = null;
        using (MemoryStream postDataStream = new MemoryStream())
        {
            byte[] postDataBuffer = Encoding.UTF8.GetBytes(postDataBuilder.ToString());
            postDataStream.Write(postDataBuffer, 0, postDataBuffer.Length);
            postDataStream.Write(contentFileByteArray, 0, contentFileByteArray.Length);
            postDataBuffer = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--");
            postDataStream.Write(postDataBuffer, 0, postDataBuffer.Length);
            postData = postDataStream.ToArray();
        }

        ServicePointManager.Expect100Continue = false;
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(AppConfig.WistiaCustomCourseBucket);
        request.Method = "POST";
        request.Expect = String.Empty;
        request.Headers.Clear();
        request.ContentType = "multipart/form-data; boundary=" + boundary;
        request.ContentLength = postData.Length;

        Stream requestStream = request.GetRequestStream();
        requestStream.Write(postData, 0, postData.Length);  //for file > 100mb this call throws and error --the requet was aborted. the request was canceled. 
        requestStream.Flush();
        requestStream.Close();

        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        return response;
        }

以上代码适用于小于 50mb 的视频文件 mp4。但是当我尝试上传一个 100mb 的文件时,它会抛出异常(请求被中止。)我需要支持高达 1.5gb 的文件大小所以现在我不确定这种方法对于如此大的文件大小上传是否正确。任何正确方向的建议都会有所帮助...谢谢(我正在尝试将文件上传到 Wistia 服务器) 在这一行抛出异常 -- requestStream.Write(postData, 0, postData.Length);

我已尝试更改 web.config 设置,但没有成功: httpRuntime targetFramework="4.5" maxRequestLength="2048576" executionTimeout="12000" requestLengthDiskThreshold="1024"

------异步调用-----

       MemoryStream wistiaFileStream = null;
        using (MemoryStream postDataStream = new MemoryStream())
        {
            postDataStream.Write(contentFileByteArray, 0, contentFileByteArray.Length);
            wistiaFileStream = postDataStream;
            postDataStream.Flush();
            postDataStream.Close();
        }

        Stream requestStream = await request.GetRequestStreamAsync();
        await requestStream.WriteAsync(wistiaMetadata, 0, wistiaMetadata.Length);

 using (wistiaFileStream)
        {
            byte[] wistiaFileBuffer = new byte[500*1024];
            int wistiaFileBytesRead = 0;

            while (
                (wistiaFileBytesRead =
                    await wistiaFileStream.ReadAsync(wistiaFileBuffer, 0, wistiaFileBuffer.Length)) != 0)
            {
                await requestStream.WriteAsync(wistiaFileBuffer, 0, wistiaFileBytesRead);
                await requestStream.FlushAsync();
            }
            await requestStream.WriteAsync(requestBoundary, 0, requestBoundary.Length);
        }

【问题讨论】:

    标签: asp.net-mvc c#-4.0 file-upload stream httprequest


    【解决方案1】:

    我建议转移到 async 并直接从文件系统写入文件以请求,以避免内存中 1.5GB 的三重缓冲(未测试以下警告)。

    public async Task<HttpWebResponse> PushFileToWistiaAsync(string contentFilePath)
    {
        string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
        string contentBoundary = "\r\n--" + boundary + "\r\n";
    
        StringBuilder wistiaMetadataBuilder = new StringBuilder();
        wistiaMetadataBuilder.Append("--" + boundary + "\r\n");
        // Append all the wistia config and setting here
    
        byte[] wistiaMetadata = Encoding.UTF8.GetBytes(wistiaMetadataBuilder.ToString());
        byte[] requestBoundary = Encoding.UTF8.GetBytes(contentBoundary);
    
        ServicePointManager.Expect100Continue = false;
    
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(AppConfig.WistiaCustomCourseBucket);
        request.Method = "POST";
        request.Headers.Clear();
        request.Expect = String.Empty;
        request.ContentType = "multipart/form-data; boundary=" + boundary;
    
        Stream requestStream = await request.GetRequestStreamAsync();
        await requestStream.WriteAsync(wistiaMetadata, 0, wistiaMetadata.Length);
        using (FileStream wistiaFileStream = new FileStream(contentFilePath, FileMode.Open, FileAccess.Read))
        {
            byte[] wistiaFileBuffer = new byte[500 * 1024];
            int wistiaFileBytesRead = 0;
    
            while ((wistiaFileBytesRead = await wistiaFileStream.ReadAsync(wistiaFileBuffer, 0, wistiaFileBuffer.Length)) != 0)
            {
                await requestStream.WriteAsync(wistiaFileBuffer, 0, wistiaFileBytesRead);
                await requestStream.FlushAsync();
            }
        }
        await requestStream.WriteAsync(requestBoundary, 0, requestBoundary.Length);
    
        return (HttpWebResponse)(await request.GetResponseAsync());
    }
    

    您应该调整缓冲区大小、一次读取的数据量和request.SendChunked 以获得合理的性能。

    这是另一种直接从缓冲区写入请求的方法(不是异步的,因此可能是最差的可扩展性):

    public HttpWebResponse PushFileToWistia(byte[] contentFileByteArray)
    {
        string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
        string contentBoundary = "\r\n--" + boundary + "\r\n";
    
        StringBuilder wistiaMetadataBuilder = new StringBuilder();
        wistiaMetadataBuilder.Append("--" + boundary + "\r\n");
        // Append all the wistia config and setting here
    
        byte[] wistiaMetadata = Encoding.UTF8.GetBytes(wistiaMetadataBuilder.ToString());
        byte[] requestBoundary = Encoding.UTF8.GetBytes(contentBoundary);
    
        ServicePointManager.Expect100Continue = false;
    
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(AppConfig.WistiaCustomCourseBucket);
        request.Method = "POST";
        request.Headers.Clear();
        request.Expect = String.Empty;
        request.ContentType = "multipart/form-data; boundary=" + boundary;
        request.ContentLength = wistiaMetadata.Length + contentFileByteArray.Length + requestBoundary.Length
    
        // You can play with SendChunked and AllowWriteStreamBuffering to control the size of chunks you send and performance
        //request.SendChunked = true;
        //request.AllowWriteStreamBuffering = false;
    
        int contentFileChunkSize = 500 * 1024;
        int contentFileBytesRead = 0;
    
        Stream requestStream = request.GetRequestStream();
        requestStream.Write(wistiaMetadata, 0, wistiaMetadata.Length);
        while (contentFileBytesRead < contentFileByteArray.Length)
        {
            if ((contentFileBytesRead + contentFileChunkSize) > contentFileByteArray.Length)
            {
                contentFileChunkSize = contentFileByteArray.Length - contentFileBytesRead;
            }
    
            requestStream.Write(contentFileByteArray, contentFileBytesRead, contentFileChunkSize);
            requestStream.Flush();
    
            contentFileBytesRead += contentFileChunkSize;
        }
        requestStream.Write(requestBoundary, 0, requestBoundary.Length);
        requestStream.Close();
    
        // You might need to play with request.Timeout here
        return (HttpWebResponse)request.GetResponse();
    }
    

    此外,如果您在 Web 应用程序中执行此操作并且想要使用异步方法,则需要一直“异步/等待”(因此异步控制器中的异步操作等)。

    一般来说,我不鼓励在 Web 应用程序中作为请求处理的一部分这样做(从用户角度观察到的总时间将是上传到您的应用程序然后到 Wistia 的总和,这可能远远超过客户端超时允许的时间)。在这种情况下,通常最好保存文件并安排其他一些“后台任务”来完成上传工作。

    【讨论】:

    • 我没有从磁盘读取文件我从 HTML 文件上传中获取文件。我不得不稍微修改上述解决方案以适应我的代码。它正确运行异步调用,但没有任何错误。它将成功消息返回给客户端 Ux。但我在 WISTIA 服务器上看不到任何文件。它运行如此之快的 1.5 gb 文件,我认为它实际上不会将文件内容发送到 WISTIA。有没有办法可以停止所有其他执行,直到我们完成异步调用并获得成功状态...我在问题中添加了编辑后的代码
    • @Scorpio 你的实现不会抛出异常吗?如果我阅读正确,wistiaFileStream 在您开始阅读时已关闭。如果您确实必须将文件保留为字节数组(这很危险,因为在 10 个并行请求的情况下,您最终可能会分配 15 GB)我建议直接从该数组写入请求。我会尝试编辑我的答案以显示这一点。
    • @Scorpio 添加了不同方法的示例和一些一般性建议
    猜你喜欢
    • 2021-01-14
    • 2020-03-20
    • 2015-06-08
    • 2020-04-16
    • 2013-10-11
    • 1970-01-01
    • 2019-06-03
    • 2014-04-27
    • 2018-08-09
    相关资源
    最近更新 更多