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

时间:2009-12-18 12:05:26

标签: service exception presentation-layer

我们在Presentation Layer(PL)和基于WCF的服务层(SL)中使用MVP模式。 PL在SL上调用操​​作合同,并在内部执行一些业务验证。如果验证通过,我们将一个obect(作为数据契约公开)返回给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:这是一个枚举,它告诉像errorCode等发生的验证/异常的具体细节。

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

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

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

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

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

1 个答案:

答案 0 :(得分:2)

考虑:

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

我不确定如何在这里特别提供帮助。首先,我并不真正了解您的设置,或了解有关WCF细节的任何信息。其次,我并没有真正得到关于不喜欢商业逻辑的例外的评论......但我假设你的意思是“业务验证”,正如你在其他地方所说的那样(在这种情况下,这对我来说很有意义)。

在我的无知中,看起来你已经开始了自己的计划,所以也许你有很多自由。当然,很多事情可以工作。所以,这里有一些选择:

沟通方法

您可以尝试自己的方法,看看您喜欢它。 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();
}

如果我将“验证错误”与“后验证错误”和“意外错误”区分开来,我可能会做到以上几点。由于要求验证而得到验证问题肯定不是“例外”。

除此之外,您可能会考虑更加抽象地了解您将对验证后错误做些什么。其中一些您可能是用户可操作的,无论他们是否与业务相关。 “Datatraveler似乎已损坏。请重新格式化thumbdrive。”甚至是“未找到首选项,默认情况下已完成”等警告。如果您的应用程序具有高度交互性,那么您的健谈SL可能会使用更通用的机制来发回验证问题。

沟通内容

老实说,我没有看到你的Response-class-with-error-enums-and-null-entities与定义你自己的错误类或异常的里程不同。我对这样的“多用途”回报并不大,但是这种方法有一个案例:实现了许多EventArgs或异步回调参数以获取错误,取消和结果信息。

关于你列出的缺点,当你说“PL需要处理exceptionInfo中定义的所有情况”时,我不确定错误层次结构有多广泛,所以原谅我在这里假设最坏的情况。您选择的工具(例外,普通字符串或exceptionInfo枚举)不会改变以下事实:如果您识别出762个不同的错误,则会识别762个不同的错误。

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

因此,您的演示者只需知道适用于其上下文的较短列表,而不是所有这些列表。其他一切都是“意外的......”。

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