Binding any field prefix to an action parameter in C# MVC 4/5

asp.net-mvc, c#, model-view-controller

Solution

I see that in your view you have different partials for the different kind of vehicles. That means that you know beforehand what are the different vehicle types.

As you know it before hand, you simply have to make the separation of groups when you create the viewmodel. I.e. create a viewmodel with the different lists for cars, trucks, buses... In this way you'll have the required prefixes in the client side.

An what about the post action? Well, instead of receiving the list as individual parameters, just receive a class similar to the one you use to render the editor, i.e.

Use a class that has this properties to create the editor (use it as your view model):

public class VehiclesViewModel
{
  public List<Vehicle> Cars { get; set;}
  public List<Vehicle> Buses { get; set;}
  // other stuff here!
}

If you use a class like, this, that also has the cars, buses, etc. lists, the data will be bound automatically, i.e. insetad of using:

public ActionResult Edit([Bind(Prefix = "Car")] VmVehicle car, 
     [Bind(Prefix = "Bus")] VmVehicle bus, ...)

use an Action like this:

public ActionResult Edit(VehiclesViewModel vehicles)

and the model binder will handle the prefixes for you, and bind each vehicle to its corresponding list.

Display and edit templates

However, if you use different classes for each type of vehivle, you can use custom Display and Edit templates, that can make your lief easier. I.e. you can define display and edit templates that apply to a given data type. So, if you have a different class for each kind of vehicle you can use display and edit templates for each different class, and using ´DisplayFor´ or `EditorFor` you'll get automatically the required view. Some samples in this links:

- Exploring Display and Editor Templates in ASP.NET MVC3/4

- ASP.NET MVC DisplayTemplate and EditorTemplates for Entity Framework DbGeography Spatial Types

- ASP.NET MVC display and editor templates

(I don't understand what you're exactly doing, so I can give a more concrete explanation for this)

Model binding a list of complex objects

Another classical problem which peoplefind with MVC is that, when they want to bind a list of complex objects that have to be edited, they don't know how to do it so that they get the list of objects back in the server in the post action.

This explanation by Phil Haack is one of the best that you can find.

Problem

I'm using C# ASP.Net MVC 4 and MVC 5. I use an aggregate model `VmVehicleGroup` which looks little bit like: ``` public class VmVehicleGroup { public VehicleTypeEnum Type { get; set; } public List<VmVehicle> Vehicles { get; set; } public VmVehicle Editable { get; set;} } ``` The master view has partials for each each group, for example, ``` @Html.Partial(x => x.Cars, "_VehicleEditor") @Html.Partial(x => x.Bus, "_VehicleEditor") @Html.Partial(x => x.Truck, "_VehicleEditor") ``` Each group partial displays `Model.Vehicles` and presents an editor template for the `Model.Editable` My problem comes from the ModelState. Each partial will render the same input field name/ids for Model.Editable. When there are ModelState validation errors, the validation error for say the 'Car' partial, will appear on all the other forms, not just Car. I've worked around this by prefixing the models in the editor paritial, eg: ``` ViewData.TemplateInfo.HtmlFieldPrefix = Model.Type.ToString(); // VehicleTypeEnum ``` The Add/Edit form will now submit `Model.Editable` with field post data prefixes, ie: Car.Reg, Car.Name, Car.Type and Car.Id. My problem arises on the MVC action. My action currently looks like this: ``` [ValidateAntiForgeryToken] [AcceptVerbs(HttpVerbs.Post)] [Route("Edit", Name = "EditVehicle")] public ActionResult Edit([Bind(Prefix = "Car")] VmVehicle car, [Bind(Prefix = "Bus")] VmVehicle bus, [Bind(Prefix = "Truck")] VmVehicle truck, ....) { var model = car ?? bus ?? truck; ... } ``` My problem is that this is maintanence nightmare - for each VehicleTypeEnum I need to add extra bind parameters. I can't have a single action for a prefixed model. I've tried using `public ActionResult Edit(VmVehicle model) {}`, but the prefix hinders the MVC binding. Unfortunately it appears MVC also doesn't let you bind a wildcard or comman separated prefix, ie: *.Car or Car,Bus,Truck. Is it possible to encourage the MVC action to accept any prefix, while maintaining the prefix for ModelState validation errors?

Original source