带派生类的控制器操作

时间:2015-01-12 01:49:37

标签: c# asp.net-mvc polymorphism derived-class

我有一个基类和两个派生类:

public class UserModel {
    public int Id {get; set; }
    public string Name {get; set; }
    public UserType UserType {get; set;}
}

public class StudentModel : UserModel {
    public string StudentProperty {get; set;}
}

public class TeacherModel : UserModel {
    public string TeacherProperty {get; set;}
}

在我的控制器ProfileController.cs中,我有以下两个动作:

public virtual ActionResult Detail(int id)
{
    var userModel = _userService.Get(id);

    return view(usermodel);
}

public virtual ActionResult Save(UserModel userModel)
{
    _userService.Save(userModel);
}

我有一个视图来显示学生和教师的个人资料。我的问题如下:

保存时,使用操作Save(UserModel userMode),StudentModel和TeacherModel(分别为StudentProperty和TeacherProperty)的附加属性显然不绑定到UserModel。所以我的问题是:

设置Controller Action的正确方法是什么,以便我可以传递派生类,StudentModel或TeacherModel?

仅供参考,我尝试过自定义活页夹(见下文),但是,我不知道这是否是处理此问题的好方法。

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    var form = controllerContext.HttpContext.Request.Form;

    switch (form["UserType"])
    {
        case "student":
            {
                var studentModel = bindingContext.Model as StudentModel;                        
                return studentModel;
            }
        case "Teacher":
            {
                var teacherModel = bindingContext.Model as TeacherModel;
                medico.TeacherProperty = form["TeacherProperty"];
                return teacherModel;
            }
    }

    return bindingContext.Model;
}

2 个答案:

答案 0 :(得分:3)

多态模型绑定的最大问题是安全问题。毕竟,您实际上是在允许客户端控制数据的解释方式。例如,您必须要小心,用户无法修改帖子并告诉服务器您的UserModel实际上是一个AdministratorModel并且您现在是管理员。

在你的使用案例中,我不知道你的应用程序做了什么..但假设它是某种记录保存应用程序,想象一下学生只需改变提交给服务器的类型就可以让自己成为一名教师,现在他们可以改变自己的成绩,或者其他学生的成绩。

但是,如果这不是一个真正的问题,那么一个相当简单的机制就是简单地执行此操作:

public virtual ActionResult Save(UserModel userModel)
{
    TeacherModel tmodel = null;
    StudentModel smodel = null;
    if (userModel.UserType == UserType.Teacher) {
        tmodel = new TeacherModel();
        UpdateModel<TeacherModel>(tmodel);
    }
    else {
        smodel = new StudentModel();
        UpdateModel<StudentModel>(smodel);
    }

    _userService.Save((UserModel)tmodel ?? smodel);
}

您在问题中提出的自定义模型绑定器方法也很好,如果在多个方法中使用它,则更好的选择,但对于维护应用程序的人来说则不是那么明显。

事实上,假设您的模型类型基于某种安全机制,在这种情况下更好的解决方案是根据用户的角色实例化正确的模型。因此,当您的请求进入时,您检查用户权限,如果他们是教师角色,您实例化TeacherModel对象,如果他们是学生您实例化StudentModel对象,那么最终用户没有任何东西可以改变它的运作方式。

即,像这样:

public virtual ActionResult Save(UserModel userModel)
{
    TeacherModel tmodel = null;
    StudentModel smodel = null;
    // lookup user in database and verify the type of user they are
    var user = UserManager.GetUser(userModel.UserId)
    if (user.Role == "Teacher")
        tmodel = new TeacherModel();
        UpdateModel<TeacherModel>(tmodel);
    }
    else {
        smodel = new StudentModel();
        UpdateModel<StudentModel>(smodel);
    }

    _userService.Save((UserModel)tmodel ?? smodel);
}

答案 1 :(得分:1)

我以前做过这个确切的行为。我所做的是视图将根据类型动态更改表单操作。绑定的每个类型化模型都具有该类型的独立方法。

所以我的模特类似于:

public abstract class Property {...}

public class Industrial : Property {...}

public class Commercial : Property {...}

public abstract class Residence : Property {... }

public class Condo : Residence {...}

public class Residential : Residence {...}

查看:

@model Property

@using(Html.BeginForm(Model.GetType().Name, "Property", ...))
{
}

控制器:

public class PropertyController : Controller
{
  [HttpPost]
  public ActionResult Industrial(Industrial model)
  {
    ...
  }

  [HttpPost]
  public ActionResult Commercial(Commercial model)
  {
    ...
  }

  // etc
}

我担心使用自定义模型绑定器创建单个方法是因为我会开始根据类型执行特定于类的功能,这会创建一个非常大的方法,负责多种类型(打破Separation of Concerns