代码之家  ›  专栏  ›  技术社区  ›  Funka

如何在ModelBinder/UpdateModel方法中白名单/黑名单子对象字段?

  •  7
  • Funka  · 技术社区  · 17 年前

    我有一个问题,关于如何让MVC控制器的updateModel/tryUpdateModel的黑白列表功能处理子对象的各个属性。例如,假设我有一个问卷,收集填写表单的人和他或她的公司的详细信息。

    我的[简化]表单字段将被命名,例如:

    YourName
    YourEmail
    Company.Name
    Company.Phone
    

    现在在我的模型中,假设我不希望company.i d或company.ispremiumember被篡改,所以我想将它们从模型绑定中排除。我试过将白名单和黑名单结合起来使用,以使这两种方法都有效。我没有取得任何成功。以下是我遇到的问题:

    当我在我的白名单中明确地包括我在上面写的四个字段名时,整个公司不会被绑定(即,问卷。公司为空),除非我在白名单中也包括“公司”。但是这样做会对整个公司产生不良影响,而不仅仅是我想要的两个属性。

    因此,我尝试将company.id和company.ispremiummember加入黑名单,但这似乎被白名单击败了,我想“在事实之后”不会过滤掉这些属性。

    我知道还有其他方法来表示“可绑定性”,例如通过成员的[bind]属性来表示,但这并不理想,因为我希望在具有不同绑定规则的其他情况下使用相同的模型类,例如允许管理员设置她想要的任何属性。

    我希望一个显而易见的答案是,我应该写自己的模型活页夹,我已经开始尝试如何做到这一点,但我真的希望使用一个“开箱即用”的解决方案来解决(在我看来)看起来很常见的情况。我正在考虑的另一个想法是编写我自己的ValueProvider字典来提供UpdateModel方法,但同样,如果有更简单的方法,我宁愿避免这种方法。

    谢谢你的帮助! -迈克


    附录1

    以下是我在表单上显示的字段:

    YourName
    YourEmail
    Company.Name
    Company.Phone

    这是一顶黑帽子给我带来的:

    YourName=Joe+Smith&YourEmail=joe@example.com&Company.Name=ACME+Corp&Company.Phone=555-555-5555&Company.CreditLimit=10000000

    (确保您注意到末尾附加的额外参数!)

    问题是:

    正如我最初发布的那样,似乎不可能(使用默认的模型绑定器)在没有大的解决方案的情况下阻止设置信用额度——要么是整个公司,要么什么都没有。我错了吗?


    附录2

    我现在非常确信,我所拥有的简单目标是不可能“开箱即用”的。我的解决方案是浏览已发布的表单字段,构建自己的ValueProvider字典,从而将我想要允许的字段白名单化,并将其交给UpdateModel。


    附录3

    我还没有签出automapper,但是有了这样的解决方案,创建一些视图模型/dto来处理这种复杂的白名单的解决方案,加上能够轻松附加我已经在域对象上使用的同一服务器端验证(fluentvalidation),似乎是一个可行的解决方案。谢谢大家!

    3 回复  |  直到 17 年前
        1
  •  1
  •   yfeldblum    17 年前

    一般来说,最好的方法是 视图模型 模型的建立 专门针对您的观点 . 这些型号是 域对象。它们是数据传输对象,用于将数据从控制器操作传输到视图模板。你可以使用像这样的工具 AutoMapper 从视图模型对象创建/更新域模型对象,或者从域模型创建/更新视图模型对象,都是非常简单的。

        2
  •  1
  •   user434917    17 年前

    我通过使操作接受两个对象(父对象和子对象)来解决这个问题。

    例子:
    假设我们有以下模型:

     public class Employee
        {
            public string Name { get; set; }
            public int Age { get; set; }
            public Company Comapany { get; set; }
        }
        public class Company
        {
            public int Phone { get; set; }
        }
    

    您可以这样构建表单:

        <form action="Home/Create" method="post">
       <label for="Employee.Name">Name</label>
        <%=Html.TextBox("Employee.Name") %><br />
       <label for="Employee.Name">Age</label>    
        <%=Html.TextBox("Employee.Age") %><br />
       <label for="Employee.Name">Comapany Phone</label>    
        <%=Html.TextBox("Company.Phone") %><br />
        <input type="submit" value="Send" />
       </form>
    

    然后构建一个“创建”操作,接受两个对象,一个是Employee类型,另一个是Comapny类型,并将Company对象分配给Employee.Company属性:

     public ActionResult Create(Employee employee,Company company)
            {
                employee.Comapany = company;
                UpdateModel(employee);
                return View();
            }
    

    我希望这对你有帮助。

    编辑:

    public ActionResult Create(Employee employee,Company company)
    {
       employee.Comapany = company;
       UpdateModel(employee,new[] {"Name","Email","Phone"});
       return View();
    }
    
        3
  •  0
  •   jebcrum    17 年前

    您尝试过使用以下内容吗?:

    public actionresult create([bind(exclude=“propertyToExclude1,propertyToExclude2”)]员工) {

    //此处为操作代码

    }

    或者使用include而不是exclude列出可以绑定的字段,而不是不能绑定的字段