Search code examples
c#asp.net-mvcmodel-bindingrequest.querystringvalue-provider

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. The keys of the QueryString match my view model properties.

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? ASP.NET MVC already do this when you just pass the view model into the action method parameters. So what I need is an afterwards model binding using ASP.NET MVC mechanics.


Solution

  • 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. Both methods use typeof(TModel). But you have to use model.GetType().

    Take a look at: Model Binding - Type in External Assembly

    Darin Dimitrov gave the right answer :)