W
W
WhiteNinja2017-02-22 15:35:26
ASP.NET
WhiteNinja, 2017-02-22 15:35:26

C#: How to properly organize services in Business Logic Layer using DI?

Good afternoon!
I ask to prompt how competently to organize interaction of services.
Let's say, for example, we have the following service structure:

public abstract class BaseService : IService
{
  protected readonly IUnitOfWork _uow;
  
  public BaseService(IUnitOfWork uow)
  {
    _uow = uow; 
  }
  
  // Other base protected & private methods
}

public class FooService : BaseService, IFooService
{
  public FooService(IUnitOfWork uow)  : base(uow) { }
  
  public void CreateFoo(FooDTO foo) 
  {
    // Вопрос как получить репозиторий для сущности Foo ?
    IRepository<Foo> rep = _uow.Getrepository<Foo>();
    // Но таким образом я получу, только Generic репозиторий, 
    // как получить "кастомный" репозиторий, например, IFooRepository?
        
    // Insert Foo entity
    _uow.Commit();
  }
}

public class BarService : BaseService, IBarService
{
  private readonly IFooService _fooService;
  
  public BarService(IUnitOfWork uow, IFooService fooService)  : base(uow) 
  { 
    _fooService = fooService;
  }
  
  public void CreateBar(BarDTO bar) 
  {
    // Insert Bar entity
    
    // После чего необходимо вызвать FooService.CreateFoo(fooDTO)
    _fooService.CreateFoo(new FooDTO()); // только для примера создается пустой FooDTO-объект
    // При этом действие должно выполниться одной транзакцией
    // т.е.  полчается, что _uow.Commit() в методе FooService.CreateFoo не должен сработать,
    // а должен сработать _uow.Commit для всех сущностей (и Bar и Foo) тот что ниже??
      
    _uow.Commit();
  }
}

Questions:
1) How to get a "custom" repository from _uow, for example IFooRepository or IBarRepository? If you connect DI in the constructor, then I don’t quite understand, because these repositories should be taken from the uow specified by the first parameter?
2) How to organize a transaction for BarService.CreateBar(...) ?
Grateful for any help!

Answer the question

In order to leave comments, you need to log in

2 answer(s)
V
Valery Abakumov, 2017-02-27
@Valeriy1991

1. BarService as a business service should not know about another business service, i.e. about FooService. If it comes to understanding that you need to call a method from FooService in BarService, then your FooService should become a lower-level component than the business service. For example, FooManager (remember all sorts of ***Manager from ASP.NET Identity). Then this FooManager can be used not only in BarService, but in some other ***Service. Architecturally, it will look like this: at the top is ***Service (business logic), below - ***Manager (also business logic), even lower - ***Repository (and this is already DAL).
2. Yes, there is a need to extend the Generic repository with a specific repository. But here it is necessary very wellthink about why we do it. Perhaps we are trying to attach part of the business logic to a specific repository? If so, then it is no longer a specific repository and not even a DAL layer component - it is a business logic layer component. Well, okay, let's say we realized that we still need an IFooRepository. I came across such a solution to this problem: a new property is added to IUnitOfWork:
And that's it. Initialization is done inside the UnitOfWork instance, like so:
and FooRepository is available to us "outside":
As a result, in BarService your code will look something like this:

public void CreateBar(BarDTO bar) 
{
    // Insert Bar entity
    
    _uow.FooRepository.CreateFoo(new FooDTO()); 

    _uow.Commit();
}

But I repeat. In your example, I have suspicions that the CreateFoo method should not belong to FooRepository, but to some component of the business logic level (but in the hierarchy it is not a business service). For example, FooManager or FooCreator of some kind (which is only responsible for creating an object). Remember the SRP principle.

H
heartdevil, 2017-02-22
@heartdevil

Like uof inject
To save one transaction, just do not call _uow.Commit() on CreateFoo, but call it after you have done all the manipulations with the entities. This can be achieved by passing an optional parameter to the CreateFoo method to specify whether to save or not save.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question