C# 处理数据错误和警告而不是异常的最佳实践是什么

C# What is best practise for handling Data Errors and Warnings as opposed to Exceptions

我们正在创建一个新的 .Net Core 库,这是一个驻留在 Clean Architecture 中的应用程序服务。

新服务将通过 RepositoryService 层读取新客户详细信息,并通过 RestApiService 层 Post 将它们读取到多个系统,包括:CreditCheck 系统、计费系统等。

在新的应用程序服务中,我们需要一种一致的方式来处理来自 RestAPI 服务的响应。响应数据包括:

- Return values:  entities returned by restAPI service 

 - Exceptions like an error 500, time outs.. that have bubbled up from the RestAPi. 

- Data Errors messages such as Customer already exists, bank details invalid

- Warning messages ... "Processing continues as normal, but order is flagged" 

foxing 我们是最后两个,因为这不同于与没有业务逻辑的 Repository 层的交互,所以基本上 return 是成功或异常。

Microsoft 和 SOLID 实际上声明使用异常处理是可行的方法,无论是异常、错误还是警告。

但在这种情况下不清楚这将如何工作..

  a. We loose the option of handling and forwarding on the return values. 
     We really don't fancy storing all this in the exception message

   - Whilst not a show stopper, we fear the code will be more difficult to read than it needs to be.    

   - Exception handling is expensive,but not worried too much on this score with number of transactions. 

我们被吸引到一些如何使用 FluentValidation 或混合版本,它需要与 Logging 和 RepositoryService 一起工作,因为我们需要记录和解码东西。

我们真的不想重复 RestAPI 服务层方法,即单独处理 HTTP 异常,然后处理 return 值,这些值基本上是具有错误状态、错误代码和消息的扩展实体。

我们不希望以上内容是我们公司特有的。问题似乎与处理来自应用程序服务中的第三方业务逻辑层的消息有关。

所以我们的问题是我们如何才能最好地处理应用程序服务层中附带数据的错误警告,并且仍然有 SOLID 可测试和可维护的代码?

Microsoft 和 SOLID 是对的。

正确的做法是根据标准实践(和 c#)排除异常,独立于其他考虑因素,例如性能。

一般来说,有两种不同类型的 "Errors"、技术和业务逻辑相关。

无法连接到数据库、从 REST 服务接收到 500 等...都是技术性的,因为它们可能是暂时的,您可以尝试从这种情况中恢复,有时不成功,最终导致业务Orchestration/Process失败。

业务逻辑错误,如 'Customer already exists'、'Bank details invalid'、'Input data is not in the valid format' 是非暂时性的,并且完全由业务规则(一些隐式的,其他的显式的)决定,并且会停止停止你的进程也没有恢复的可能性,仅仅是因为某些东西不在 proper/expected 状态。

我们使用异常(作为技术工件)是为了处理这些硬停止 'properly'。

每次您抛出异常时,应用程序都会遍历堆栈,直到第一个能够处理此类异常的可用异常处理程序,return将控制权交给您和某个已知位置(遥测、重新抛出、向用户显示对话框...)

任何试图替代这种传播(错误)的机制都必须依赖,例如,劫持方法的 return 值来提供回状态,或者强行在所有方法签名中包含一个 out 参数,这将对您的实施产生可怕的附带影响。

是的,有时您当前的设计看起来 'too flat' 您很想在各处劫持 return 值,从而创建一个高度耦合的组件,但您永远无法判断系统的复杂性如何增长,这意味着在某些时候你会用额外的层扩展你的系统,并且很可能 'substituting mechanism' 方法不适合,你被迫支持它们,常规方式和富有想象力的方式。

因此,尝试实施自定义解决方案将产生必须全面支持的紧密耦合的技术要求,在架构术语中只是 'not good'(不是好的做法)

如果您使用的任何服务无法产生有意义的 'error' 结构良好的信息,那么服务设计不佳,问题就会转移到客户端(用 SOA 术语来说) ).

唯一 'most correct' 不给您的客户端带来混乱的解决方案是根据您的实施方法所需的规则创建服务代理。

我关于错误处理的建议非常简单,坚持众所周知并且已经存在了几十年的规则,不要自己尝试解决这个问题,否则你将面临太多问题,创建一个代理每项服务并将它们正确集成到您的代码库中(单元测试等)

关于警告,没有任何人建议使用异常来处理这个问题,你问题中的那些 'warnings' 是与 Service/a 支持的逻辑状态交互时的正常输出业务逻辑,因此,处理这种状态的地方是在从服务返回的数据契约中,同样,如果服务设计得太糟糕以至于只用包含单词 'warning' 的文本字符串回复你,并且您被迫解析此字符串以注意到这种情况,然后您的服务代理应该检查它并向客户端提供有意义且结构良好的输出。