C# ASP.NET MVC中的模型绑定:如何将查询字符串值转换为视图模型?

C# ASP.NET MVC中的模型绑定:如何将查询字符串值转换为视图模型?,c#,asp.net-mvc,model-binding,request.querystring,value-provider,C#,Asp.net Mvc,Model Binding,Request.querystring,Value Provider,我有一个没有参数的动作方法 QueryString集合包含我的所有值。查询字符串的键与我的视图模型属性匹配 var queryStringValueProvider = new QueryStringValueProvider(ControllerContext); var providerResult = queryStringValueProvider.GetValue(ValidationKeys.Id); // ?! var viewModelTypeName = queryStrin

我有一个没有参数的动作方法

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就已经做到了这一点。因此,我需要的是使用ASP.NET MVC机制进行后期模型绑定。

要手动执行自定义模型绑定,请创建自定义模型绑定器实现IModelBinder并将其注册到IoC容器中


或者可以在action方法中调用this.UpdateModel。这应该将ValueProvider RoutedData、Request.Form集合和QueryString中的值绑定到您的模型。

您要求的是序列化。为了简单地执行此操作,您可以放置一个构造函数重载,该重载接受QueryStringValueProvider作为参数,并且该构造函数负责基于该提供程序初始化模型的所有属性。如果您坚持使用字符串,就可以很容易地将这样的构造函数放入一个模型基类中,该基类可以被所有模型继承

这也可以内置到扩展方法中,以便在需要时而不是在构建时调用它。

您可以使用TryUpdateModel

我的控制器动作

更新模型

问题是UpdateModel或TryUpdateModel在设计上不适用于对象。 这两种方法都使用typeofTModel。但是您必须使用model.GetType

看看:


达林·迪米特罗夫给出了正确的答案:

这也许能回答你的问题@阿德玛:不,不是。参数名/属性名仅在运行时已知。我尝试使用RemoteAttribute属性验证用户输入数据。我希望有一个单一的操作方法来处理应该是唯一的属性的远程验证。IoC与我的问题有什么关系:o?MVC将使用您的IoC容器来解析模型绑定。如果您创建自己的模型绑定器,则需要在IoC容器中注册。为什么我必须编写自己的模型绑定器?如果您的查询字符串中有任何数据无法与DefaultModelBinder绑定,例如,您可能需要在绑定前进行一些计算,您需要创建自己的模型绑定器来明确地告诉MVC您的值应该如何映射到您的模型。如果DefaultModelBinder可以绑定您的值,那么您就不需要创建自己的模型绑定器,而且正如许多人所建议的,您可以在控制器上使用UpdateModel或TryUpdateModel方法。@Rookian您问了一个问题,我给出了答案。这取决于你是否尝试。如果你知道模型TryUpdateModel运行良好。但是我不知道模型,但是它的类型。你是在模型绑定器中做这个过程的吗?但我认为,对这种类型本身了解得足够多。你必须查看这篇文章
public ContentResult TestAction()
{
   var model = new MyModel();

   if(TryUpdateModel(model, new QueryStringValueProvider(ControllerContext)))
   {
      return Content("success");
   }

   return Content("failed");
}
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);
}