如何在使用DTO时处理异常

时间:2013-10-18 20:30:29

标签: c# wcf dto

我有一个解决方案结构,其中契约(数据/服务等)与业务实体位于不同的项目中,我使用Automapper在第三个Service实现项目之间进行映射。

WCFProject.Service.BusinessLayer
WCFProject.Service.Contracts
WCFProject.Service.Impl

我的ServiceImpl引用了这两个其他项目,并且在这里完成了从DataContract到BusinessEntity的自动化,然后在BusinessEntity对象上调用了正确的方法

现在,我想添加一些FaultContracts,然后在我的业务逻辑中使用它们来抛出正确的异常。但是,如果我将它们添加到Contracts项目(这是理想的,因为我想将所有合同保持在一起),那么我需要BusinessLayer引用合同以在BusinessLayer中使用它们。如果可能的话,我想保持这些独立性,并且只处理这两层之间的DTO。这是我的一个有效的方法,我想让这两个项目保持独立吗?你也映射了例外吗?或者有更好的方法来解决这个问题。

3 个答案:

答案 0 :(得分:6)

您的商务图层应该没有上述图层的知识。所以它不知道你有一个wcf层在上面。投掷错误是来自你的wcf层,在那里捕捉你的例外和你想要做的事情。业务异常可以映射到wcf错误,但是如果你有一个nullpointer异常的连接,你只想给出一个错误的一般错误。

可以在此处找到服务行为中处理/映射错误的示例: WCF-Exception-Handling

答案 1 :(得分:3)

在您指定的问题中:

  

我想添加一些FaultContracts,然后在我的业务逻辑中使用它们来抛出正确的异常。

正如您所确定的那样 - 这引入了服务的公共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"
                });
            }
        }
    }
}

顺便说一句,值得仔细考虑您在客户端公开的故障契约以及当服务器端出现问题时客户端需要哪些信息。在服务上公开过多的例外信息可能会带来安全风险。

答案 2 :(得分:2)

如果您遇到创建DTO图层的麻烦,那么您可能希望保护外部世界免受域名内部工作的影响。

同样,您应该保护外部世界免受您域内可能发生的每一个异常。

恕我直言,您应该开始捕捉您的域异常,决定您想要(或不想要)暴露的内容,然后将它映射到DTO异常格式中的正确错误。例如,您可能不希望在域外公开堆栈跟踪。

作为一般规则,我尝试仅公开客户端可以执行某些操作的异常。如果数据库关闭,那么客户端将采取什么措施呢?因此,也许客户端不需要SqlException,而是需要500 Internal Server Error