4

我们在表示层(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:这是一个枚举,它告诉业务验证是否失败或安全验证或某些未知异常发生。

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

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

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

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

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

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

4

1 回答 1

2

考虑:

您如何使用 MVP 将服务层消息/错误传达给更高层?

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

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

沟通方式

你可能只是尝试你的方法,看看你喜欢它。国际海事组织,它在验证和操作方面有点混合关注(有时它无济于事,尤其是如果你开始询问如何处理故障)。Command-Query,抛开其他东西不谈,这是一个经典的 return-vs-throw 问题,在这个边界上,只要它有效,您就有权选择其中任何一个。

如果你的 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 出现损坏。请重新格式化拇指驱动器。” 甚至是“未找到首选项,使用默认值完成”之类的警告。如果您的应用程序具有高度交互性,您的健谈 SL 可能会使用更通用的机制来发回验证问题。

通讯内容

老实说,我不认为您的 Response-class-with-error-enums-and-null-entities 与定义您自己的错误类或异常相差甚远。我不喜欢这样的“多用途”返回,但这种方法有一个案例:许多 EventArgs 或异步回调 args 被实现为具有错误、取消和结果信息。

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

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

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

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

于 2009-12-29T21:36:57.617 回答