3
votes

I'm developing an MVC application, I'm using Unity for IoC. My Application basically consists of a UI layer, a services layer and a repository layer.

My typical controller is:

public class TestController : Controller
    {
        private ITestService testServ;

        public TestController(ITestService _testServ)
        {
            testServ= _testServ;
        }

    public ActionResult Index()
    {
        testServ.DoSomething();
        return View();
    }
}

Nothing out of the ordinary, each of my controllers has a service object injected. So of my service layer objects carry out complex business rules aggregating information from many different repositories. By using IoC I'm finding my constructors look overly complex, but as the service requires access to many repositories I cannot see any way around this.

A typical class in my service layer will look like:

public class TestService : ITestService
    {
        private ITransactionRepository transRepo;
        private IAccountRepository accountRepo;
        private ISystemsRepository sysRepo;
        private IScheduleRepository schRepo;
        private IProfileRepository profileRepo;

        public TestService(ITransactionRepository _transRepo;
                           IAccountRepository _accountRepo;
                           ISystemsRepository _sysRepo;
                           IScheduleRepository _schRepo;
                           IProfileRepository _profileRepo)
        {
            transRepo = _transRepo;
            accountRepo = _accountRepo;
            sysRepo = _sysRepo;
            schRepo = _schRepo;
            profileRepo = _profileRepo;
        }

        public DoSomething()
        {
            //Implement Business Logix
        }
    }

Several of my service layer object require 10 or more repositories. My repository sits is using Entity Framework where each repository class exposes a table in the underlying data store.

I'm looking for some advice on best practice in a situation like described.

2
Are looking for advice on IoC or on DI containers (Unity is the later)?Random Dev
BTW: if your "Service" has to many dependencies it probably does to much (the S in SOLID) - maybe you can split the Service itself into it's real responsibilities - most likely you can give the results some better name than Service too ;)Random Dev

2 Answers

3
votes

You have created a service layer so that it acts as a facade to the underlying repositories. This approach is a good practice to provide a facade to the client with a coarse API. The clients do not have to worry about underlying repositories.

The service themselves have now a complex constructor because of the way the DI is done. The other approach is to use an abstract factory pattern at the Service layer and do a setter injection. This complexity of newing up the repositories are moved into a separate class, a factory of its own. For example:

You may set the repositories of your test service as follows instead of a constructor

public class TestService : ITestService
{
    private ITransactionRepository transRepo = DataAccess.transRepo;
    private IAccountRepository accountRepo = DataAccess.accountRepo;
    private ISystemsRepository sysRepo = DataAccess.sysRepo;
    private IScheduleRepository schRepo = DataAccess.schRepo ;
    private IProfileRepository profileRepo = DataAccess.profileRepo;
}

Below is an example of an interface for factory

public interface IRepoFactory
{
    ITransactionRepository TransRepo {get;}
    IAccountRepository AccountRepo {get;}
    ISystemsRepository SysRepo {get;}
    IScheduleRepository SchRepo {get;}
    IProfileRepository ProfileRepo {get;}
}

Below is an example of a concrete factory that will new up all the repositories.

public class EfFactory : IRepoFactory

{

    public ITransactionRepositry TransRepo { return new TransactionRepository();}

    public IAccountRepository AccountRepo {return new AccountRepository();}

    public ISystemsRepository SysRepo {return new SystemRepository();}

    public IScheduleRepository SchRepo {return new SchRepository();}

    public IProfileRepository ProfileRepo {return new ProfileRepository();}

}

Below is a factory method that will return the concrete factory (in your case, it would be an EF Factory)

public class RepoFactories
{
    public static IRepoFactory GetFactory(string typeOfFactory)
    {
        return (IRepoFactory)Activator.CreateInstance(Type.GetTypetypeOfFactory)
    }
}

The abstract factory with static methods to new up and return the repository objects

//Example: factoryName = MyProject.Data.EFFactory ( This can be added in your web.config or app.config)

Public static class DataAccess
{
    private static readonly string DbfactoryName=   ConfigurationManager.AppSettings.Get("factoryName");
    private static readonly IRepoFactory factory = RepoFactories.GetFactory(DbfactoryName);

    public static ITransactionRepositry transRepo
    {
        get {return factory.TransRepo;}
    }
    public static IAccountRepository accountRepo
    {
        get {return factory.AccountRepo;}
    }
}
2
votes

Here are some steps to simplify (and decrease) dependencies:

  1. Split you service into separate services and inject them in your controller. That will decrease number of dependencies of services. The downside is that you'll need to inject more dependencies to your controllers. The next step is split controllers when they become complicated. Remember about Single Responsibility Principle.

  2. Take a look at Bounded Context pattern: you could try to group entities that often comes together in single context and inject that context into a service instead of injecting tens of repositories:

    public class TestService : ITestService
    {
        private readonly ITestData testData; // represents a bounded context
    
        public TestService(ITestData testData)
        {
            this.testData = testData;
        }
    
        public void DoSomething()
        {
            this.testData.Transactions.Add(...); //It gives you access to Transactions repository
        }
    }