asp.net mvc fill viewModel from FormCollection

asp.net, asp.net-mvc, c#, model-binding

Solution

You can try Controller.UpdateModel or Controller.TryUpdateModel method:

[HttpPost]
public ActionResult SaveStatement(User currentUser, FormCollection statement, string ViewModelName)
{
    ...
    object ViewModel = Activator.CreateInstance(type);
    if (TryUpdateModel(viewModel))
    {
        // save the ViewModel
    }   

    return View(ViewModelName, ViewModel);
}

However I would suggest you to create a custom ModelBinder, as it is its responsibility to create and populate model properties.

I can show you a simple example how you can achieve this:

Base ViewModel

public abstract class StatementViewModel
{
    public abstract StatementType StatementType { get; }
    ...
}

public enum StatementType
{
    Relief,
    RequestForSalary,
    ...
}

ViewModels

public class RequestForSalaryVM : StatementViewModel
{
    public override StatementType StatementType
    {
        get { return StatementType.RequestForSalary; }
    }
    ...
}

public class ReliefVM : StatementViewModel
{
    public override StatementType StatementType
    {
        get { return StatementType.Relief; }
    }
    ...
}

ModelBinder

public class StatementModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var statementTypeParameter = bindingContext.ValueProvider.GetValue("StatementType");
        if (statementTypeParameter == null)
            throw new InvalidOperationException("StatementType is not specified");

        StatementType statementType;
        if (!Enum.TryParse(statementTypeParameter.AttemptedValue, true, out statementType))
            throw new InvalidOperationException("Incorrect StatementType"); // not sure about the type of exception

        var model = SomeFactoryHelper.GetStatementByType(statementType); // returns an actual model by StatementType parameter
                                                                         // this could be a simple switch statement
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, model.GetType());
        bindingContext.ModelMetadata.Model = model;
        return model;
    }
}

After that register the model binder in the `Global.asax`:

ModelBinders.Binders.Add(typeof(StatementViewModel), new StatementModelBinder());

Controller

[HttpPost]
public ActionResult Index(StatementViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        // save the model
    }
    return View(viewModel);
}

Problem

I have a lot of similar ViewModel: ``` public class RequestForSalaryVM : StatementViewModel { // RequestForSalaryVM properties } public class ReliefVM : StatementViewModel { // ReliefVM properties } ``` and a lot of similar methods: ``` [HttpPost] public ActionResult SaveRelief(User currentUser, ReliefVM statement) { ReliefVM model = (ReliefVM)SaveModel(currentUser, statement); if (model == null) return RedirectToAction("List"); return View("Relief", model); } [HttpPost] public ActionResult SaveRequestForSalary(User currentUser, RequestForSalaryVM statement) { RequestForSalaryVM model = (RequestForSalaryVM)SaveModel(currentUser, statement); if (model == null) return RedirectToAction("List"); return View("RequestForSalary", model); } ``` I want to get something like this: ``` [HttpPost] public ActionResult SaveStatement(User currentUser, FormCollection statement, string ViewModelName) { Assembly assembly = typeof(SomeKnownType).Assembly; Type type = assembly.GetType(ViewModelName); object ViewModel = Activator.CreateInstance(type); //Fill ViewModel from FormCollection <= how can I use asp.net mvc binding for this? //I do not want to create their own implementation of asp.net mvc binding return View(ViewModelName, ViewModel); } ```

Original source