简体   繁体   English

之后在ASP.NET MVC中进行模型绑定:如何将QueryString值转换为视图模型?

[英]Afterwards Model Binding in ASP.NET MVC: How to convert QueryString values into a view model?

I have an action method without parameters. 我有一个没有参数的动作方法。

The QueryString collection contain all of my values. QueryString集合包含我所有的值。 The keys of the QueryString match my view model properties. 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

How can I convert the QueryString collection to a view model? 如何将QueryString集合转换为视图模型? ASP.NET MVC already do this when you just pass the view model into the action method parameters. 当您仅将视图模型传递给操作方法参数时,ASP.NET MVC已经做到了。 So what I need is an afterwards model binding using ASP.NET MVC mechanics. 因此,我需要使用ASP.NET MVC机制进行事后模型绑定

To manually do custom model binding, create a custom model binder (implement IModelBinder ) and register it with your IoC container. 要手动执行自定义模型绑定,请创建一个自定义模型绑定器(实现IModelBinder )并将其注册到您的IoC容器中。

Or you could call this.UpdateModel on inside your action method. 或者,您可以在action方法内部调用this.UpdateModel This should bind the values from your ValueProvider (RouteData, Request.Form collection and QueryString) to your model. 这应该将ValueProvider中的值(RouteData,Request.Form集合和QueryString)绑定到模型。

What you're asking for is serialization. 您要的是序列化。 For doing this simply, you could put a constructor overload that accepts a QueryStringValueProvider as an argument and that constructor is responsible initializing all of the model's properties based on the provider. 为了简单地执行此操作,可以放置一个构造函数重载,该重载接受QueryStringValueProvider作为参数,并且该构造函数负责根据提供程序初始化所有模型的属性。 If you stick to strings, you could very easily put such a constructor into a model base class that could be inherited by all of your models. 如果坚持使用字符串,则可以很容易地将这样的构造函数放到可以被所有模型继承的模型基类中。

This could also be built into an extension method so it could be called "on demand" rather than at construction. 也可以将其内置到扩展方法中,因此可以将其称为“按需”而不是在构建时使用。

You could use TryUpdateModel 您可以使用TryUpdateModel

public ContentResult TestAction()
{
   var model = new MyModel();

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

   return Content("failed");
}

My Controller Action 我的控制器动作

var viewModelTypeName = queryString[ValidationKeys.ViewModelType];
var viewModelType = Type.GetType(viewModelTypeName);
var instance = Activator.CreateInstance(viewModelType);
UpdateModelUsingQueryString(instance);

UpdateModel 更新模型

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);
}

The problem was that UpdateModel or TryUpdateModel does not work for object by design. 问题是UpdateModelTryUpdateModel不适用于设计object Both methods use typeof(TModel) . 两种方法都使用typeof(TModel) But you have to use model.GetType() . 但是您必须使用model.GetType()

Take a look at: Model Binding - Type in External Assembly 看一下: 模型绑定-键入外部装配体

Darin Dimitrov gave the right answer :) Darin Dimitrov给出了正确的答案:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM