我有一个没有参数的操作方法。
QueryString
集合包含我的所有值。QueryString
的键与我的视图模型属性匹配。
var queryStringValueProvider = new QueryStringValueProvider(ControllerContext);
var providerResult = queryStringValueProvider.GetValue(ValidationKeys.Id); // ?!
var viewModelTypeName = queryString[ValidationKeys.ViewModelType];
var viewModelType = Type.GetType(viewModelTypeName);
var viewModelInstance = providerResult.ConvertTo(viewModelType); // throws an InvalidOperationException
如何将QueryString
集合转换为视图模型?ASP.NET MVC 在将视图模型传递到操作方法参数时已经执行此操作。所以我需要的是使用 MVC 机制 ASP.NET 事后模型绑定。
我的控制器操作
var viewModelTypeName = queryString[ValidationKeys.ViewModelType];
var viewModelType = Type.GetType(viewModelTypeName);
var instance = Activator.CreateInstance(viewModelType);
UpdateModelUsingQueryString(instance);
更新模型
protected internal void UpdateModelUsingQueryString<TModel>(TModel model) where TModel : class
{
if (model == null) throw new ArgumentNullException("model");
Predicate<string> propertyFilter = propertyName => new BindAttribute().IsPropertyAllowed(propertyName);
var binder = Binders.GetBinder(typeof(TModel));
var bindingContext = new ModelBindingContext()
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, model.GetType()),
ModelState = ModelState,
PropertyFilter = propertyFilter,
ValueProvider = new QueryStringValueProvider(ControllerContext)
};
binder.BindModel(ControllerContext, bindingContext);
}
问题是UpdateModel
或TryUpdateModel
在设计上不适用于object
。两种方法都使用 typeof(TModel)
.但是你必须使用model.GetType()
.
查看: 模型绑定 - 键入外部程序集
达林·季米特洛夫给出了正确的答案:)
你要求的是序列化。为了简单地执行此操作,您可以放置一个构造函数重载,该重载接受 QueryStringValueProvider 作为参数,并且该构造函数负责基于提供程序初始化模型的所有属性。如果您坚持使用字符串,则可以轻松地将这样的构造函数放入可由所有模型继承的模型基类中。
这也可以内置到扩展方法中,因此可以称为"按需"而不是在构造时。
若要手动执行自定义模型绑定,请创建自定义模型绑定程序(实现IModelBinder
)并将其注册到 IoC 容器。
或者,您可以在操作方法中调用this.UpdateModel
。 这应该将 ValueProvider(RouteData、Request.Form 集合和 QueryString)中的值绑定到模型。
你可以使用TryUpdateModel
public ContentResult TestAction()
{
var model = new MyModel();
if(TryUpdateModel(model, new QueryStringValueProvider(ControllerContext)))
{
return Content("success");
}
return Content("failed");
}