Monday, July 08, 2013

Simplest Example of Posting File + Object to ASP.NET Web API

I searched through quite a few samples of posting multipart (I need to post a file and a custom object as with a form using Web API Client Libraries for 4.0) data to an ASP.NET Web API 4 service.  I couldn't get MultipartFormDataStreamProvider.FileData to populate on the server.  All the examples I looked at were really complicated (even current ones).

It turns out I was simply calling the wrong overload of MultipartFormDataContent.Add (see comment in client portion below).

Client:

var client = new HttpClient() ;
var formData = new MultipartFormDataContent();
/// FileContent code from stackoverflow.com/questions/17497584/cant-post-a-file-to-asp-net-web-api-from-httpclient
formData.Add( new FileContent( @"C:\temp\killme.xml" ), "name_not_used", "killme.xml" );  // third param causes provider.FileData on server to be populated.
formData.Add( new ObjectContent<MyCustomObject>( new MyCustomObject{ Path=@"C:\temp\killme.xml" }, new JsonMediaTypeFormatter() ), "options" );
client.PostAsync( "http://localhost:52800/api/Import", formData ).ContinueWith( ( task ) =>
{
    Console.WriteLine( task.Result.StatusCode.ToString() );
    client.Dispose();
} );

Server:

public HttpResponseMessage Post()
{
    if ( Request.Content.IsMimeMultipartContent() )
    {
        string root = HttpContext.Current.Server.MapPath( "~/App_Data" );  // This call can't be in async portion.
        var provider = new MultipartFormDataStreamProvider( root );

        try
        {
            Request.Content.ReadAsMultipartAsync( provider ).ContinueWith( task =>
            {
                var options = JsonConvert.DeserializeObject<MyCustomObject>( provider.FormData["options"] );
                if ( !task.IsFaulted )
                {
                    foreach ( MultipartFileData file in provider.FileData )                    {
                        Debug.Print( file.Headers.ContentDisposition.FileName );   // file name parameter to formData.Add back on client.
                        Debug.Print( "Server file path: " + file.LocalFileName );  // posted file automatically streamed to path specified by root var above.
                    }
                }
            } );

        }
        catch ( Exception e )
        {
            ;  // TBD
        }
        return new HttpResponseMessage( HttpStatusCode.Accepted );
    }
    else
    {
        return new HttpResponseMessage( HttpStatusCode.BadRequest );
    }
}

No comments: