写入请求流

时间:2017-04-19 14:15:11

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

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;
        }

以上代码适用于视频文件mp4小于50mb。但是当我尝试上传一个100mb的文件时,它会抛出异常(请求被中止。)我需要支持高达1.5gb的文件大小所以现在我不确定这种方法对于这么大的文件大小上传是否正确。正确方向的任何建议都会有所帮助...谢谢(我正在尝试将文件上传到Wistia Server) 此行引发异常       - 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);
        }

1 个答案:

答案 0 :(得分: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的总和,这可能比客户端超时允许的多得多)。在这种情况下,通常最好保存文件并安排其他一些“后台任务”来完成上传作业。