Created
June 19, 2017 11:16
-
-
Save quexy/2f977be255074835607a3deca2b28c9c to your computer and use it in GitHub Desktop.
WebAPI 'multipart/form-data' input formatter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Net.Http; | |
using System.Net.Http.Formatting; | |
using System.Net.Http.Headers; | |
using System.Reflection; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace WebApi.Formatters | |
{ | |
public class MultipartFormDataMediaTypeFormatter : MediaTypeFormatter | |
{ | |
private const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty; | |
public MultipartFormDataMediaTypeFormatter() | |
{ | |
SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-data")); | |
} | |
public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) | |
{ | |
return ReadFromStreamAsync(type, readStream, content, formatterLogger, CancellationToken.None); | |
} | |
public override async Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger, CancellationToken cancellationToken) | |
{ | |
cancellationToken.ThrowIfCancellationRequested(); | |
try | |
{ | |
var obj = Activator.CreateInstance(type); | |
var parts = await content.ReadAsMultipartAsync(cancellationToken); | |
foreach (var item in parts.Contents) | |
{ | |
cancellationToken.ThrowIfCancellationRequested(); | |
var partName = item.Headers.ContentDisposition.Name; | |
if (string.IsNullOrEmpty(partName)) | |
{ | |
if (parts.Contents.Count == 1) | |
{ | |
return await item.ReadAsAsync(type, cancellationToken); | |
} | |
else // multiple parts, no name -> error | |
{ | |
formatterLogger.LogError("", "The content part does not have a name"); | |
} | |
} | |
else // part defined its destination | |
{ | |
var property = obj.GetType().GetProperty(partName, flags); | |
if (property == null) | |
{ | |
formatterLogger.LogError(partName, "The model does not have this property"); | |
} | |
else // we found the property for the name | |
{ | |
var part = await item.ReadAsAsync(property.PropertyType, cancellationToken); | |
try { property.SetValue(obj, part); } | |
catch (Exception ex) { formatterLogger.LogError(partName, ex); } | |
} | |
} | |
} | |
return obj; | |
} | |
catch (OperationCanceledException) | |
{ | |
throw; | |
} | |
catch (Exception ex) | |
{ | |
formatterLogger.LogError("", ex); | |
throw; | |
} | |
} | |
// we can read but cannot write: it would be a much greater project | |
public override bool CanReadType(Type type) { return true; } | |
public override bool CanWriteType(Type type) { return false; } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment