We are looking into creating a new project and are wanting to explore using the Repository and Service layer patterns, the aim to is create loosely coupled code which is fully testable using mock repositories.
Please see below the basic architecture idea. We will be using interfaces to describe the repositories and inject these into the service layers to remove any dependencies. Then using autofac we will wire up the services at runtime.
public interface IOrderRepository
{
IQueryable<Order> GetAll();
}
public class OrderRepository : IOrderRepository
{
public IQueryable<Order> GetAll()
{
return new List<Order>().AsQueryable();
}
}
public class OrderService
{
private readonly IOrderRepository _orderRepository;
public OrderService(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}
public IQueryable<Order> GetAll()
{
return _orderRepository.GetAll();
}
}
public class EmailService
{
public void SendEmails()
{
// How do I call the GetAll method from the order serivce
// I need to inject into the orderService the repository to use
}
}
There are a few questions which we are having trouble finding out the best way forward.
1) Should the service be reproducing the CRUD methods, as it appears we may be reproducing code with no real benefit. Or should the UI call the repositories directly?
2) What happens when a service needs to call another service. In our example above if Email Service needs to get all the orders, do we inject the order service into the Email service?
Hope this makes sense
Email service should not be aware of services like OrderService, you need Mediator to work with both Email&&Order services so they would be decoupled, or Adapter to adapt IOrder
to IEmail
:
IEnumerable<IOrder> orders = orderService.GetAll();
// TODO: Create emails from orders by using OrderToEmailAdaptor
IEnumerable<IEmail> emails = ...
emailService.SendEmails(emails);
public sealed class EmailService
{
public void SendEmails(IEnumerable<IEmail> emails)
{
}
}
Mediator:
Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently
Adapter:
The adapter pattern (often referred to as the wrapper pattern or simply a wrapper) is a design pattern that translates one interface for a class into a compatible interface
Take a look at Domain Driven Design. DDD moves most of the logic into the entities (Order
, Email
) and lets them use the repositories.
1) Should the service be reproducing the CRUD methods, as it appears we may be reproducing code with no real benefit. Or should the UI call the repositories directly?
A service in DDD is used when you find yourself writing business logic outside the entities.
2) What happens when a service needs to call another service. In our example above if Email Service needs to get all the orders, do we inject the order service into the Email service?
Inject it in the constructor. However, the order service should send an email, not the other way around.
The DDD approach would be to create a OrderNotificationService
which takes the domain event OrderCreated
and composes an email which it sends through the EmailService
Update
You missunderstood me. Duplicated logic is never good. I would not put a method in my service named GetAll
when my repository has one. Neither would I put that method in my entity either.
Example code:
var order = repository.Create(userId);
order.Add(articleId, 2);
order.Save(); // uses the repository
Order.Send()
should create a domain event that the OrderNotificationService
can catch.
Update2
Repository.Create
is just a factory method (google factory method pattern
) to get all domain model creations in one place. It do not do anything in the db (although it could in future versions).
As for order.Save it would use the repository to save all order lines, the order itself or anything else that would be needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With