我们一直在迁移大量遗留代码&系统到ASP.NET MVC表单。我已经使用模型绑定,验证,属性等编写了许多与MVC 4的CRUD类型接口,因此我非常熟悉整个范例。到目前为止,所有这些形式一直在我们的后端管理和&管理应用程序,它需要非常严格的输入验证。我们正在MVC推出我们的第一个面向消费者的应用程序,并面临着不同类型的问题。
我们在该领域的传统形式是我们公司的主要收入引擎。消费者体验的可用性是当今的规则。为此,我们希望我们的表单尽可能宽松 - 遗留系统做了很多事情来自动纠正用户输入(当然,每次都是完全自定义的,非标准的方式)。为此,我们不需要输入验证,因为我们需要卫生设施。
我们要求用户提供隐含的度量单位的数字输入。常见的是货币金额或平方英尺。输入标签很清楚,他们不需要提供这些格式:
近似面积是多少? (例如:2000)
您的预算是多少? (例如:150)
人是人,不是每个人都遵循指示,我们经常得到如下答案:
大约2100
1500平方英尺
$ 47.50,给予或接受
(好吧,我夸大了最后一个。)我们最终存储到业务逻辑中的模型接受这些字段的数字输入类型(例如int& float)。我们当然可以使用datatype validator attributes(示例[DataType(DataType.Currency)]
作为预算输入,或者只是将字段类型设置为平方英尺的整数),以清楚地向用户表明他们做错了,提供了有用的帮助错误消息,例如:
平方英尺必须只是数字。
然而,更好的用户体验是尝试尽可能宽松地解释他们的响应,因此他们可以尽可能少地中断完成表单。 (注意我们有一个广泛的客户服务方面,他们可以在我们的系统之后解决错误,但我们必须让用户在我们联系之前填写表格。)对于上面的平方镜头示例,这只是意味着剥离非数字字符。对于预算,这意味着要删除所有不是数字或小数点的内容。只有这样我们才能应用剩余的验证(是一个数字,大于0,小于50000等)。
我们坚持采取最佳方法来实现这一目标。
我们考虑了自定义属性,自定义模型绑定以及在模型和数据库之间存在的单独的scrubber服务类。以下是我们在尝试确定方法时考虑的一些注意事项。
我已经阅读了很多有用的资源。 (它们具有不同程度的相关性和新近性。我找到的很多东西都是为MVC2或MVC3编写的,并且在MVC4中可以使用标准属性。)
我找不到的是有人在做我想做的事情,这会改变模型价值本身。我显然可以创建值的本地副本,清理它并提供通过/失败,但这会导致大量重复的代码。在保存到数据库之前,我仍然需要再次清理任何输入值。
更改模型值本身有3个好处:
这是一种有效的方法吗?是否有人以这种方式使用验证属性而我错过了?
我阅读了Splitting DateTime - Unit Testing ASP.NET MVC Custom Model Binders,其中关注自定义日期时间输入字段以及自定义验证&解析在模型绑定层完成。这与模型本身更接近,所以它似乎是修改模型值的更合适的地方。实际上,示例class DateAndTimeModelBinder : IModelBinder
在几个地方就是这样做的。
但是,为此示例提供的控制器操作签名不使用整体模型类。看起来像这样
public ActionResult Edit(int id,
[DateAndTime("year", "mo", "day", "hh","mm","secondsorhwatever")]
DateTime foo) {
而不是这个
public ActionResult Edit(
MyModelWithADateTimeProperty model) {
在此之前不久,文章确实说了
首先,用法。您可以通过在Global.asax中注册此自定义模型绑定器来管理所有日期时间:
ModelBinders.Binders[typeof(DateTime)] =
new DateAndTimeModelBinder() { Date = "Date", Time = "Time" };
是否足以在单参数模型示例MyModelWithADateTimeProperty
上调用日期时间字段的模型绑定?
我在这里看到的另一个可能的缺点是模型绑定器对类型进行操作,而不是可以应用于标准数据类型的属性。因此,例如,我想要应用的每组验证规则都需要一个新的自定义类型。这不一定是坏事,但它可能会变得混乱并导致大量重复的代码。想象:
public class MyDataModel {
[Required]
public CurrencyType BudgetRange { get; set; }
public PositiveOnlyCurrencyType PaymentAmount { get; set; }
[Required]
public StripNonDigitsIntegerType SquareFootage { get; set; }
不是我见过的最丑陋的型号代码,但也不是最漂亮的。
这对我来说问题最少,但也有最大的缺点。我以前做过这样的事情,只是因为以下原因之一而后悔:
您会采取哪种方法(或者,您已经采取过)来实现这种类型的消毒?它为你解决了什么问题?你遇到了什么问题?
答案 0 :(得分:3)
我会采用ModelBinder方法。
当表单数据进入时 - 它会转到模型绑定器基础结构。在那里你可以覆盖十进制模型绑定器来优化输入。之后,您可以将其发送到验证例程,而无需编写特定的验证属性或类似的东西。
此外,您可以使用一个智能模型绑定器,它将执行internaly类型切换或覆盖ModelBinderProvider,因此您的代码不会使用ModelBinderAttribute膨胀。 Jimmy Bogart article就此而言。此外,您将获得一些灵活性,因为您可以使用属性来声明模型是否使用严格绑定或自适应绑定。
总体而言,恕我直言,验证属性不会改变输入。他们应该验证它。模型粘合剂实际上负责将所有奇怪的东西转换成系统中可用的东西,而第三种方法复制模型粘合剂功能)
希望这对我的英语有帮助和抱歉)