我们在表示层(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抛出异常.我不太热衷于这种方法,因为我不想使用异常来处理我的业务逻辑.
还有更多想法来处理这种情况吗?
最佳答案 考虑:
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语句.