如何处理使用 DTO 时的异常
本文关键字:DTO 异常 何处理 处理 | 更新日期: 2023-09-27 18:35:56
我有一个解决方案结构,其中合同(数据/服务等)与业务实体位于不同的项目中,并且我正在使用Automapper在第三个服务实现项目之间进行映射。
WCFProject.Service.BusinessLayer
WCFProject.Service.Contracts
WCFProject.Service.Impl
My ServiceImpl 引用了这两个其他项目,并且从 DataContract 到 BusinessEntity 的自动映射在这里完成,然后在 BusinessEntity 对象上调用正确的方法
现在,我想添加一些FaultContracts
,然后在业务逻辑中使用它们来引发正确的异常。但是,如果我将它们添加到合同项目中(这是理想的,因为我想将所有合同放在一起),那么我需要从业务层到合同的引用才能在业务层中使用它们。如果可能的话,我想保持这些独立,只处理这两层之间的 DTO。这是否是我想要保持两个项目独立的有效保证?你也映射异常吗?或者有没有更好的方法来解决这个问题。
您的业务层应该不知道上述层。因此,它不知道您顶部有一个 wcf 层。抛出错误是来自 wcf 层的东西,在那里捕获你的异常并决定你想要做什么。业务异常可以映射到 wcf 错误,但如果具有 nullpointer 异常的连接,则只想给出一个一般错误,指出某些错误。
可以在此处找到服务行为中的处理/映射错误示例:WCF 异常处理
在问题中,您指定:
我想添加一些错误合约,然后在我的业务逻辑中使用它们来抛出正确的异常。
正如您正确识别的那样 - 这在服务的公共 API(服务、数据和错误协定)和业务逻辑之间引入了耦合。 理想情况下,您的业务逻辑应该与服务调用的事实无关,因此对协定程序集的引用令人不安。
合约程序集应列出客户端对服务的公开可用信息:
namespace Contracts
{
[ServiceContract]
interface IMyService
{
[OperationContract]
[FaultContract(typeof(MyFaultContract))]
[FaultContract(typeof(AnotherFaultContract))]
void MyOperation();
}
[DataContract]
public class MyFaultContract
{
[DataMember]
public string Problem { get; set; }
}
[DataContract]
public class AnotherFaultContract
{
[DataMember]
public string Description { get; set; }
}
}
与软件开发中的许多问题一样,您的问题可以通过间接层来解决。 尽管您在问题中指定了什么 - 您不希望将业务逻辑耦合到合约程序集。 不这样做的好处是显而易见的 - 它允许公共合同和"内部"业务逻辑独立发展。
下面显示了一个示例,其中服务实现用于将协定耦合到业务逻辑。 业务层中的异常映射到返回给客户端的错误合同:
namespace Service
{
class MyService: IMyService
{
public void MyOperation()
{
try
{
var businessLogic = new BusinessLogic();
businessLogic.DoOperation();
}
catch (KeyNotFoundException)
{
throw new FaultException<MyFaultContract>(new MyFaultContract
{
Problem = "A key issue occurred in the service"
});
}
catch (Exception)
{
throw new FaultException<AnotherFaultContract>(new AnotherFaultContract
{
Description = "Something BAD happened in the service"
});
}
}
}
}
顺便说一句,值得仔细考虑您在客户端中公开的错误合同,以及当服务器端出现问题时客户端需要哪些信息。 公开太多有关服务异常的信息可能会带来安全风险。
如果您正在经历创建DTO层的麻烦,那么您可能希望保护外部世界免受域内部工作的影响。
同样,您应该保护外部世界免受域内可能出现的所有异常的影响。
恕我直言,您应该做捕获域异常的工作,决定您想要(或不希望)公开的内容,并将其映射到 DTO 异常格式中的正确错误。 例如,您可能不希望在域外部公开堆栈跟踪。
作为一般规则,我尝试只公开客户端可以处理的异常。 如果数据库关闭,那么客户端将如何处理它?所以,也许客户不需要那个SqlException
,而是需要一个500 Internal Server Error
。