这是对问题Custom form data with multiple files to Web API controller和Filling Parameter with Attribute [FromForm] with Fiddler的跟进,这两个问题都是通过引用A MediaTypeFormatter for WebApi for multipart/form-data including file uploads来回答的。
基本上这与Tocana之前在最后一个链接中提出的问题相同。
我复制了后者的代码,注册了媒体类型格式化程序并尝试使用fiddler,但是当它进入UploadController.Post(UploadRequestViewModel model)
时,模型是实例化的,但其属性都等于null
。
我调试了它,发现FormMultipartEncodedMediaTypeFormatter.BindToModel(IDictionary<string, object> data, Type type, IFormatterLogger formatterLogger)
被一个正确的data
字典调用,但从那时起,我无法从尾巴开始。用于绑定模型的绑定器是CompositeModelBinder
,但是这个绑定是否正确我无法分辨。
fiddler请求如下所示:
标题
Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
User-Agent: Fiddler
Host: localhost:49473
Content-Length: 13192
体
---------------------------acebdf13572468
Content-Disposition: form-data; name="SiteId"
Content-Type: text/plain
987654321
---------------------------acebdf13572468
Content-Disposition: form-data; name="StartDate"
Content-Type: text/plain
24.08.1979
---------------------------acebdf13572468
Content-Disposition: form-data; name="Zulu"; filename="ExifTest.tif"
Content-Type: image/tiff
<@INCLUDE *C:\...\ExifTest.tif*@>
---------------------------acebdf13572468--
我需要做些什么来正确初始化我的模型,即它的值不是null
?
修改
所有模型和控制器都是A MediaTypeFormatter for WebApi for multipart/form-data including file uploads的那些,即
型号:
public class UploadRequestViewModel
{
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
[Required]
public HttpPostedFileBase File { get; set; }
}
控制器:
[Route("UploadTest")]
[HttpPost]
public IHttpActionResult Post(UploadRequestViewModel model)
{
}
FormMultipartEncodedMediaTypeFormatter.BindToModel
private object BindToModel(IDictionary<string, object> data, Type type, IFormatterLogger formatterLogger)
{
if (data == null) throw new ArgumentNullException(nameof(data));
if (type == null) throw new ArgumentNullException(nameof(type));
using (var config = new HttpConfiguration())
{
// if there is a requiredMemberSelector set, use this one by replacing the validator provider
var validateRequiredMembers = RequiredMemberSelector != null && formatterLogger != null;
if (validateRequiredMembers)
{
config.Services.Replace(typeof(ModelValidatorProvider), new RequiredMemberModelValidatorProvider(RequiredMemberSelector));
}
// create a action context for model binding
var actionContext = new HttpActionContext
{
ControllerContext = new HttpControllerContext
{
Configuration = config,
ControllerDescriptor = new HttpControllerDescriptor
{
Configuration = config
}
}
};
// create model binder context
var valueProvider = new NameValuePairsValueProvider(data, CultureInfo.InvariantCulture);
var metadataProvider = actionContext.ControllerContext.Configuration.Services.GetModelMetadataProvider();
var metadata = metadataProvider.GetMetadataForType(null, type);
var modelBindingContext = new ModelBindingContext
{
ModelName = string.Empty,
FallbackToEmptyPrefix = false,
ModelMetadata = metadata,
ModelState = actionContext.ModelState,
ValueProvider = valueProvider
};
// bind model
var modelBinderProvider = new CompositeModelBinderProvider(config.Services.GetModelBinderProviders());
var binder = modelBinderProvider.GetBinder(config, type);
var haveResult = binder.BindModel(actionContext, modelBindingContext);
// log validation errors
if (formatterLogger != null)
{
foreach (var modelStatePair in actionContext.ModelState)
{
foreach (var modelError in modelStatePair.Value.Errors)
{
if (modelError.Exception != null)
{
formatterLogger.LogError(modelStatePair.Key, modelError.Exception);
}
else
{
formatterLogger.LogError(modelStatePair.Key, modelError.ErrorMessage);
}
}
}
}
return haveResult ? modelBindingContext.Model : GetDefaultValueForType(type);
}
}