派生的控制器动作 类

Controller Action with Derived Classes

我有一个基础 class 和两个衍生的 classes:

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。所以我的问题是:

设置控制器动作的正确方法是什么,以便我可以传递派生的 class,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;
}

我以前确实做过这种行为。我所做的是视图会根据类型动态更改表单操作。每个绑定的类型模型都有一个针对该类型的独立方法。

所以我的模型类似于:

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
}

我担心使用自定义模型联编程序创建单个方法是因为我会开始执行 class 基于类型的特定功能,这会创建一个非常大的方法来负责多种类型(这会破坏Separation of Concerns).

多态模型绑定的最大问题之一是安全性。毕竟,您实际上是在允许客户控制数据的解释方式。您必须小心,例如,用户不能修改 post 并告诉服务器您的 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);
}