- Handle data uploaded from client using
multipart/form-data
Content-Type. Previously, to handlemultipart/form-data
inWEB API 2
, there is just only one possible solution mentioned in this topic. - This library helps developers to serialize information into view model in
ASP.NET WEB API 2
just like ASP.Net does (please refer this tutorial). - Developers can re-use WEB API 2 Data annotation classes without repeating themselves doing manual data validation.
I. Installation:
-
You can choose one of following source to install nuget package into your project:
II. Formatter registration:
-
ASP.Net Framework
-
Please select one of the following implementation below for
WebApiConfig.cs
orStartup.cs
:-
WITHOUT dependency injection
public static void Register(HttpConfiguration config) { // Web API configuration and services // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( "DefaultApi", "api/{controller}/{id}", new {id = RouteParameter.Optional} ); config.Formatters.Add(new MultipartFormDataFormatter()); }
-
WITH dependency injection
public static void Register(HttpConfiguration config) { // Web API configuration and services // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( "DefaultApi", "api/{controller}/{id}", new {id = RouteParameter.Optional} ); var containerBuilder = new ContainerBuilder(); // Register formatter as a single instance in the system. containerBuilder.RegisterType<MultipartFormDataFormatter>() .InstancePerLifetimeScope(); var container = containerBuilder.Build(); config.DependencyResolver = new AutofacWebApiDependencyResolver(container); // Register multipart/form-data formatter. var instance = (MultipartFormDataFormatter) config.DependencyResolver.GetService(typeof(MultipartFormDataFormatter)); config.Formatters.Add(instance); }
-
-
-
ASP.Net Core (>= 2.2)
public class Startup { public Startup(IConfiguration configuration) { //... } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers(options => { //.. options.InputFormatters.Add(new MultipartFormDataFormatter()); }); } }
III. API Controller
-
ASP.NET Framework
[RoutePrefix("api/account")] public class ApiAccountController : ApiController { [Route("register")] [HttpPost] public HttpResponseMessage Register(AccountRegistrationViewModel parameters) { if (parameters == null) { parameters = new AccountRegistrationViewModel(); Validate(parameters); } if (!ModelState.IsValid) { return Request.CreateResponse(HttpStatusCode.BadRequest); } return Request.CreateResponse(HttpStatusCode.OK); } }
-
ASP.NET Core
[Route("api/upload")] [ApiController] public class ApiUploadController : Controller, IUploadController { /// <summary> /// Upload attachment to service end-point. /// </summary> /// <returns></returns> [HttpPost("")] public IActionResult BasicUpload([FromBody] UploadRequestViewModel model) { if (model == null) { model = new UploadRequestViewModel(); TryValidateModel(model); } if (!ModelState.IsValid) return BadRequest(ModelState); return Ok(new UploadResponseViewModel(model)); } }
- Start posting a multipart/form-data to your WEB API project and enjoy.
- NOTE: In ASP.NET Core, you have to mark your controller with [ApiController] in order to make this plugin works. Otherwise, it doesn't.
- To specify a parameter to be a file in a
ViewModel
class, please useHttpFile
orHttpFileBase
class.HttpFile
andHttpFileBase
are treated as HttpPostedFileBase class inASP.NET MVC
. - Below is the example of
HttpFile
andHttpFileBase
usage:
public class Category
{
public int Id { get; set; }
public List<Photo> Photos { get; set; }
}
public class AccountRegistrationViewModel
{
/// <summary>
/// Account owner.
/// </summary>
[Required]
public Owner Owner { get; set; }
/// <summary>
/// User age.
/// </summary>
[Required]
public int Age { get; set; }
/// <summary>
/// Account photo.
/// </summary>
[Required]
public HttpFile Photo { get; set; }
[Required]
public List<HttpFileBase> Photos { get; set; }
}
(Previously IMultiPartFormDataModelBinderService
)
-
In version2.0.0
, this plugin usesIMultiPartFormDataModelBinderService
to help developer overridemultpart-form/data
parameter serialization. -
From version
3.0.0
, this plugin usesIModelBinderService
to serialize data read from MultipartFormDataContent stream. -
This helps developers to initialize Data type that has not been recoginized by ASP.NET Web API (Mostly about custom classes or data type).
-
For data that should be skipped analyzing, please throw
UnhandledParameterException
inBuildModelAsync
function. -
Below is an example of
IModelBinderService
implementation that can be found in project source code.
public class GuidModelBinderService : IModelBinderService
{
#region Methods
public Task<object> BuildModelAsync(Type propertyType, object value,
CancellationToken cancellationToken = default(CancellationToken))
{
// Get property type.
var underlyingType = Nullable.GetUnderlyingType(propertyType);
// Property is GUID.
if (propertyType == typeof(Guid) && Guid.TryParse(value.ToString(), out var guid))
return Task.FromResult((object) guid);
if (underlyingType == typeof(Guid))
{
if (Guid.TryParse(value?.ToString(), out guid))
return Task.FromResult((object)guid);
return Task.FromResult(default(object));
}
throw new UnhandledParameterException();
}
#endregion
}
-
IModelBinderService
can be registered in DI Frameworks such as (AutoFac, Ninject, ...). This requiresMultipartFormDataFormatter
to be registered in DI Frameworks also. Example:// ... containerBuilder.RegisterType<GuidModelBinderService>() .AsImplementedInterfaces() .SingleInstance(); // ...
-
IModelBinderService
can be registered DIRECTLY while initializingMultipartFormDataFormatter
object.config.Formatters.Add(new MultipartFormDataFormatter( new IModelBinderService[] { new GuidModelBinderService() }));
-
BY DEFAULT,
MultipartFormDataFormatter
is registered with a list of default services WHEN NO ModelBinderService is specified:
public MultipartFormDataFormatter(IEnumerable<IModelBinderService> modelBinderServices = null)
{
_modelBinderServices = modelBinderServices?.ToArray();
if (_modelBinderServices == null || _modelBinderServices.Length < 1)
{
_modelBinderServices = new IModelBinderService[]
{
new DefaultMultiPartFormDataModelBinderService(),
new GuidModelBinderService(),
new EnumModelBinderService(),
new HttpFileModelBinderService()
};
}
// Register multipart/form-data as the supported media type.
SupportedMediaTypes.Add(new MediaTypeHeaderValue(SupportedMediaType));
}
- You can refer to this project for further information of how to implement ASP Web API 2 project with this plugin.
-
Currently, this formatter cannot deal with interfaces such as:
IAccount
,IList
,IEnumerable
, ... To use it with a collection, please specify :List
,Enumerable
, .... -
For a collection, please use
List
,Enumerable
, ... instead of[] (array)
. This feature will be updated later.
-
3.0.0:
-
ASP.Net Core supported.
-
Provided
HttpFile
andHttpFileBase
support (previouslyHttpFile
only). HttpFileBase is recommended since it reads data using stream instead of convert data into bytes array. Please refer discussion for further information.- (Thank Driedas for his pull request)
-
Replaced
IMultiPartFormDataModelBinderServicewithIModelBinderService
for custom data serialization. Therefore,IModelBinderService
classes can be registered to handle custom data that plugin cannot handled.
-
-
2.1.0:
-
Merge pull request 6 created by everfrown which supported extended data types binding such as:
- enum (string or number)
- guid
- and nullable value types
-
Removed ApiMultipartFormDataFormatter.cs class. Please use MultipartFormDataFormatter.cs instead.
-
-
1.0.4:
- Fixed bug #3 : Bad request while trying casting string to GUID
- Added
IMultiPartFormDataModelBinderService
for intercepting model serialization. ApiMultipartFormDataFormatter
now is obsoleted. An exception is thrown if this class is used. Please usingMultipartFormDataFormatter
instead.FindContentDispositionParametersInterceptor
: Allow developer to custmize how parameter will be serialized. Please take a look at MultipartFormDataFormatter.cs
-
1.0.3:
- Prevent dependencies such as
NewtonSoft.Json
, ... from being compiled and included in release nuget package. Therefore, the package size is smaller. - Prevent dependencies from being removed when
ApiMultipartFormDataFormatter
nuget is uninstalled.
- Prevent dependencies such as
-
1.0.1:
- Fixed issue about list serialization, mentioned here
-
1.0.2:
- Incorrect release version. Please skip this.
-
1.0.0:
- Initial release.
- While sending the request, please make sure not to attach
Content-Type
in header or makeContent-Type
beNULL
ApiMultipartFormDataFormatter
is obsolete and will be removed in version after 1.0.3. Please useMultipartFormDataFormatter
instead.