ApiMultipartFormFormatter
ApiMultipartFormFormatter copied to clipboard
This formatter which is for handling parameters and file uploaded to Web API controller.
ApiMultipartFormDataFormatter
A. Description:
- Handle data uploaded from client using
multipart/form-dataContent-Type. Previously, to handlemultipart/form-datainWEB 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 2just 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.
B. Implementation:
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.csorStartup.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.
C. HttpFile or HttpFileBase usage:
- To specify a parameter to be a file in a
ViewModelclass, please useHttpFileorHttpFileBaseclass.HttpFileandHttpFileBaseare treated as HttpPostedFileBase class inASP.NET MVC. - Below is the example of
HttpFileandHttpFileBaseusage:
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; }
}
IV. Data serializer customization with IModelBinderService
(Previously IMultiPartFormDataModelBinderService)
-
~~In version
2.0.0, this plugin usesIMultiPartFormDataModelBinderServiceto help developer overridemultpart-form/dataparameter serialization.~~ -
From version
3.0.0, this plugin usesIModelBinderServiceto 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
UnhandledParameterExceptioninBuildModelAsyncfunction. -
Below is an example of
IModelBinderServiceimplementation 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
}
-
IModelBinderServicecan be registered in DI Frameworks such as (AutoFac, Ninject, ...). This requiresMultipartFormDataFormatterto be registered in DI Frameworks also. Example:// ... containerBuilder.RegisterType<GuidModelBinderService>() .AsImplementedInterfaces() .SingleInstance(); // ... -
IModelBinderServicecan be registered DIRECTLY while initializingMultipartFormDataFormatterobject.config.Formatters.Add(new MultipartFormDataFormatter( new IModelBinderService[] { new GuidModelBinderService() })); -
BY DEFAULT,
MultipartFormDataFormatteris 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));
}
VI. Examples:
- You can refer to this project for further information of how to implement ASP Web API 2 project with this plugin.
VII. Limitation:
-
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.
VIII. Change logs:
-
3.0.0:
-
ASP.Net Core supported.
-
Provided
HttpFileandHttpFileBasesupport (previouslyHttpFileonly). 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 ~~IMultiPartFormDataModelBinderService~~ with
IModelBinderServicefor custom data serialization. Therefore,IModelBinderServiceclasses 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
IMultiPartFormDataModelBinderServicefor intercepting model serialization. ApiMultipartFormDataFormatternow is obsoleted. An exception is thrown if this class is used. Please usingMultipartFormDataFormatterinstead.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
ApiMultipartFormDataFormatternuget 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.
IMPORTANT NOTE:
- While sending the request, please make sure not to attach
Content-Typein header or makeContent-TypebeNULL ApiMultipartFormDataFormatteris obsolete and will be removed in version after 1.0.3. Please useMultipartFormDataFormatterinstead.