简体   繁体   中英

Clean/onion architecture in .NET core question

I have a few questions regarding clean/onion architecture. I've been reading the Microsoft docs and it states that the application core is in the center and the outer layers point inwards in terms of "dependencies". 在此处输入图像描述

What exactly do they mean when it depends on in this context? When I think of dependencies, I think of class B is getting instantiated inside of class A therefore class A depends on class B. However, when I take a look at the eShopOnWeb repo ( https://github.com/dotnet-architecture/eShopOnWeb ), it looks like the architecture core has repos that are being implemented the infrastructure as dependencies, isn't this contradictory?

A depends on B in this context means: A "knows" about B.

Types of the inner circles can be used by types of the outer circles but not vice versa.

Pls also refer to: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

...it looks like the architecture core has repos that are being implemented the infrastructure as dependencies, isn't this contradictory?

The thing that you are missing here is the use of interfaces . Let's take at the OrderService from the Application Core layer:

namespace Microsoft.eShopWeb.ApplicationCore.Services
{
    public class OrderService : IOrderService
    {
        private readonly IAsyncRepository<Order> _orderRepository;
        private readonly IUriComposer _uriComposer;
        private readonly IAsyncRepository<Basket> _basketRepository;
        private readonly IAsyncRepository<CatalogItem> _itemRepository;

        public OrderService(IAsyncRepository<Basket> basketRepository,
            IAsyncRepository<CatalogItem> itemRepository,
            IAsyncRepository<Order> orderRepository,
            IUriComposer uriComposer)
        {
            _orderRepository = orderRepository;
            _uriComposer = uriComposer;
            _basketRepository = basketRepository;
            _itemRepository = itemRepository;
        }

        public async Task CreateOrderAsync(int basketId, Address shippingAddress)
        {
            var basketSpec = new BasketWithItemsSpecification(basketId);
            var basket = await _basketRepository.FirstOrDefaultAsync(basketSpec);

            Guard.Against.NullBasket(basketId, basket);
            Guard.Against.EmptyBasketOnCheckout(basket.Items);

            var catalogItemsSpecification = new CatalogItemsSpecification(basket.Items.Select(item => item.CatalogItemId).ToArray());
            var catalogItems = await _itemRepository.ListAsync(catalogItemsSpecification);

            var items = basket.Items.Select(basketItem =>
            {
                var catalogItem = catalogItems.First(c => c.Id == basketItem.CatalogItemId);
                var itemOrdered = new CatalogItemOrdered(catalogItem.Id, catalogItem.Name, _uriComposer.ComposePicUri(catalogItem.PictureUri));
                var orderItem = new OrderItem(itemOrdered, basketItem.UnitPrice, basketItem.Quantity);
                return orderItem;
            }).ToList();

            var order = new Order(basket.BuyerId, shippingAddress, items);

            await _orderRepository.AddAsync(order);
        }
    }
}

The OrderService which is defined in the Application Core only has dependencies to interfaces which are also defined in the Application Core.

For instance there is

private readonly IAsyncRepository<Order> _orderRepository;

which is injected into the constructor of OrderService.

The implementation of the OrderRepository is defined in the infrastructure layer :

namespace Microsoft.eShopWeb.Infrastructure.Data
{
    public class OrderRepository : EfRepository<Order>, IOrderRepository
    {
        public OrderRepository(CatalogContext dbContext) : base(dbContext)
        {
        }

        public Task<Order> GetByIdWithItemsAsync(int id)
        {
            return _dbContext.Orders
                .Include(o => o.OrderItems)
                .Include($"{nameof(Order.OrderItems)}.{nameof(OrderItem.ItemOrdered)}")
                .FirstOrDefaultAsync(x => x.Id == id);
        }
    }
}

The infrastructure class OrderRepository follows the IOrderInterface contract defined in the Application Core layer. The IOrderRepository again is derived from IAsyncRepository which is also defined in the Application Core layer.

I guess the reason why they use IAsyncRepository rather than IOrderRepository in the OrderService is that by now the OrderService method only accesses methods defined by the base interface IAsyncRepository.

But the idea remains the same: everything in the Application Core layer shall only have dependencies to stuff from the same layer . The concrete implementations are than injected at runtime via dependency injection. But the Application Core layer itself does never have to know anything about the "real" implementation residing in the infrastructure layer.

And if you follow this approach the statement

...the application core is in the center and the outer layers point inwards in terms of "dependencies".

remains true as outer layers are dependent on classes and interfaces from Application Core and Application Core only depends on - Application Core.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM