业务/服务层中的 ASP.NET 复杂验证

Posted

技术标签:

【中文标题】业务/服务层中的 ASP.NET 复杂验证【英文标题】:ASP.NET complex validation in business / service layer 【发布时间】: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) 那你为什么要在方法中再次验证?您可以直接发布。 【参考方案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不好看?

【讨论】:

或者你认为每个服务方法实现某种结果更好?

以上是关于业务/服务层中的 ASP.NET 复杂验证的主要内容,如果未能解决你的问题,请参考以下文章

根据 DTO、实体模型或其他东西验证服务层中的数据?

ASP.NET MVC IOC依赖注入之Autofac系列开篇

ASP.NET MVC IOC 之 Autofac

Java Server Faces:仅在业务逻辑层中进行验证

控制器或服务层中的 Spring MVC 验证?

ASP.NET MVC - 服务层 - 业务层 - 数据层 (EF) - SQL DB :: 数据传输?