3

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

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

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

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

4

3 回答 3

6

您的业​​务层应该不了解上述各层。所以它不知道你在上面有一个 wcf 层。抛出错误是来自您的 wcf 层的东西,在那里捕获您的异常并决定您想要做什么。业务异常可以映射到 wcf 故障,但是如果您有空指针异常的连接,您只想给出一个错误的一般故障。

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

于 2013-10-21T16:21:02.257 回答
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"
                });
            }
        }
    }
}

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

于 2013-10-22T11:25:20.140 回答
2

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

同样,您应该保护外部世界免受域内可能出现的所有异常的影响。

恕我直言,您应该进行捕获域异常的工作,确定您想要(或不想要)公开的内容,并将其映射到 DTO 异常格式中的正确错误。例如,您可能不想在域外公开堆栈跟踪。

作为一般规则,我尝试只公开客户可以做某事的异常。如果数据库已关闭,那么客户端将如何处理它?所以,也许客户不需要那个SqlException,而是需要一个500 Internal Server Error.

于 2013-10-21T16:13:09.567 回答