DTO和服务之间的通话

时间:2013-07-31 12:24:03

标签: c# architecture dto service-layer

假设我的服务层ServiceAServiceB中有两项服务,每项服务都有一个界面(分别为IServiceAIServiceB)。

UI层仅引用从其方法返回 DTO 的服务接口。具体的服务类负责将域模型(EF POCO)映射到DTO。

ServiceA通过依赖注入使用IoC容器依赖于IServiceB,以便在该服务上调用某些方法。

这样做会产生一些问题:

  1. 与DTO之间的不必要/重复映射只是为了调用方法和/或使用结果。

  2. 将调用方法与调用方法输入参数和返回类型的DTO契约紧密耦合。

  3. 最初我想将逻辑重构为内部方法并从两个服务中调用它。但是,由于ServiceA依赖于接口IServiceB,因此不会公开内部方法。

    你将如何处理这个问题?

    更多信息 (根据要求添加了示例代码):

    // This is the domain model
    public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
    // This is a dto for the domain model
    public class CustomerDto
    {
        public string Name { get; set; }
    }
    
    // Interface for ServiceA
    public interface IServiceA
    {
        void AddCustomer();
    }
    
    // ServiceA
    public class ServiceA : IServiceA
    {
        private readonly IServiceB _serviceB;
    
        // ServiceA takes in an IServiceB as a dependency
        public ServiceA(IServiceB serviceB)
        {
            _serviceB = serviceB;
        }
    
        public void AddCustomer()
        {
            var entity = new Customer();
    
            // !! This is the key part !!
    
            // I have to map to a dto in order to call the method on ServiceB.
            // This is a VERY simple example but this unnecessary mapping 
            // keeps cropping up throughout the service layer whenever
            // I want to make calls between services.
    
            var dto = Mapper.CreateFrom<CustomerDto>(entity);
    
            _serviceB.DoSomethingElseWithACustomer(dto);
        }
    }
    
    // Interface for ServiceB
    public interface IServiceB
    {
        void DoSomethingElseWithACustomer(CustomerDto customer);
    }
    
    // ServiceB
    public class ServiceB : IServiceB
    {
        public void DoSomethingElseWithACustomer(CustomerDto customer)
        {
            // Some logic here
        }
    }
    

3 个答案:

答案 0 :(得分:2)

关于到DTO的不必要映射:考虑使用Data Access ObjectsRepositories if you prefer Domain Driven Design来访问数据库。因此,您可以在服务层下面使用一种“实用程序层”,直接使用映射(实体)对象。

关于耦合的类型:ServiceB可以实现多个接口,尤其是只在服务器端可见的接口。 ServiceA可能依赖于该接口来访问不适合向客户端发布的ServiceB的更多内部部分。

答案 1 :(得分:2)

我们基本上最终有两种选择来处理我们的情景。

  1. 将现有服务层拆分为两个独立的层:

    • 仅处理域模型并允许进行服务间调用而无需dto映射的业务逻辑层。

    • “消息/服务”层,全权负责按摩业务逻辑层中的数据,以供客户使用。

  2. 根据@oddparity的建议,为每项服务提供公共和另一个内部接口。实现的公共接口方法调用内部方法。

  3. 我们选择使用选项2作为创建另一层抽象似乎是许多额外的开发人员工作,特别是当只有某些服务需要服务间调用时。

    因此,我们只需为那些需要它们的服务创建内部接口。

    这个article概述了分层架构,与我们的解决方案非常相似。

答案 2 :(得分:0)

如果我理解正确,可以通过将域对象而不是DTO传递到您的服务来解决这两个问题。通过这种方式,您可以避免不必要的映射,如果由于任何原因您必须更改应用程序接口/合同,您的服务可能保持不变。

恕我直言,DTO域映射应该只在您的应用程序的边界发生。例如,DTO到域映射应该是你的[控制器动作|的第一件事事件处理程序] do和域到DTO映射应该是返回结果之前的最后一个。

希望它有所帮助。