Ответ uadrive взял меня на часть пути, но все еще были некоторые пробелы. Без каких-либо данных во входных данных new NameValueCollectionValueProvider()связыватель модели привяжет контроллер к пустой модели, а не к modelобъекту.
Это нормально - просто сериализуйте свою модель как объект NameValueCollection, а затем передайте его в NameValueCollectionValueProviderконструктор. Не совсем так. К сожалению, в моем случае это не сработало, потому что моя модель содержит коллекцию, а NameValueCollectionValueProviderона плохо работает с коллекциями.
Однако JsonValueProviderFactoryздесь на помощь приходит. Его можно использовать до тех DefaultModelBinderпор, пока вы укажете тип содержимого "application/json"и передадите свой сериализованный объект JSON во входной поток вашего запроса (обратите внимание, поскольку этот входной поток является потоком памяти, можно оставить его нераспределенным, как память stream не привязан ни к каким внешним ресурсам):
protected void BindModel<TModel>(Controller controller, TModel viewModel)
{
var controllerContext = SetUpControllerContext(controller, viewModel);
var bindingContext = new ModelBindingContext
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => viewModel, typeof(TModel)),
ValueProvider = new JsonValueProviderFactory().GetValueProvider(controllerContext)
};
new DefaultModelBinder().BindModel(controller.ControllerContext, bindingContext);
controller.ModelState.Clear();
controller.ModelState.Merge(bindingContext.ModelState);
}
private static ControllerContext SetUpControllerContext<TModel>(Controller controller, TModel viewModel)
{
var controllerContext = A.Fake<ControllerContext>();
controller.ControllerContext = controllerContext;
var json = new JavaScriptSerializer().Serialize(viewModel);
A.CallTo(() => controllerContext.Controller).Returns(controller);
A.CallTo(() => controllerContext.HttpContext.Request.InputStream).Returns(new MemoryStream(Encoding.UTF8.GetBytes(json)));
A.CallTo(() => controllerContext.HttpContext.Request.ContentType).Returns("application/json");
return controllerContext;
}