Testing MultipartFormDataContent

Topics: ASP.NET Web API
May 2, 2012 at 9:32 AM

Hi There.

I have an ASP.net MVC 4 (beta) WebApi that looks something like this:

    public void Post()
   
{
       
if (!Request.Content.IsMimeMultipartContent("form-data"))
       
{
           
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
       
}

       
IEnumerable<HttpContent> parts = Request.Content.ReadAsMultipartAsync().Result;

       
// Rest of code here.
   
}

I am trying to unit test this code, but can't work out how to do it. Am I on the right track here?

    [TestMethod]
   
public void Post_Test()
   
{
       
MultipartFormDataContent content = new MultipartFormDataContent();
        content
.Add(new StringContent("bar"), "foo");

       
this.controller.Request = new HttpRequestMessage();
       
this.controller.Request.Content = content;
       
this.controller.Post();
   
}

This code is throwing the following exception:

System.AggregateException: One or more errors occurred. ---> System.IO.IOException: Unexpected end of MIME multipart stream. MIME multipart message is not complete. at System.Net.Http.MimeMultipartBodyPartParser.d__0.MoveNext() at System.Net.Http.HttpContentMultipartExtensions.MoveNextPart(MultipartAsyncContext context) at System.Net.Http.HttpContentMultipartExtensions.MultipartReadAsyncComplete(IAsyncResult result) at System.Net.Http.HttpContentMultipartExtensions.OnMultipartReadAsyncComplete(IAsyncResult result)

Am I on the right track? How do I mark the end of the MultipartFormDataContent?

May 2, 2012 at 10:01 PM

We have looked into this and while it does repro using the beta bits we have confirmed that the issue has been resolved in the latest bits. You can either try out the latest nightly build (see instructions here [1]) or wait for our next drop.

Hope this helps and thanks for the report!

Henrik

[1] http://blogs.msdn.com/b/henrikn/archive/2012/04/29/using-nightly-nuget-packages-with-asp-net-web-stack.aspx

May 4, 2012 at 11:28 AM

Thanks Henrik! There are a few people involved with this project, so will probably have to wait for the next drop to give it a go, but good to know it's fixed.

Aug 7, 2012 at 5:11 PM

Hi Henrik,

 

I'm experiencing the same problem with the ASP.NET MVC4 version that ships with VS 2012 Ultimate RC. It's really annoying because I'm using Uploadify on the client side which means I can only make changes to the server code.

I'm not really comfortable with the nightly builds. Is there anything I can do to work around it?

Sep 5, 2012 at 11:57 PM

Hancock,

I hope you find the issue to have been resolved with the RTM bits.

Henrik

Sep 6, 2012 at 10:25 AM

Unfortunately that was not the case. I gave up on MVC4 and I'm sticking with MVC3 which does the job.

The issue is really simple but extremely hard to fix. The problem is that Uploadify does not add an "\r\n" at the end of the MultiPartForm message which causes the MVC4 parser to crash and throw an exception. I've tested this with Fiddler. If I add the missing "\r\n" it works. 

It's a shame that MVC4 does this because according to the RFC an "\r\n" at the end may or may not occur so the parser ought to be able to treat both cases.

Anyway, thanks for taking the time to answer.

 

hancock

Aug 13, 2013 at 2:49 PM
This is a bit late, but I fixed the issue in MVC4 by adding a name attribute to my input box.

<input type="file" id="fileInput" name="fileInput"/>

Hope this helps someone!
Oct 28, 2013 at 7:29 PM
So am I to understand that this issue is not going to be fixed then?
Coordinator
Oct 28, 2013 at 8:39 PM
Hi InternetSavage,

Is this happening in Web API 2, which was just released a couple of weeks ago? You can use NuGet to update your package references from Web API 1 (came out with MVC4) to Web API 2 (came out with MVC5).

If this issue still happens in Web API 2 then please let us know so that we can re-investigate.

Thanks,
Eilon
Oct 29, 2013 at 6:13 AM
I was running Web API 2 with MVC 4 so I upgraded my site to MVC 5 but I'm still getting this exception.

System.IO.IOException
Unexpected end of MIME multipart stream. MIME multipart message is not complete.

Below I've included an example request that is being generated by Uploadify. In the past I've used Uploadify to upload images via MVC controller actions with no issues at all.


POST http://localhost:49977/api/media/upload?requireUploadifySessionSync=true&sessionId=vy1q12jn25yz3ducb5uab0ec&securityToken=3B02367859F9452D839938971F3932FDB2570ACBD086D8D15DB7A4F6C8E32074F430C471F227EE0E6842FFA4A73C865B960AEF1702F011B0DCB9C17D92B31851D38E1D0634D5815B36B7620D27832A84E433C0B7527D03F1923B452778E24FECE6B6ECEF9B38B4B669BA977B1C3EDA11897CB4065F8272B927FBD98910F94295 HTTP/1.1
Accept: text/*
Content-Type: multipart/form-data; boundary=----------gL6ae0Ef1ae0cH2Ef1KM7Ij5Ij5cH2
User-Agent: Shockwave Flash
Host: localhost:49977
Content-Length: 472
DNT: 1
Connection: Keep-Alive
Pragma: no-cache
Cookie: .ASPXAUTH=3B02367859F9452D839938971F3932FDB2570ACBD086D8D15DB7A4F6C8E32074F430C471F227EE0E6842FFA4A73C865B960AEF1702F011B0DCB9C17D92B31851D38E1D0634D5815B36B7620D27832A84E433C0B7527D03F1923B452778E24FECE6B6ECEF9B38B4B669BA977B1C3EDA11897CB4065F8272B927FBD98910F94295; ASP.NET_SessionId=vy1q12jn25yz3ducb5uab0ec

------------gL6ae0Ef1ae0cH2Ef1KM7Ij5Ij5cH2
Content-Disposition: form-data; name="Filename"

_test.txt
------------gL6ae0Ef1ae0cH2Ef1KM7Ij5Ij5cH2
Content-Disposition: form-data; name="Filedata"; filename="_test.txt"
Content-Type: application/octet-stream

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
------------gL6ae0Ef1ae0cH2Ef1KM7Ij5Ij5cH2
Content-Disposition: form-data; name="Upload"

Submit Query
------------gL6ae0Ef1ae0cH2Ef1KM7Ij5Ij5cH2--
Nov 19, 2013 at 7:35 PM
Hi, I have the exact same problem. Any recent info?
Nov 19, 2013 at 9:03 PM
Haven't heard anything yet, I've had to go back to using a MVC controller action for uploads.
Nov 19, 2013 at 9:07 PM
I don't think they even made a serious attempt to fix it but maybe I'm wrong. The way I resolved my issue was to migrate everything to ServiceStack. If you have a large project this might not work for you though.
Coordinator
Nov 19, 2013 at 9:32 PM
Edited Nov 19, 2013 at 9:49 PM
@hancock/@InternetSavage - From one of the responses above by @gregsipes looks like by adding the name attribute the issue is resolved, is it not the case for you?

Edit - After talking to Kiran, seems that there are two issues at play. On ehas to do with CRLF ending of the part, and one to do with Chrome. Can you guys please confirm what this comment does for you?

We are going to open a bug to track this, and will update this thread once we have it ready. That will be the place to track progress on this issue.

Thanks,
Yishai
Nov 19, 2013 at 10:01 PM
Assuming the trick is to make the name attribute the same value as the id attribute then no it doesn't seem to make any difference for me when I try it. I've actually seen other public APIs, like YouTube, choke on multipart form uploads with the absence of "\r\n" at the end of a message, would actually be nice if Flash would just append "\r\n" at the end of the messages.
Nov 20, 2013 at 12:50 PM
If it helps you MS guys, I can't push any packages with NuGet to my custom repo. It was working well before I moved from WebAPI and EF5 to WebAPI2 and EF6 (I can't be 100% sure that is the reason why it stopped working, though, even though I haven't touched the code itself).

I use nuget.exe push name-of-the-package apiKey -s "where-to-put-it"

The address, name of the package and ApiKey are 100% correct.

The code is as follows:
public async Task<HttpResponseMessage> Put()
{
    CheckApiKey();

    if (!Request.Content.IsMimeMultipartContent("form-data"))
    {
        throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.UnsupportedMediaType));
    }

        var package = await CreatePackageAsync(Request.Content);

/* Rest of the code */
}
private async Task<IPackage> CreatePackageAsync(HttpContent content)
{
    using (var stream = new MemoryStream())
    {
        var streamProvider = new MemoryDataStreamProvider(stream);
        try
        {
            await content.ReadAsMultipartAsync(streamProvider); // this is where it bugs out
        }
        catch (Exception ex)
        {
            if (ex.Message.Contains("MIME multipart message is not complete"))
            {
                //do nothing, this is bug in Web API (http://aspnetwebstack.codeplex.com/discussions/354215)
            }
            else
            {
                throw;
            }
        }

        stream.Position = 0;
        return new ZipPackage(stream);
    }
}
And MemoryDataStreamProvider.cs:
public class MemoryDataStreamProvider : MultipartStreamProvider
{
    private Stream _stream;

    public MemoryDataStreamProvider(Stream stream)
    {
        _stream = stream;
    }

    public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
    {
        return _stream; // this is where the stream is already disposed of, according to VS Debugger
    }
}
The code runs well until it hits the ReadAsMultipart... part. It goes in it, then does something internal and when it hits the GetStream() method, the HttpContent is already disposed of, which ultimately also closes the stream.

There has always been the "MIME multipart is not complete" exception, but it at least worked before WebAPI2 after catching it. Now it doesn't. :(
Nov 25, 2013 at 11:50 AM
Sigh, just hit this too...
Coordinator
Nov 25, 2013 at 4:28 PM
Thanks everyone for reporting this and keeping the discussion alive.

Here are the bugs tracking the above issues:
https://aspnetwebstack.codeplex.com/workitem/1433
https://aspnetwebstack.codeplex.com/workitem/1444

1444 is already checked in the nightly packages - You can go ahead and verify that scenario at https://www.myget.org/gallery/aspnetwebstacknightly

We are still actively working on 1433.
Nov 25, 2013 at 4:52 PM
Edited Nov 25, 2013 at 4:53 PM
Thank you for your reply! Unfortunatelly, even after updating to the latest nightly build, the issue still remains the same - nothing has changed in its nature here.

I, however, believe, it might actually be caused by 1433, so we'll see after that is done. Any ETA, please?
Coordinator
Nov 25, 2013 at 5:06 PM
@Berzeger

We are actively coding/reviewing/testing. As soon as it's ready we will get it in. This could be as early as this week if all goes well.
Nov 25, 2013 at 5:08 PM
Great, thank you!
Nov 26, 2013 at 4:15 PM
The 20131126 nightly build does no longer throw the MIME not complete exception and it also doesn't dispose of the stream anymore. Thank you, great work! :)
Developer
Nov 26, 2013 at 5:05 PM
Thanks Berzeger for the quick verification.

@hancock, @InternetSavage : Now that this bug is fixed, could you please try our latest nightly builds to verify that this scenario is fixed for you guys too. We have already verified with Uploadify tool, but wondering if you are using any other tools/technologies that we are not aware of and would like to have a quick verification with them too. Thanks in advance.
Nov 26, 2013 at 6:29 PM
Yes, I can confirm that this fixes the bug, I am using Uploadify as well. When can we expect the next official release on NuGet?
Coordinator
Nov 26, 2013 at 7:32 PM
We will push out a release candidate in December and then an official release early next year.

Daniel Roth