2
\$\begingroup\$

I am developing an application using Asp.NET core with MVC framework. I would like to ask your opinion about whether I inject my repository in a good way into my business layer.

First of all, lets see my IRepository interface:

public interface IRepository<T>
{
    IEnumerable<T> GetAll();
    T Get(long id);
    void Insert(T entity);
    void Update(T entity);
    void Delete(T entity);
}

Lets see one of my service class:

public interface IContainersGridService
{
    IList<ContainerGridViewModel> GetGridViewModels(string searchText);
}

public class ContainersGridService : IContainersGridService
{
    private readonly IRepository<Container> _containersRepository; //TODO: when write test, test when throws same db exception
    private readonly IContainerGridViewModelsGetter _containerGridViewModelsGetter;

    public ContainersGridService(IRepository<Container> containersRepository, IContainerGridViewModelsGetter containerGridViewModelsGetter)
    {
        _containersRepository = containersRepository;
        _containerGridViewModelsGetter = containerGridViewModelsGetter;
    }

    public IList<ContainerGridViewModel> GetGridViewModels(string searchText)
    {
        var containers = _containersRepository.GetAll();
        return _containerGridViewModelsGetter.Get(containers, searchText);
    }
}

As you can see I have an IRepository interface with the basic CRUD method signatures. I also have a ContainersGridService which is responsible to get some containers (domain: dump containers) from the database.

Furthermore, I have an ContainersGridService injected which is responsible for mapping and sorting the data coming from the database:

public interface IContainerGridViewModelsGetter
{
    IList<ContainerGridViewModel> Get(IEnumerable<Container> containers, string searchText);
}

public class ContainerGridViewModelsGetter : IContainerGridViewModelsGetter
{
    private readonly IContainerMappingService<ContainerGridViewModel> _containerMappingService;
    private readonly IContainersGridGlobalSearcher _containersGridGlobalSearcher;

    public ContainerGridViewModelsGetter(IContainerMappingService<ContainerGridViewModel> containerContainerMappingService, IContainersGridGlobalSearcher containersGridGlobalSearcher)
    {
        _containerMappingService = containerContainerMappingService;
        _containersGridGlobalSearcher = containersGridGlobalSearcher;
    }

    public IList<ContainerGridViewModel> Get(IEnumerable<Container> containers, string searchText)
    {
        var containerGridViewModels = GetContainerGridViewModels(GetSortedContainers(containers));

        return _containersGridGlobalSearcher.Search(containerGridViewModels,searchText);
    }

    private List<ContainerGridViewModel> GetContainerGridViewModels(IEnumerable<Container> sortedContainers)
    {
        return sortedContainers
            .Select(c => _containerMappingService.Map(c))
            .ToList();
    }

    private IEnumerable<Container> GetSortedContainers(IEnumerable<Container> containers)
    {
        return containers.OrderBy(c => c.DesiredTakeUpDate);
    }
}

As you can see, I have injected two additional (one mapping and one searching) logic class here. At this point I am wondering if it is the best way to implement my business layer like this, with the repository.

First I wanted to inject my repository into the ContainerGridViewModelsGetter but later I realized that it is (maybe) better if I separate the my repository from this logic class and I only pass an IList to my ContainerGridViewModelsGetter.Get(...) method. Using this way, I separated the data from this class, so the corresponding tests are also cleaner and clearer.

My questions are the following: Is it a good way to inject my repository to my service layer? Or maybe I would have injected the IRepository into my ContainerGridViewModelsGetter? Maybe do you have any other remarks regarding my code generally?

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

Injecting Repositories or anything else into the business layer is an overall bad idea. You business layer should be free from framework mechanisms. You will pollute your most important parts with unneccessary complexity.

What you can do is to place DI in certain objects that will initialize the dependencies around your business layer. So you may use a "RepositoryProvider" as an DI dependent artefact that will initialize a "RepositoryRegistry" which is DI independent and is used by the business layer.

Keep your your business layer clean.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks for you answer! And sorry for the late reply, I was on vacation...I agree with you that I should keep my business layer clean. But to be honest the solution you mentioned seems complex for me, and unfortunately I can not reproduce it :( Would you be so kind as to give me some code example, or a nice link/article where I could learn more about these approaching? I would appreciate it , thanks in advance! \$\endgroup\$
    – mirind4
    Commented Aug 12, 2017 at 11:43
  • 1
    \$\begingroup\$ "DI dependent artefact" - exactly what is that? DI/IoC (done right) isn't a dependency, it's a design pattern. If your "DI" code is aware of your IoC framework, you're Doing It Wrong™. \$\endgroup\$ Commented Sep 26, 2017 at 19:36
1
\$\begingroup\$

Your repository implementation is fine. However normally in a service I deal with Business/Domain objects only. I wouldn't return a viewmodel there. I would only return a domain object. Let your presentation layer (if there is any) handle mapping from a domain object to a view model. If it's MVC/Web API do it in the controller. The viewmodel class only lives in the view project.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for your reply! You are absolutely right, I should decouple the view-relevant stuffs from my business layer! Good point, thanks again ;) \$\endgroup\$
    – mirind4
    Commented Aug 12, 2017 at 11:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.