Rie*_*edi 1 dto automapper service-layer clean-architecture asp.net-core-webapi
我构建了一个具有干净架构的 asp.net core Web api,我的层是:
在我的 Web API 中,我从外部 Exchange Web 服务加载数据。我想为我的客户提供我自己的 Web API。
为此,我在数据层实现了一个存储库,该存储库从外部 Web 服务获取数据作为 Class 的对象Appointment。
在服务层,我使用 AutoMapper 将对象映射到我自己的类EventDTO。
现在我不知道从 Web API 控制器访问这些数据的最佳实践是什么。
在我看来,当遵循干净的架构原则时,我必须EventDTO将EventEntity. 但是当我这样做时,我有两个 100% 相同的对象,因为没有逻辑,EventEntity并且我做了两次相同的映射。那没有意义?!?
但是当我将直接传递EventDTO给控制器时,它会打破干净架构的原则吗?
namespace Example.API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class EventController : ControllerBase
{
private readonly IEventService eventService;
public EventController (IEventService eventService)
{
this.eventService = eventService ?? throw new ArgumentNullException(nameof(eventService));
}
[HttpGet]
public async Task<IActionResult> LoadEventsAsync()
{
IEnumerable<EventDTO> items = await eventService.GetEvents();
return Ok(items);
}
}
}
Run Code Online (Sandbox Code Playgroud)
namespace Example.Core.Application.Services
{
public class EventService: IEventService
{
private IEventRepository eventRepository;
private IMapper mapper;
public EventService(IEventRepository eventRepository, IMapper mapper)
{
this.eventRepository= eventRepository;
this.mapper = mapper;
}
public async Task<IEnumerable<EventDTO>> GetEvents()
{
var appointments = await eventRepository.GetAppointments();
return mapper.Map<IEnumerable<EventDTO>>(appointments);
}
}
}
Run Code Online (Sandbox Code Playgroud)
namespace Example.Infrastructure.Repository
{
public class EventRepository : IEventRepository
{
private ExchangeService _exchangeService;
public EventRepository()
{
_exchangeService = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
_exchangeService.Credentials = new WebCredentials("user", "passwort", "domain");
_exchangeService.Url = new Uri("https://example.de/Exchange.asmx");
}
async Task<IEnumerable<Appointment>> IEventRepository.GetAppointments()
{
CalendarFolder calendar = await CalendarFolder.Bind(
_exchangeService,
new FolderId
(
WellKnownFolderName.Calendar,
"user@example.de"
)
);
return await calendar.FindAppointments(
new CalendarView()
);
}
}
}
Run Code Online (Sandbox Code Playgroud)
namespace Example.Core.Application.DTO
{
public class EventDTO
{
public string Subject { get; set; }
public bool Cancelled { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
}
Run Code Online (Sandbox Code Playgroud)
namespace Example.Core.Entities
{
public class EventEntity
{
public string Subject { get; set; }
public bool Cancelled { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
}
Run Code Online (Sandbox Code Playgroud)
也许有人已经实施了类似的项目。并且可以给我一个方法。
这取决于项目及其复杂性。如果它是一个短期项目、原型或简单项目,请务必继续重用 DTO 来为客户端提供数据。
如果您的目标是长期可维护性,那么请始终映射到端点的不同实体,因为最终请求的数据的形状会发生变化;您可能需要组合两个或多个 DTO,您可能需要添加几个特定于 UI 的属性(例如,切换组件或存储当前过滤器/搜索词等)。此外,如果您为两个不同的端点重复使用单个 DTO,这意味着向其中一个端点添加数据将会污染另一个端点,这也意味着当一个端点不再需要某些数据时,您无法自由修改 DTO (如果每个端点都有单独的实体,则可以根据端点要求轻松更改它们)。
由于您已经在使用 AutoMapper,因此一对一映射不需要特殊配置,因此在执行其他实体映射时不会引入复杂性。
我参与过许多项目,这些项目实现了这两种方法中的一种(或两种方法的混合),其中控制器实体只是 DTO 的包装器,这比直接使用 DTO 更糟糕,因为它们增加了类的数量,但没有附加值端点仍然与 DTO 紧密耦合),最容易处理的问题是为每个端点使用单独的实体,永远不要重用 DTO,并且永远不要重用实体,即不要将实体彼此组合;每个端点都有自己的实体,如果另一个端点需要类似的数据,它会获得不同的实体。
| 归档时间: |
|
| 查看次数: |
5460 次 |
| 最近记录: |