Відповідь uadrive зайняла мене частину шляху, але все-таки були певні прогалини. Без будь-яких даних на вході в new NameValueCollectionValueProvider()
, прив’язка моделі прив’яже контролер до порожньої моделі, а не до model
об’єкта.
Це чудово - просто серіалізуйте свою модель як NameValueCollection
, а потім передайте її в NameValueCollectionValueProvider
конструктор. Ну, не зовсім. На жаль, це не спрацювало у моєму випадку, оскільки моя модель містить колекцію, і NameValueCollectionValueProvider
вона не дуже добре грає з колекціями.
Однак JsonValueProviderFactory
тут на допомогу приходить. Він може використовуватися до тих DefaultModelBinder
пір, поки ви вкажете тип вмісту "application/json
"і передасте ваш серіалізований об'єкт JSON у вхідний потік вашого запиту (Будь ласка, зверніть увагу, оскільки цей вхідний потік є потоком пам'яті, його можна залишити без використання, як пам'ять потік не тримається на жодних зовнішніх ресурсах):
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;
}