Click here to Skip to main content
15,917,997 members
Articles / Web Development / ASP.NET
Tip/Trick

ASP.NET WebApi: MultipartDataMediaFormatter

Rate me:
Please Sign up or sign in to vote.
4.93/5 (18 votes)
5 Jun 2017MIT2 min read 150.1K   2.2K   25   25
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:

C#
Install-Package MultipartDataMediaFormatter.V2

Add it to WebApi formatters collection:

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

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

If WebApi is self-hosted:

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

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

C#
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:

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

Bind custom model example:

C#
//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.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer (Senior)
Ukraine Ukraine
.net developer

Comments and Discussions

 
QuestionGetting exception "at MultipartDataMediaFormatter.Converters.HttpContentToFormDataConverter" Pin
Member 1261249828-Sep-22 11:59
Member 1261249828-Sep-22 11:59 
GeneralMy vote of 5 Pin
Member 151821421-Sep-17 18:36
Member 151821421-Sep-17 18:36 
QuestionCan you show how to append nested objects to formsData? Pin
Member 1192641222-Aug-16 4:21
Member 1192641222-Aug-16 4:21 
AnswerRe: Can you show how to append nested objects to formsData? Pin
Alexander Kozlovskiy22-Aug-16 6:29
Alexander Kozlovskiy22-Aug-16 6:29 
GeneralRe: Can you show how to append nested objects to formsData? Pin
Member 1192641222-Aug-16 20:51
Member 1192641222-Aug-16 20:51 
QuestionUsing it with AngularJS Pin
Member 1131820029-May-15 1:33
Member 1131820029-May-15 1:33 
AnswerRe: Using it with AngularJS Pin
Alexander Kozlovskiy29-May-15 4:25
Alexander Kozlovskiy29-May-15 4:25 
GeneralRe: Using it with AngularJS Pin
Member 1131820029-May-15 4:50
Member 1131820029-May-15 4:50 
SuggestionMultiple File Upload Supported Now! Pin
Jener Garcia Menezes6-May-15 4:54
Jener Garcia Menezes6-May-15 4:54 
GeneralRe: Multiple File Upload Supported Now! Pin
Alexander Kozlovskiy7-May-15 4:23
Alexander Kozlovskiy7-May-15 4:23 
QuestionThanks Pin
Valdis Iljuconoks10-Mar-15 22:57
Valdis Iljuconoks10-Mar-15 22:57 
AnswerRe: Thanks Pin
Alexander Kozlovskiy23-Mar-15 23:57
Alexander Kozlovskiy23-Mar-15 23:57 
QuestionformData empty Pin
Member 1101580615-Aug-14 18:50
Member 1101580615-Aug-14 18:50 
AnswerRe: formData empty Pin
Alexander Kozlovskiy15-Aug-14 19:50
Alexander Kozlovskiy15-Aug-14 19:50 
GeneralRe: formData empty Pin
Member 1101580618-Aug-14 3:49
Member 1101580618-Aug-14 3:49 
GeneralRe: formData empty Pin
Alexander Kozlovskiy18-Aug-14 7:12
Alexander Kozlovskiy18-Aug-14 7:12 
QuestionNuGet Pin
Rory Primrose8-May-14 13:12
Rory Primrose8-May-14 13:12 
AnswerRe: NuGet Pin
Alexander Kozlovskiy8-May-14 21:30
Alexander Kozlovskiy8-May-14 21:30 
GeneralMy vote of 5 Pin
Volynsky Alex4-Apr-14 11:34
professionalVolynsky Alex4-Apr-14 11:34 
GeneralRe: My vote of 5 Pin
Alexander Kozlovskiy4-Apr-14 23:29
Alexander Kozlovskiy4-Apr-14 23:29 
GeneralRe: My vote of 5 Pin
Volynsky Alex5-Apr-14 1:55
professionalVolynsky Alex5-Apr-14 1:55 
SuggestionUse MimeMultipartContent Pin
rongchaua1-Mar-14 18:52
rongchaua1-Mar-14 18:52 
GeneralRe: Use MimeMultipartContent Pin
mrwizzard5-Jun-14 11:30
mrwizzard5-Jun-14 11:30 
SuggestionExcellent! Pin
Axel Zarate4-Feb-14 7:33
Axel Zarate4-Feb-14 7:33 
GeneralRe: Excellent! Pin
Alexander Kozlovskiy1-Apr-14 3:01
Alexander Kozlovskiy1-Apr-14 3:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.