【问题标题】:How to Preserve/Protect Certain Fields in Edit in ASP.NET MVC如何在 ASP.NET MVC 中保留/保护编辑中的某些字段
【发布时间】:2011-09-25 14:53:51
【问题描述】:

在 ASP.NET MVC 的编辑操作中,可以使用 HiddenFieldFor 对用户隐藏某些字段。但是,这并不能保护字段(例如 ID、数据创建日期)不被编辑。

例如,模型 Student 具有字段 Id、Name 和生日。我喜欢允许用户更新姓名,但不允许更新 ID 或生日。

对于这样的编辑操作

public ActionResult Edit(Student student)
{
    if (ModelState.IsValid)
    {
        db.Entry(student).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(student);
}

如何防止编辑 ID 和生日?谢谢!

【问题讨论】:

    标签: asp.net asp.net-mvc entity-framework


    【解决方案1】:

    您应该使用仅包含您要编辑的属性的视图模型:

    public class EditStudentViewModel
    {
        public string Name { get; set; }
    }
    

    然后:

    public ActionResult Edit(StudentViewModel student)
    {
        ...
    }
    

    另一种我不推荐的技术是从绑定中排除某些属性:

    public ActionResult Edit([Bind(Exclude = "Id,Birthday")]Student student)
    {
        ...
    }
    

    或包括:

    public ActionResult Edit([Bind(Include = "Name")]Student student)
    {
        ...
    }
    

    【讨论】:

    • 我怎么忘记了视图模型。你的意思是我应该有一个基于 Student 模型的视图模型,并在 Edit 视图/操作中使用它?
    • @Jim,是的,你怎么能这样?真的。解决所有问题的 ASP.NET MVC 中最基本的概念 :-) 是的,您应该有一个专门为 Edit 操作设计的视图模型。它应该只包含您感兴趣的属性。然后您应该在视图模型和模型模型之间进行映射以执行更新。 AutoMapper 是完成这项工作的绝佳工具。
    • 谢谢!我将检查 AutoMapper。为什么不建议排除某些属性?
    • @Jim,因为明天您(或团队中的其他开发人员)将向域模型添加一个新属性,而忘记将其添加到控制器操作的 [Bind] 属性中,您将得到非常糟糕的惊喜。它被称为mass assignment 攻击,它基本上会在您的数据库中设置不应该设置的字段。想想如果你的域模型有一个 IsAdmin 字段的后果 => 灾难性的。伪造一个带有IsAdmin=true 的HTTP 请求就足够了,学生将成为管理员。
    • 感谢您的详细回答。我最终在模型和视图模型之间建立了自己的映射。
    【解决方案2】:

    我假设您必须在模型中拥有属性,以便在 View 中您可以使用它们来呈现有用的信息,例如带有 ID 或一些只读文本的 ActionLink。

    在这种情况下,您可以使用显式绑定来定义您的模型:

    [Bind(Include = "Name")]
    public class Student
    {
        int Id { get; set; }
        int Name { get; set; }
        DateTime Birthday { get; set; }
    }
    

    这样在更新你的模型时,如果用户提交了一个额外的Id,它就不会被绑定。

    我喜欢的另一个想法是让您的模型知道每个场景的绑定并让它们经过编译器验证:

    public class ModelExpression<T>
    {
        public string GetExpressionText<TResult>(Expression<Func<T, TResult>> expression)
        {
            return ExpressionHelper.GetExpressionText(expression);
        }
    }
    
    public class Student
    {
        public static string[] EditBinding = GetEditBinding().ToArray();
    
        int Id { get; set; }
        int Name { get; set; }
        DateTime Birthday { get; set; }
    
        static IEnumerable<string> GetEditBinding()
        {
            ModelExpression<Student> modelExpression = new ModelExpression<Student>();
            yield return modelExpression.GetExpressionText(s => s.Name);
        }
    }
    

    这样在你的 Action 调用 TryUpdateModel 时你可以传递这些信息。

    【讨论】:

    • 感谢您的回答。投票 =)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多