简体   繁体   中英

Generic type in MVC controller action

My controller action should be usable for a set of models that inherit the abstract class Polis:

public abstract class Polis
{
    /// <summary>
    /// Fields
    /// </summary>

    protected Polis()
    {
    }

    public Polis(Object input)
    {
        // Use input
    }
}

My controler action specifies the generic type should inherit this abstract class. But it does not see the constructor of the abstract class that has an argument. So I have to specify that it implements 'new()', instead I would like to use the constructor with an argument.

    public virtual ActionResult SavePolis<TModel>(PolisPostModel polisPM) where TModel : Polis, new()
    {
        if (ModelState.IsValid)
        {
            // Get the object or save a new object in the database
        }

        return Json(new
        {
            success = ModelState.IsValid,
            status = this.GetStatus(polisPM),
        });
    }

All data handling is done inside the inhereting classes, so I need the methods of the inheriting classes to be executed. But when I try to call the controller action giving my specific type as argument it has the error "No overload for method 'SavePolis' takes 0 arguments":

@Html.Hidden("SaveMyPolis", Url.Action(MVC.Controller.SavePolis<MyPolis>())

So what is the correct way to call this? And is it possible that the inherited class is made fully available, so it's methods are called instead of those from the abstract class.

I would use a custom modelbinder for this and multiple action methods accepting the subclasses. Assuming two subclasses of Polis: SubPolisA and SubPolisB, I would have 2 action methods:

  1. public ActionResult SavePolis(SubPolisA model)
  2. public ActionResult SavePolis(SubPolisA model)

then I would define a custom modelbinder for polis:

public class PolisModelBinder : System.Web.Mvc.IModelBinder
{
   public object BindModel(ControllerContext controllerContext, 
                            ModelBindingContext bindingContext)
    {
         var form = controllerContext.HttpContext.Request.Form;
         //use hidden value to determine the model
         if(form.Get("PolisType") == "SubClassA") 
         {
            //bind SubPolisA
         }
         else 
         {
            //bind SubPolisB
         }
    }
}

then in Application_Start() I would register the model binder using

ModelBinders.Binders.Add(typeof(SubPolisA), new PolisModelBinder());
ModelBinders.Binders.Add(typeof(SubPolisB), new PolisModelBinder());

or use the ModelBinderAttribute. If you want to you could also use multiple model binders for each subclass.

*sorry for code formatting

I believe all you need to do is this:

@Html.Hidden("SaveMyPolis", Url.Action(MVC.Controller.SavePolis<MyPolis>(Model))

assuming the model type in your View is PolisPostModel .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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