65.9K
CodeProject is changing. Read more.
Home

ASP.NET WebApi: MultipartDataMediaFormatter

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (18 votes)

Nov 22, 2013

MIT

2 min read

viewsIcon

152300

downloadIcon

2242

Used for binding custom types (including files) when sending and receiving multipart encoded form data

Introduction

This is a solution for automatic binding action parameters of custom types (including files) encoded as multipart/form-data. It works similar to ASP.NET MVC binding. This media type formatter can be used also for sending objects (using HttpClient) with automatic serialization to multipart/form-data.

This formatter can process:

  • custom non enumerable classes (deeply nested classes supported)
  • all simple types that can be converted from/to string (using TypeConverter)
  • files (MultipartDataMediaFormatter.Infrastructure.HttpFile or byte[])
  • generic arrays
  • generic lists
  • generic dictionaries

Using the Code

Install formatter from Nuget:

Install-Package MultipartDataMediaFormatter.V2

Add it to WebApi formatters collection:

If WebApi is hosted on IIS (on Application Start):

GlobalConfiguration.Configuration.Formatters.Add
(new FormMultipartEncodedMediaTypeFormatter(new MultipartFormatterSettings()));    

If WebApi is self-hosted:

new HttpSelfHostConfiguration(<url>).Formatters.Add
(new FormMultipartEncodedMediaTypeFormatter(new MultipartFormatterSettings()));      

Using formatter for sending objects (example from test project):

private ApiResult<T> PostModel<T>(T model, string url)
{
 var mediaTypeFormatter = new FormMultipartEncodedMediaTypeFormatter(new MultipartFormatterSettings()
    {
        SerializeByteArrayAsHttpFile = true,
        CultureInfo = CultureInfo.CurrentCulture,
        ValidateNonNullableMissedProperty = true
    });
 using (new WebApiHttpServer(BaseApiAddress, mediaTypeFormatter))
 using (var client = CreateHttpClient(BaseApiAddress))
 using (HttpResponseMessage response = client.PostAsync(url, model, mediaTypeFormatter).Result)
 {
  if (response.StatusCode != HttpStatusCode.OK)
  {
    var err = response.Content.ReadAsStringAsync().Result;
    Assert.Fail(err);
  }
  
  var resultModel = response.Content.ReadAsAsync<ApiResult<T>>(new[] { mediaTypeFormatter }).Result;
  return resultModel;
  }
}

You can use MultipartDataMediaFormatter.Infrastructure.FormData class to access raw http data:

[HttpPost]
public void PostFileBindRawFormData(MultipartDataMediaFormatter.Infrastructure.FormData formData)
{
      HttpFile file;
      formData.TryGetValue(<key>, out file);
} 

Bind custom model example:

//model example
public class PersonModel
{
    public string FirstName {get; set;}
    public string LastName {get; set;}
    public DateTime? BirthDate {get; set;}
    public HttpFile AvatarImage {get; set;}
    public List<HttpFile> Attachments {get; set;}
    public List<PersonModel> ConnectedPersons {get; set;}
    public PersonModel Creator {get; set;}
    public List<string> Attributes {get; set;}
}

//api controller example
[HttpPost]
public void PostPerson(PersonModel model)
{
   //do something with the model
}

/*
Client http form keys:
* FirstName
* LastName
* BirthDate
* AvatarImage

* Attachments[0]
* Attachments[1]
* ... other Attachments[0...n]

* ConnectedPersons[0].FirstName
* ConnectedPersons[0].LastName
* ... other properties for ConnectedPersons[0] property

* Creator.FirstName
* Creator.LastName
* ... other properties for Creator property

* Attributes[0]
* Attributes[1]
* ... other Attributes[0...n]
 or you can use not indexed names for simple types:
 * Attributes
 * Attributes
 * ... other Attributes
*/

 

History

Version 2.0.0 (2017-05-27)

Version 1.0.2 (2016-08-12)

  • Parsing lists of simple types and files with not indexed naming scheme (keys have same names like "propName" or "propName[]")
  • Parsing values "on" and "off" for boolean properties
  • Binding HttpFile from http request as byte[] if model has such property
  • Added class MultipartDataMediaFormatter.Infrastructure.MultipartFormatterSettings to control:
    • CultureInfo
    • Serializing byte[] as HttpFile when sending data
    • Validating non nullable value types properties if there are no appropriate keys in http request

Version 1.0.1 (2014-04-03)

  • Fixed a bug that caused Exception (No MediaTypeFormatter is available to read an object of type <type name>) when posted data use multipart boundary different from used inside formatter code
  • Fixed a bug that caused error when binding model with recursive properties

Version 1.0 (2013-11-22)

  • First release

Notes

For successfully running tests from the test project, you should run Visual Studio with administrator rights because of using Self Hosted WebApi Server System.Web.Http.SelfHost.HttpSelfHostServer.