7

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.....

tom redfern
  • 30,562
  • 14
  • 91
  • 126
Dave Stringer
  • 349
  • 4
  • 15
  • When posting code please make sure it is formatted to be as readable as possible. It is rude to ask people to spend their time picking through a badly formatted sample. – tom redfern Jan 30 '12 at 14:39
  • Do you have any config entries on server and client? If so then can you post them too – Rajesh Jan 30 '12 at 14:44
  • left all the config to code only... you can see the config params being passed to the service on creation (and on the client).... – Dave Stringer Feb 03 '12 at 15:52

3 Answers3

4

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.

BBoy
  • 1,063
  • 1
  • 10
  • 21
  • Thanks for this.. sorted it out. Just took ages before I got back and revisited the code... lets just say there was a reason I delayed the feature that depended on it! – Dave Stringer Jun 28 '12 at 16:48
1

Have you set the maxRequestLength in web.config:

<httpRuntime maxRequestLength="10240" />
Toni Parviainen
  • 2,217
  • 1
  • 16
  • 15
  • It's not a problem on the request side... the request gets to the server ok... the only problem occurs when the code attempts to read the content into a byte array... at this point it violates the buffer size limit, even though this has been explicitly set when the service was hosted....got a feeling its a bug in wcf.... – Dave Stringer Feb 03 '12 at 15:59
0

I struggled with a similar problem with WCF WinAPI for few days, I was trying to post a file of 12Mb and I could not figure out what was going on. My server side was a WCF service hosted in IIS; my problem was not the WCF settings but what Toni mentioned. When hosting in IIS, remember to increase this setting. The MS documentation indicates that the default value is 4Mb, that explains why I could post files of 400Kb.

Hope this helps others with the same sort of trouble.

ealbert
  • 91
  • 1
  • 3