service - 将业务验证错误从服务层传递到表示层

标签 service exception presentation-layer

我们在表示层 (PL) 和基于 WCF 的服务层 (SL) 中使用 MVP 模式。 PL 在 SL 上调用操作合约,并在内部进行一些业务验证。如果验证通过,我们将一个对象(作为数据契约公开)返回给 PL。

但是如果验证失败,我们通知 PL 的最佳做法是什么。

Entity2 Operation1(Entity1 e)
{
 //Do some business validation and if passes pass on the updated object back to PL
}

一种方法是我们创建一个通用的响应类,它对于所有操作合约都是通用的。它看起来像这样。

public class Response
{
    public ExceptionType exceptionType;
    public ExceptionInfo exceptionInfo;

    Collection<Entity> entityCollection;
}

ExceptionType:这是一个枚举,用于说明是否发生了businessValidation 失败、SecurityValidation 或某些未知异常。

ExceptionInfo:这是一个枚举,它告诉发生的验证/异常的具体细节,如错误代码等。

集合:服务层可以返回单个实体或实体的集合。我们使用此属性根据要求返回一个或多个实体。如果验证失败或该方法不需要从服务层返回任何实体,它也可以为 null。

这是将验证失败传递给 PL 的好方法吗?

我认为这样做的缺点是 - PL 需要处理 exceptionInfo 中定义的所有情况,可能使用 switch case 并做必要的事情。

执行此操作的其他方法是,如果任何业务验证或安全验证失败,则向 PL 抛出异常。我不太喜欢这种方法,因为我不想使用异常来处理我的业务逻辑。

还有更多的想法来处理这种情况吗?

最佳答案

考虑:

How Do You Communicate Service Layer Messages/Errors to Higher Layers Using MVP?

我不知道如何在这里提供具体帮助。首先,我不太了解您的设置,也不了解有关 WCF 详细信息的任何信息。其次,我并没有真正得到关于不喜欢业务逻辑异常(exception)的评论......但我假设您的意思是“业务验证”,正如您在其他地方所说的那样(在这种情况下,这对我来说是有意义的)。

在我的无知中,看起来你已经开始了自己的计划,所以也许你有很多自由。当然,很多事情都可以发挥作用。因此,这里有一些替代方案:

沟通方式

您可以尝试一下您的方法,看看您是否喜欢它。 IMO,它混合了一些关注点来验证和一起操作(有时这是没有帮助的,特别是如果你开始询问如何处理故障)。撇开命令-查询不谈,这是一个经典的返回与抛出问题,在这个边界上,只要它有效,您就有权选择其中之一。

如果您有 MVP 的框架,您可能会看看它是否有内置的东西。

除此之外,您可以更改 PL/SL 关系以将验证与操作明确分开。就像这样:

IList<Error> Validate_Operation1(Entity1 a){}
Entity2 Operation1(Entity1 a){}

或者,疯狂一点:

public interface ICommand
{
    IList<Param> Params { set; }
    IList<Error> Validate();
    void Execute();
}

如果我坚决区分“验证错误”与“验证后错误”和“意外错误”,我可能会执行上述操作。由于请求验证而返回验证问题当然不是“异常(exception)”。

除此之外,您可能会考虑更抽象地了解要如何处理验证后错误。其中一些可能是用户可操作的,无论它们是否与业务相关。 “Datatraveler 似乎已损坏。请重新格式化拇指驱动器。”甚至是“未找到首选项,使用默认值完成”之类的警告。如果您的应用程序具有高度交互性,则您的闲聊 SL 可能会使用更通用的机制来发回验证问题。

沟通内容

老实说,我不认为您的 Response-class-with-error-enums-and-null-entities 与定义您自己的错误类或异常有什么不同。我并不热衷于像这样的“多用途”返回,但这种方法有一个案例:许多 EventArgs 或异步回调参数被实现为具有错误、取消和结果信息。

关于您列出的缺点,当您说“PL需要处理ExceptionInfo中定义的所有情况”时,我不确定错误层次结构有多宽,所以请原谅我在这里假设最坏的情况。您选择的载体(异常、纯字符串或 exceptionInfo 枚举)不会改变这样一个事实:如果您识别出 762 个不同的错误,您就识别出 762 个不同的错误。

但这并不意味着您的演示者需要明确考虑到每一个人。您已经获得了上下文的好处 - 您知道在用户已经登录并检查其抵押贷款余额后,您不会收到“用户名为空”的消息。 (如果您这样做,您可能应该将其视为“检查余额时出现意外错误。请稍后再试。”并记录调用堆栈,对吗?)

因此,您的演示者只需要知道适用于其上下文的较短列表,而不是全部。其他一切都是“意想不到的......”。

而且,由于您正在定义自己的 Error 类,因此您可能会考虑将错误放入字符串资源中,并在创建对象时将资源 ID 与特定错误联系起来。然后,不必单独处理这些情况,而是可以通过相同的操作来解决许多情况:获取 ID、加载字符串、显示字符串,完成。不需要 switch 语句。

关于service - 将业务验证错误从服务层传递到表示层,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1927838/

相关文章:

service - DDD 在存储库中使用服务

java - 如何处理 UsernameNotFoundException spring security

c - 纯 C 中的异常处理库

ios - 如何获得动画期间制作的最旧对象的位置?

c# - 轮询服务 - C#

android - 在android中显示来自后台服务的弹出窗口

android - 与来自服务的 Activity (LocalService) 进行通信 - Android 最佳实践

java - 包装第三方库时包装异常

ruby-on-rails - 将表示逻辑放在 Controller 中是 Ruby 中的一个好习惯吗?

CSS:固定布局还是 float 布局?