Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error with a file upload WCF WEB API (Preview 6) : Cannot write more bytes to the buffer than the configured maximum buffer size: 65536

I'm having a real problem with the WCF web api.

I have a simple method that uploads a file and saves to disk. I seem to have set all the right params, but get the above error message when I try to upload a 2mb file.

Server Code:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    HttpServiceHostFactory _factory  = new HttpServiceHostFactory();

    var config = new HttpConfiguration() 
    { 
        EnableTestClient = true, 
        IncludeExceptionDetail = true,
        TransferMode = System.ServiceModel.TransferMode.Streamed,
        MaxReceivedMessageSize = 4194304,
        MaxBufferSize = 4194304    
    };

    _factory.Configuration = config;

    RouteTable.Routes.Add(new ServiceRoute("api/docmanage", _factory, typeof(WorksiteManagerApi)));
}

client:

HttpClientHandler httpClientHandler = new HttpClientHandler();
httpClientHandler.MaxRequestContentBufferSize = 4194304;

var byteArray = 
    Encoding.ASCII.GetBytes(ConnectionSettings.WebUsername + ":" + ConnectionSettings.WebPassword);

HttpClient httpClient = new HttpClient(httpClientHandler);
httpClient.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
httpClient.BaseAddress = new Uri(ConnectionSettings.WebApiBaseUrl);
httpClient.MaxResponseContentBufferSize = 4194304;

...

multipartFormDataContent.Add(new FormUrlEncodedContent(formValues));
multipartFormDataContent.Add(byteArrayContent);

var postTask = httpClient.PostAsync("api/docmanage/UploadFile", multipartFormDataContent);

Then, on the server:

[WebInvoke(Method = "POST")]
public HttpResponseMessage UploadFile(HttpRequestMessage request)
{
    // Verify that this is an HTML Form file upload request
    if (!request.Content.IsMimeMultipartContent("form-data"))
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }

    // Create a stream provider for setting up output streams
    MultipartFormDataStreamProvider streamProvider = new MultipartFormDataStreamProvider();

    // Read the MIME multipart content using the stream provider we just created.
    IEnumerable<HttpContent> bodyparts = request.Content.ReadAsMultipart(streamProvider);

    foreach (var part in bodyparts)
    {
        switch (part.Headers.ContentType.MediaType)
        {
            case "application/octet-stream":
                if (part.Headers.ContentLength.HasValue)
                {
                    // BLOWS UP HERE:            
                    var byteArray = part.ReadAsByteArrayAsync().Result;

                    if (null == fileName)
                    {
                        throw new HttpResponseException(HttpStatusCode.NotAcceptable);
                    }
                    else
                    {
                        uniqueFileId = Guid.NewGuid().ToString();
                        string tempFilename = Path.GetTempPath() + @"\" + uniqueFileId + fileName;

                        using (FileStream fileStream = File.Create(tempFilename, byteArray.Length))
                        {
                            fileStream.Write(byteArray, 0, byteArray.Length); 
                        }
                    }

                }
                break;
        }
    }
}

Any ideas? I am using the latest preview of the web api.... I noticed a lot is missing from the support documentation but it seems there is some buffer limit that I can't find out how to specify or is being ignored.....

like image 910
Dave Stringer Avatar asked Jan 30 '12 14:01

Dave Stringer


2 Answers

One of the things that is not made clear in the (lack of) documentation for the HttpContent class is that the default internal buffer is 64K so any content that is not a stream will throw the exception you are seeing once the content exceeds 64Kb.

The way around it is to use the following:

part.LoadIntoBufferAsync(bigEnoughBufferSize).Result();
var byteArray = part.ReadAsByteArrayAsync().Result;

I presume that the 64K limit on the buffer of the HttpContent class is there for preventing to much memory allocation occuring on the server. I wonder if you would be better of passing through the byte array content as a StreamContent? This way it should still work without having to increase the HttpContent buffer size.

like image 133
BBoy Avatar answered Nov 01 '22 00:11

BBoy


Have you set the maxRequestLength in web.config:

<httpRuntime maxRequestLength="10240" />
like image 45
Toni Parviainen Avatar answered Nov 01 '22 01:11

Toni Parviainen