3

I've the following class structure.

public BaseClass
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public ClassOne : BaseClass
{

}

public ClassTwo : BaseClass
{

}

My Controller is like this

public TestController : Controller
{
     public ActionResult ClassOne()
     {
          ClassOne model = new ClassOne();
          return View("Create",model);
     }

     public ActionResult ClassTwo()
     {
          ClassTwo model = new ClassTwo();
          return View("Create",model);
     }         

My View ("Create") is like this :

     @model MvcApplication.Models.BaseClass

     @using(Html.BeginForm("Post","Test",FormMethod.Post))
     {
            @Html.HiddenFor(model => mode.Id)
            @Html.TextBoxFor(model => model.Name)
            <input type="submit" value="Submit"/>
     }

My Post Action is the same for both the models i.e. ClassOne & ClassTwo. On Post how can I know which model is passed in the Post Action whether it is ClassOne or ClassTwo.

     [HttpPost]
     public ActionResult Post(BaseClass model)
     {
          /* Code */
     }
hendrixchord
  • 4,662
  • 4
  • 25
  • 39
  • Have you tried using "is" in your controller ? (i.e. if(model is a ClassTwo) – Pacman Nov 20 '13 at 14:28
  • 1
    I don't see how this is possible. When the post action is invoked, the model binder will try and bind to the parameters of the method - and in the process instantiate an instance of the `BaseClass` with no knowledge of the original type passed in to the view when rendering it - any anyway - the model type for the view is the `BaseClass` so.. i just don't see it.. – Quinton Bernhardt Nov 20 '13 at 14:35
  • Exactly as I answered. You should write custom ModelBinder and store actual type name inside your form and then create appropriated class in your model binder – Dmytro Rudenko Nov 20 '13 at 14:36
  • There are different techniques. Have a look at the answer here, and the ops own solution http://stackoverflow.com/a/19450985/150342 – Colin Nov 20 '13 at 15:07

6 Answers6

2

Inside the post just check the type. Either by if(model is ClassOne) or if(model.GetType() == typeof(ClassOne))

Adam Bilinski
  • 1,188
  • 1
  • 18
  • 28
  • This will not work. Without storing extra information about the type, whether that's in a hidden field, or from `ViewBag` / `ViewData`, there is no way for the model binder to infer the type. As far as it will be concerned, it will have created the base type. – John H Nov 20 '13 at 15:53
2

I'm not sure that it is possible without creating your own ModelBinder. In this case you'll always get in your action instance of BaseType class.

Dmytro Rudenko
  • 2,524
  • 2
  • 13
  • 22
  • 1
    I agree. When the post action is invoked, the model binder will try and bind to the parameters of the method - and in the process instantiate an instance of the `BaseClass` with no knowledge of the original type passed in to the view when rendering it. – Quinton Bernhardt Nov 20 '13 at 14:36
  • 1
    All, what you need for successful implementation of your model binder is information about current model type. You may store it in view as hidden field for example and in your model binder at the beginning get this info, create property of appropriate type and fill it. – Dmytro Rudenko Nov 20 '13 at 14:44
  • 1
    This technique does it without creating a ModelBinder http://stackoverflow.com/questions/7222533/polymorphic-model-binding/7376583#7376583 – Colin Nov 20 '13 at 15:13
1

You can use typeof():

if(model.GetType() == typeof(ClassOne)){
 // do something
}else {
 // do something else.
}

Edit:

thanks to @JoreanVannevel

if(model is ClassOne){}

Aniket Inge
  • 25,375
  • 5
  • 50
  • 78
0

You can just check the type of the object.

if(model.GetType() == typeof(ClassOne))
{
    // Do something
}
Colin Bacon
  • 15,436
  • 7
  • 52
  • 72
  • See above. There is not sufficient information for the model binder to make any distinction about which of the derived types it constructed without extra information being provided. – John H Nov 20 '13 at 15:55
0

Jonah, You should use one model for a view. Now you can do two things

First thing,

you can use custom model binder see here http://www.codeproject.com/Articles/605595/ASP-NET-MVC-Custom-Model-Binder

or (Second thing),

in Html.Beginform also place hidden field to for identifying type (like 1 for ClassOne , 2 for ClassTwo). and now create a third class which has distinct property of both ClassTwo and ClassOne , common property of BaseClass and a extra property for type information.(do not use any type of validation here) for the post use the newly created type, then check the type field.

Arjun Vachhani
  • 1,761
  • 3
  • 21
  • 44
0

your problem is action can't judge which type.because view to action the type is loose. but we can get type at view and send the type to the action.

view like this: @model MvcApplication.Models.BaseClass

 @using(Html.BeginForm("Post","Test",FormMethod.Post))
 {
        @Html.HiddenFor(model => mode.Id)
        @Html.TextBoxFor(model => model.Name)
        @Html.Hidden("type", model.GetType().Tostring())

        <input type="submit" value="Submit"/>
 }

action like this:

[HttpPost]
 public ActionResult Post(BaseClass model)
 {
      /* Code */
      if(Request["type"] == typeof( ClassOne).Tostring())
      {
      } 
      if(Request["type"] == typeof( ClassTwo ).Tostring())
      {
      } 
 }