我来这里是想听听您对我们迄今为止所采取的验证方法的看法。我们仍处于开发过程的早期,所以我们仍然可以改变它。验证对于这个应用程序和我们的客户来说非常重要,所以我们需要找到最优化的方法。让我描述一下我们到目前为止所做的事情......
我们正在构建这个应用程序,它将被不同的客户使用。我们不控制所有客户端,因此对所有层的验证都有严格的要求。我们确实控制了一些客户端应用程序,其中一个是大约 100 个用户使用的 WPF 应用程序。在此应用程序中,工作流程如下:
| Client | Backend Service |
ViewModel -> ClientRepository -> ServiceClient -> Service (WCF) -> ApplicationService -> DomainModel -> Repository -> Database
我们将以下内容视为执行验证的候选者。
- 客户端:ViewModel 验证,用于支持带有必填字段、长度等的 UI。
- 后端:服务请求 DTO 验证,因为我们不能依赖客户端始终提供 100% 有效值。
- 后端:域模型实体验证。我们不希望我们的实体最终处于无效状态,因此每个实体在执行操作时都会包含不同的检查。
- 后端:数据库验证,例如失败的约束(FK、唯一性、长度等)
客户端 ViewModel 验证非常明显,对于我们自己的客户端,应在到达服务之前纠正尽可能多的错误。但不能代表其他使用我们服务的应用程序,应该假设最坏的情况。
服务请求 DTO 应主要针对第三方应用程序和我们自己客户端中的错误进行验证。确保请求正确,可以防止稍后在处理请求时弹出错误,从而保证更有效的服务。与 ViewModel 验证一样,这归结为不同属性的必填字段、长度和格式(例如电子邮件)。
领域模型中的实体本身应该确保它们始终具有完全有效的属性/属性,我们就是这样实现的,以Customer
实体为例。
public class Customer : Entity
{
private Customer() : base() { }
public Customer(Guid id, string givenName, string surname)
: this(id, givenName, null, surname) { }
public Customer(Guid id, string givenName, string middleName, string surname)
: base(id)
{
if (string.IsNullOrWhiteSpace(givenName))
throw new ArgumentException(GenericErrors.StringNullOrEmpty, "givenName");
if (string.IsNullOrWhiteSpace(surname))
throw new ArgumentException(GenericErrors.StringNullOrEmpty, "surname");
GivenName = givenName.Trim();
Surname = surname.Trim();
if (!string.IsNullOrWhiteSpace(middleName))
MiddleName = middleName.Trim();
}
}
现在,虽然这确保了属性是有效的,但一个CustomerValidator
类作为一个整体验证了 Customer 类,确保它处于有效状态并且不仅具有有效的属性。这CustomerValidator
是使用 FluentValidation 框架实现的。它在将客户对象提交到数据库之前在应用程序服务中调用。
到目前为止,您如何看待我们的方法?
我有点担心的是,到处都在使用异常。例如ArgumentException
上面的示例,但InvalidOperationException
在调用对象当前状态中不允许的某些方法的情况下也是如此。
希望这些异常很少被抛出,因为服务请求 DTO 已经过验证,因此我认为它可能没问题?例如,当验证服务请求 DTO 时,绝不应引发参数异常,除非验证中的某处出现错误。因此,您可以说域模型中的这些参数检查充当了额外的安全层。InvalidOperationException
另一方面,如果客户端调用了一个服务方法,该服务方法调用了在其当前状态下不可用的 Customer 对象上的方法(因此它应该失败),则可以引发。
你怎么看?如果听起来一切正常,当出现故障时,如何通过 WCF 适当地通知用户?无论是ArgumentException
,InvalidOperationException
还是包含错误列表的异常(由 ApplicationService 在使用 CustomerValidator 类验证客户对象后抛出)。我是否应该以某种方式捕获所有这些异常并将它们转换为 WCF 抛出的一些一般错误异常,从而客户端可以对其做出反应并通知用户发生了什么?
我很想听听您对我们方法的看法。我们正在开始构建这个相当大的应用程序,我们真的想找到一种执行验证的好方法。在我们的应用程序中有一些非常关键的部分,其中数据的正确性非常重要,因此验证很重要!