【问题标题】:ASP.NET complex validation in business / service layer业务/服务层中的 ASP.NET 复杂验证
【发布时间】:2017-01-02 20:40:44
【问题描述】:

我问这个是因为经过长时间的搜索,我还没有找到一个好的答案......

这就是我想要的:

示例:我有一个域模型“JobPosting”,如果它仍然是草稿,用户应该能够将状态更改为已发布。在发布之前,我不仅必须验证模型属性,还必须验证关于用户帐户、注册公司等的许多不同要求。所有这些验证逻辑都放入服务层。到目前为止一切顺利...

这是我的服务层的样子:

public IValidationResult ValidatePublish(JobPosting jobPosting){
    ...
}

public void Publish(JobPosting jobPosting){
    jobPosting.State = JobPostingState.Published;
    ...
}

任何我的控制器:

public ActionResult Publish(PublishViewModel model){
    ...
    var validationResult = _jobService.ValidatePublish(jobPosting);
    if(validationResult.Success){
        _jobService.Publish(jobPosting);
        ...
    }
    ...
}

现在我的问题是:

我希望能够从控制器调用 ValidatePublish 以在视图中显示验证错误。但是,当验证失败时,我绝不能发布作业。 因此,为了让我的代码更健壮,我在服务层的 Publish 方法中添加了第二个验证检查:

public void Publish(JobPosting jobPosting){
    if(ValidatePublish(jobPosting).Success){
        jobPosting.State = JobPostingState.Published;
        ...
    }
}

但我对这种方法感觉不太好,因为现在在每个控制器发布请求期间验证正常时,我会调用两次验证。

你怎么看。第二个电话太多了吗?有更好的方法吗? 我问是因为我的整个应用程序看起来像那样,如果我忘记了控制器中的验证调用,我最终可能会在数据库中得到一个不允许的域模型状态。这就是我在每个服务方法中添加第二个验证检查的原因。

提前感谢您对此的看法!!!

【问题讨论】:

  • “我两次调用验证”你第二次调用验证在哪里?
  • 控制器中的第一次调用:var validationResult = _jobService.ValidatePublish(jobPosting);第二次在服务方法发布:if(ValidatePublish(jobPosting).Success){
  • 那你为什么要在方法中再次验证?您可以直接发布。

标签: asp.net asp.net-mvc validation service-layer business-logic-layer


【解决方案1】:

一种快速的解决方案可能是让Publisher 类需要JobPostingIValidationResult 对象作为参数。

public void Publish(JobPosting jobPosting, IValidationResult validation)
{
    if (validation.IsValid)
    {
        jobPosting.State = JobPostingState.Published;
        // other work here...
    }
}

然后您的Controller 可以调用Validator,接收IValidationResult 并在需要时将其传递回表示层。否则转给Publisher

public ActionResult Publish(PublishViewModel model)
{
    var validationResult = _jobService.ValidatePublish(jobPosting);
    if(validationResult.Success) _jobService.Publish(jobPosting, validationResult);
    else return View("error", validationResult);
}

编辑:

更简洁的解决方案可能是让Publisher 类返回PublishAttempt 结果。

public class PublishAttempt : IValidationResult
{
    public enum AttemptOutcome {get; set;}
}

public ActionResult Publish(PublishViewModel model)
{
    var attempt = _jobService.Publish(jobPosting);
    if (attempt.Success) return View("success");
    else return View("error", attempt.ValidationResults);
}

【讨论】:

  • 谢谢!是的,这也是一种方法......但我不喜欢它的是我可以传递任何验证结果实例......甚至可以创建一个始终有效的新空实例。
  • 哦,谢谢 :-) 是的,我喜欢这样...也许我将您的想法与我的最后一个答案结合起来 :-) 只是因为我需要仅调用验证方法的能力...例如当我想通过 ajax 调用服务验证以“实时”显示错误时
【解决方案2】:

我刚想到以下内容……你怎么看:

我将服务方法更改为:

public IValidationResult Publish(JobPosting jobPosting, bool validateOnly = false){
    var validationResult = ValidatePublish(jobPosting);
    if(validateOnly) return validationResult;

    jobPosting.State = JobPostingState.Published;
    ...
    return validationResult;
}        

然后在控制器中,我总是只调用 Publish 方法,不再调用额外的 ValidatePublish:

public ActionResult Publish(PublishViewModel model)
{
    var validationResult = _jobService.Publish(jobPosting);
    if(!validationResult.Success) return View("error", validationResult);
}

当我只需要简单的验证时,我会这样做

var validationResult = _jobService.Publish(jobPosting, true);

这样做可以吗? 还是正常的服务调用返回IValidationResult不好看?

【讨论】:

  • 或者你认为每个服务方法实现某种结果更好?
猜你喜欢
  • 2010-11-01
  • 1970-01-01
  • 2018-05-21
  • 2011-11-06
  • 2017-01-07
  • 2011-04-03
  • 2013-08-07
  • 2012-01-19
  • 1970-01-01
相关资源
最近更新 更多