ASP.NET MVC 2 - abstract model binding

If I have the following strongly typed view:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<XXX.DomainModel.Core.Locations.Location>" %> 

Where Location is an abstract class.

And I have the following controller that accepts a strongly typed model using POST:

 [HttpPost] public ActionResult Index(Location model) 

I get a runtime error indicating "Unable to create abstract class

Which, of course, makes sense. However - I'm not sure what the best solution is here.

I have many specific types (about 8), and this is a view in which you can edit the properties of an abstract class.

What they tried to do to me was to create overloads for all different specific types and execute my logic in a general method.

 [HttpPost] public ActionResult Index(City model) { UpdateLocationModel(model); return View(model); } [HttpPost] public ActionResult Index(State model) { UpdateLocationModel(model); return View(model); } 

etc.

And then:

 [NonAction] private void UpdateLocationModel (Location model) { // ..snip - update model } 

But this does not work either , MVC complains that the methods of action are ambiguous (also makes sense).

What should we do? Can we just not get attached to an abstract model?

+11
c # abstract-class model-binding asp.net-mvc-2
Oct. 25 '10 at 6:19 06:19
source share
3 answers

How about writing a custom mediator for this abstract class:

 public class CustomBinder : DefaultModelBinder { protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) { // TODO: based on some request parameter choose the proper child type // to instantiate here return new Child(); } } 

This only makes sense if you have a form in which input elements are inserted dynamically based on some user actions. In this case, you need to pass an additional parameter to indicate which specific class you need. Otherwise, I will stick to specific presentation models as action parameters.

+7
Oct 25 2018-10-10T00:
source share

You can also create a generic ModelBinder that works for all of your abstract models. My solution requires you to add a hidden field to your view called " ModelTypeName " with the value set for the name of the particular type you want. However, it should be possible to make this thing smarter and select a specific type by comparing type properties with fields in the view.

In the Global.asax.cs file in Application_Start () :

 ModelBinders.Binders.DefaultBinder = new CustomModelBinder(); 

CustomModelBinder:

 public class CustomModelBinder2 : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var modelType = bindingContext.ModelType; if (modelType.IsAbstract) { var modelTypeValue = controllerContext.Controller.ValueProvider.GetValue("ModelTypeName"); if (modelTypeValue == null) throw new Exception("View does not contain ModelTypeName"); var modelTypeName = modelTypeValue.AttemptedValue; var type = modelType.Assembly.GetTypes().SingleOrDefault(x => x.IsSubclassOf(modelType) && x.Name == modelTypeName); if (type != null) { var instance= bindingContext.Model ?? base.CreateModel(controllerContext, bindingContext, type); bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => instance, type); } } return base.BindModel(controllerContext, bindingContext); } } 
+3
Sep 22 2018-11-18T00:
source share

Just to throw it there - I am very interested in what others can answer, but this is what I did in case I had a similar situation;

Basically, I did not use the model class as a parameter in the Action method, but instead passed the FormCollection and tested a couple of well-known discriminators to find out what type to create / edit, and then used TryUpdateModel .

It seemed like there might be a better way, but I never thought about it anymore.

+1
Oct 25 '10 at 6:35
source share



All Articles