Asp.net mvc 如何在ModelBinder/UpdateModel方法中白名单/黑名单子对象字段?
我有一个问题,关于如何让MVC控制器的UpdateModel/TryUpdateModel的白名单和黑名单特性处理子对象的各个属性。例如,假设我有一份调查问卷,收集有关填写表格的人及其公司的详细信息 我的[简化]表单字段将被命名,例如:Asp.net mvc 如何在ModelBinder/UpdateModel方法中白名单/黑名单子对象字段?,asp.net-mvc,Asp.net Mvc,我有一个问题,关于如何让MVC控制器的UpdateModel/TryUpdateModel的白名单和黑名单特性处理子对象的各个属性。例如,假设我有一份调查问卷,收集有关填写表格的人及其公司的详细信息 我的[简化]表单字段将被命名,例如: YourName YourEmail Company.Name Company.Phone 现在在我的模型中,假设我不希望Company.ID或Company.ispremiummber被篡改,所以我想将它们从模型绑定中排除。我尝试了白名单、黑名单以及两者的组
YourName
YourEmail
Company.Name
Company.Phone
现在在我的模型中,假设我不希望Company.ID或Company.ispremiummber被篡改,所以我想将它们从模型绑定中排除。我尝试了白名单、黑名单以及两者的组合,以使其发挥作用。我没有取得任何成功。以下是我遇到的情况:
当我在我的白名单中明确包括我上面写的四个相同的字段名时,整个公司不受约束(即,问卷调查。公司为空),除非我也在我的白名单中包括“公司”。但这会产生不良影响,约束整个公司,而不仅仅是我想要的两个属性
因此,我尝试将Company.ID和Company.ispremiummber包含在黑名单中,但这似乎被白名单所压倒,并且我认为不会“事后”过滤掉这些属性
我知道还有其他方式来表达“可绑定性”,比如通过成员上的[Bind]属性,但这并不理想,因为我希望在其他情况下使用相同的模型类,并使用不同的绑定规则,例如允许管理员设置她想要的任何属性
我希望一个明显的答案是,我应该编写自己的模型绑定器,我已经开始尝试研究如何做到这一点,但我真的希望使用“开箱即用”的解决方案来解决(在我看来)似乎非常常见的场景。我正在考虑的另一个想法是制作我自己的ValueProvider字典,将其交给UpdateModel方法,但是,如果有更简单的方法,我宁愿避免这一点
谢谢你的帮助!
-迈克
附录#1 以下是我在表格中显示的字段: 你的名字 你的电子邮件 公司名称 公司,电话 这是一顶黑帽子带给我的: YourName=Joe+Smith&YourEmail=joe@example.com&Company.Name=ACME+Corp&Company.Phone=555-555-5555&Company.CreditLimit=10000000 (请确保注意末尾附加的额外参数!) 问题是: 正如我最初发布的,如果没有一些大的解决办法,似乎不可能(使用默认的模型绑定器)阻止设置CreditLimit——要么是整个公司,要么什么都没有。我错了吗
附录2 我现在非常确信我的简单目标是不可能“开箱即用”的。我的解决方案是遍历已发布的表单字段并构建我自己的ValueProvider字典,从而将我想要允许的字段白名单,并将其交给UpdateModel
附录#3
我还没有签出AutoMapper,但有了类似的东西,创建一些ViewModels/DTO来处理这种复杂的白名单的解决方案——再加上轻松附加我已经在域对象上使用的相同服务器端验证(FluentValidation)的能力——似乎是一个可行的解决方案。谢谢大家 我通过使操作接受两个对象(父对象和子对象)来解决这个问题 示例:
假设我们有以下模型:
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>
我希望这对你有帮助
编辑:
public ActionResult Create(Employee employee,Company company)
{
employee.Comapany = company;
UpdateModel(employee,new[] {"Name","Email","Phone"});
return View();
}
通常,最好的方法是创建视图模型,即专门为视图构建的模型。这些模型不是域对象。它们是数据传输对象,用于将数据从控制器动作传输到视图模板。您可以使用类似的工具轻松地从视图模型对象创建/更新域模型对象,或从域模型创建/更新视图模型对象。您尝试过使用以下工具吗?: 公共操作结果创建([Bind(Exclude=“PropertyToExclude1,PropertyToExclude2”)]Employee员工) { //这里是行动代码 }
或者使用Include而不是Exclude列出哪些字段可以绑定,哪些字段不能绑定谢谢您的回复。然而,绑定模型并没有任何问题:我的问题是试图限制模型中绑定的内容。在您的示例中,似乎在不向UpdateModel方法提供白名单或黑名单(或其他等效项)的情况下,有人仍然可以通过将Company.IsPremiumMember注入他们的表单post来设置它。然后,解决方案是将要包含的属性列表传递给UpdateModel方法。我会更新我的回答。我在原来的帖子上加了一个附录。(特别是见最后一行。)这个问题看起来更像是公司财产上的“全有或全无”…这是一个小问题,但在上面的表单示例中,文本框id attibutes将使用下划线而不是句点呈现,因此需要相应地修改标记的标签。谢谢你,Marwan,我确实看到你的最新编辑在技术上完成了我想要的。然而,由于我有大约八到九个对象(都是公司的孩子),因此以这种方式解释所有这些对象似乎不是很有吸引力。在我的例子中,我提出的解决方案似乎只允许我处理一个白名单和一个“UpdateModel”调用,并且还可以避免事后“重新附加”所有对象。我还可以在剩下的页面上重新使用我自己的白名单技术!再次感谢!AutoMapper看起来是一个非常好的实用工具,它确实可以简化这一过程。我要去看看
<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>
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();
}