如何将服务层验证消息传递回调用方?

Jos*_*osh 9 c# validation repository service-layer asp.net-mvc-3

我做了很多研究,包括SO,我似乎无法找到明确的方向.我目前有一个ASP.NET MVC3应用程序,其中一个服务层位于存储库之上.

在我的服务层,我有以下功能:

public class MyService{

    public void CreateDebitRequest(int userId, int cardId, decimal Amount, .... )
    {
    //perform some sort of validation on parameters, save to database
    }

    public void CreateCreditRequest(.....)
    }
        //perform some sort of validation on parameters, save to database
    }

    public void CreateBatchFile()
    {
        //construct a file using a semi-complex process which could fail
        //write the file to the server, which could fail
    }


    public PaymentTransaction ChargePaymentCard(int paymentCardId, decimal amount)
    {
        //validate customer is eligible for amount, call 3rd party payments api call,
        //...save to database, other potential failures, etc.
    }

}
Run Code Online (Sandbox Code Playgroud)

我见过有人说参数验证不是很特别,因此抛出异常并不合适.我也不喜欢传递一个out-paramater的想法,比如一个字符串,并检查一个空值.我考虑过实现ValidationDictionary类,并使其成为任何给定服务类的属性(它将包含一个IsValid布尔值和一个错误消息列表,并且可以在服务层中的任何给定函数调用之后检查,以查看如何事情发生了).运行任何给定的函数后,我可以检查ValidationDictionary状态:

var svc = new MyService();
svc.CreateBatchFile();
if (svc.ValidationDictionary.IsValid)
    //proceed
else
   //display values from svc.ValidationDictionary.Messages...
Run Code Online (Sandbox Code Playgroud)

我不喜欢这样的事情是我必须为每个服务层函数调用更新它,以避免它保留旧值(如果我选择不将它用于许多或大多数功能,人们仍然会期望它在运行任何给定函数后获得有意义或空值.我考虑的另一件事是为每个可能有详细验证信息的函数调用传递ValidationDictionary,但后来我又回到使用out参数...

你们中有人有推荐吗?我似乎无法弄清楚这样做的任何干净方式.有时为函数返回null是足够的信息,但有时我想将更多的验证信息传递回调用者.任何意见,将不胜感激!

编辑以澄清: 我的服务层不知道它是一个消耗它的MVC应用程序.服务层只有一些公共函数,如CreateBatchFile()或AddDebitRequest().有时返回null足以让消费者(在这种情况下是一个控制器,但可能是其他东西)知道发生了什么,有时消费者会想要来自服务层的更多信息(如果消费者是,则可能传递给ModelState)控制器).如何从服务层本身冒泡出来?

Cha*_*tes 9

这就是我的工作.有一个类用于验证,而不是传递参数传递视图模型.所以在你的情况下是这样的,其中ValidationResult只是一个带有MemberName和ErrorMessage属性的简单类:

public class DebitRequestValidator{

  public IEnumerable<ValidationResult> Validate(DebitRequestModel model){

    //do some validation
    yield return new ValidationResult {
      MemberName = "cardId",
      ErrorMessage = "Invalid CardId."
    }
  }  
Run Code Online (Sandbox Code Playgroud)

}

然后创建一个控制器扩展方法,将这些验证结果复制到模型状态.

public static class ControllerExtensions
{
    public static void AddModelErrors(this ModelStateDictionary modelState, IEnumerable<ValidationResult> validationResults)
    {
        if (validationResults == null) return;

        foreach (var validationResult in validationResults)
        {
            modelState.AddModelError(validationResult.MemberName, validationResult.ErrorMessage);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在你的控制器做类似的事情

[HttpPost]
public ActionResult DebitRequest(DebitRequestModel model) {
  var validator = new DebitRequestValidator();
  var results = validator.Validate(model);
  ModelState.AddModelErrors(results);
  if (!ModelState.IsValid)
    return View(model)

  //else do other stuff here
}
Run Code Online (Sandbox Code Playgroud)

然后在您的视图中,您可以显示正常的错误.

@Html.ValidationMessageFor(m => m.CardId)
Run Code Online (Sandbox Code Playgroud)


小智 1

我使用的系统传递一组消息(或类集合),每个元素都有代码、描述和友好消息。我们过去只是简单地检查是否有东西存在。它在 UI 和另一个“服务”层之间工作得很好,所有异常都被很好地捕获,它们被转换成这些验证规则......只是一个想法