【问题标题】:asp.net mvc fix (correcting) data before each action. Perform in Model or Controller?asp.net mvc 在每个操作之前修复(更正)数据。在模型或控制器中执行?
【发布时间】:2012-11-11 03:47:47
【问题描述】:

我正在开发带有步骤(控制器)的向导,并使用从 BaseModel 继承的 DerivedModel1DerivedModel2 等,并使用额外的属性对其进行扩展。 模型——只有数据,没有业务逻辑。控制器操作中服务执行的所有逻辑,例如 _step1Service.GetRelated(model.id)。

现在我不仅要验证模型(对于这种情况,有 ValidationAttribute),还要修复 BaseModel 中的无效数据:

 public class BaseModel
 {
     public DateTime StartDate {get;set;}
 }

StartDate 应该大于今天。用户可以选择无效日期,而不是验证错误应用程序应该修复此值(重置为默认值?)。

在我的第一次尝试中,我添加了用于验证/纠正 StartDate 的服务并调用每个操作:

public ActionResult Index(DerivedModel1 model)
{
_svc.fixModel(model);

if(!ModelState.IsValid)
{
return View();
}

... do stuff with valid data
}

但不喜欢这样,因为必须将此行添加到每个控制器和操作。 然后我将此更正添加到StartDate setter。它看起来更好,但这打破了流行的 MVC 范式,即所有逻辑都应该在控制器中(或者我可能误解了什么?) 我在考虑这个问题的可能解决方案:ActionFilterAttribute, custom ModelBinder?但不确定这种方法是否正确以及是否有效。 你怎么看?

【问题讨论】:

  • 如果您要允许对诸如StartDate 之类的数据进行松散验证,为什么不呢?与其默认任意值或做出假设,不如在整个模型中允许空值(例如,将 StartDate 设为 @ 987654332@ 并在您的数据库中对此进行调整。我宁愿知道我没有数据也不愿拥有没有意义/没有可信度的有效数据?
  • 可能存在fixModel 不应该修复的另一个验证规则(取决于另一个输入。重要的是用户自己更正数据)。 StartDate 不能为空,它是向导中的主要选项。此字段有 javascript 验证,因此用户不能选择无效日期,但我还想在服务器端添加验证。

标签: asp.net-mvc model-view-controller architecture


【解决方案1】:

验证和业务规则之间存在差异。对象可以(并且通常应该)负责确保它们自身处于有效状态。

【讨论】:

  • 是的,我可以为模型验证添加验证属性。但也想将无效值重置为有效 - 这是业务规则吗?
【解决方案2】:

您必须实现 IModelBinder 才能实现这一点。

首先像这样定义您的自定义模型绑定器:

public class MyCustomModelBinder : IModelBinder
{
   public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            // Get the raw attempted value from the value provider
            DateTime incomingDate = (DateTime) bindingContext.ValueProvider.GetValue("datefield").AttemptedValue;
            //validate and correct date here ...
            return new BaseModel{ DateMember =  incomingDate };
        }
}

然后注册您的自定义模型绑定器,例如:

protected void Application_Start()
{
       ModelBinders.Binders.Add(typeof (BaseModel), new MyCustomModelBinder());          
}

和你的控制器:

public ActionResult YourAction([ModelBinder(typeof(MyCustomModelBinder )] BaseModel model)
{
      return Content("Ok");
}

【讨论】:

  • 所以我必须为 DerivedModel1 和 DerivedModel2 添加ModelBinders?还是根据 binder 中的规则创建派生模型,然后付诸实施?
  • 这取决于你。你可以做任何一种方式。
猜你喜欢
  • 1970-01-01
  • 2014-12-05
  • 1970-01-01
  • 1970-01-01
  • 2010-12-01
  • 2023-03-07
  • 2019-09-14
  • 1970-01-01
  • 2016-01-26
相关资源
最近更新 更多