HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

IoC Agnostic Test Project

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
projectioctestagnostic

Problem

I've been reading a lot about IoC and DI and I still haven't understood if it's a bad practice to make your Application IoC agnostic, but seems only logical to me that it should be IoC agnostic.

Using a 4 layer approach I've coded a test project just to try and apply these concepts and this is what a came up with:

Data Layer with EF 6.1.3

UnitOfWork:

using TestProject.Persistence.Contracts;

namespace TestProject.Core
{
    public class UnitOfWork : IUnitOfWork
    {
        private readonly IContext _context;

        public IRepo Customers { get; set; }
        public IRepo MembershipsTypes { get; set; }
        public IRepo Movies { get; set; }
        public IRepo Genres { get; set; }

        public UnitOfWork(
            IContext context,
            IRepo customers,
            IRepo membershipsTypes,
            IRepo movies,
            IRepo genres)
        {
            _context = context;
            Customers = customers;
            MembershipsTypes = membershipsTypes;
            Movies = movies;
            Genres = genres;
        }

        public int Complete()
        {
            return _context.SaveChanges();
        }

        public void Dispose()
        {
            _context.Dispose();
            GC.SuppressFinalize(this);
        }
    }
}


Repo(generic):

```
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using TestProject.Core.Contracts;
using TestProject.Core.Contracts.Repos;
using TestProject.Persistence.Contracts;

namespace TestProject.Persistence.Repos
{
public class Repo : IRepo where TEntity : class
{
protected readonly DbSet _entities;

public Repo(IContext context) => _entities = context.Set();

public void Add(TEntity entity) => _entities.Add(entity);

public IEnumerable Find(Expression> predicate)
{
return _entities.Where(predicate).ToList();
}

public TEntity

Solution

Do not tie up too many classes with DI if you want code to loosely coupled with Container.

Instead, Why not have your own registration & resolver object. This way you will have to change only three classes (in given example) when you wish to change the DI container.

public interface IContainerRegister
{
        void Register() where TService : class, TInterface;
        // not required, I needed though for WCF
        IResolver GetResolver();
}
public interface IResolver
{
    TService GetService();
}
internal class Resolver : IResolver
{
    // change to your container choice
    private readonly IUnityContainer _diContainer;

    public Resolver(IUnityContainer DIContainer)
    {
        _diContainer = DIContainer;
    }

    public TService GetService()
    {
        return _diContainer.Resolve();
    }
}
internal class ContainerRegister : IContainerRegister
{
    // change to your container choice
    private readonly IUnityContainer _diContainer;

    public ContainerRegister(IUnityContainer diContainer)
    {
        _diContainer = diContainer;
    }

    public void Register() where TService : class, TInterface
    {
        // change according to your container choice
        _diContainer.RegisterType();
    }

    public IResolver GetResolver()
    {
         // change according to your container choice
        return _diContainer.Resolve();
    }
}
internal class BootStrap
{
    // change to your container choice
    private UnityContainer _container = null;

    public IContainerRegister Init()
    {
        _container = new UnityContainer();
        _container.LoadConfiguration();
        _container.RegisterInstance(_container);

        _container.RegisterType();
        _container.RegisterType();
        // register your modules here using reflection
        // resolve each modules and call register()
        return _container.Resolve();
    }
}
public abstract class BaseModule {
    public BaseModule(IContainerRegister register){
        _register = register;
    }
    public abstract void Register();
}


Keep all these classes in one assembly and call bootstrap from starting of the application, and inject register class when you need to use modules.

This way you can keep all your code indepndent of DI, and only one assembly needs to be changed.

You may need to expose more methods for different types of registrations and resolution.

Code Snippets

public interface IContainerRegister
{
        void Register<TInterface, TService>() where TService : class, TInterface;
        // not required, I needed though for WCF
        IResolver GetResolver();
}
public interface IResolver
{
    TService GetService<TService>();
}
internal class Resolver : IResolver
{
    // change to your container choice
    private readonly IUnityContainer _diContainer;

    public Resolver(IUnityContainer DIContainer)
    {
        _diContainer = DIContainer;
    }

    public TService GetService<TService>()
    {
        return _diContainer.Resolve<TService>();
    }
}
internal class ContainerRegister : IContainerRegister
{
    // change to your container choice
    private readonly IUnityContainer _diContainer;

    public ContainerRegister(IUnityContainer diContainer)
    {
        _diContainer = diContainer;
    }

    public void Register<TInterface, TService>() where TService : class, TInterface
    {
        // change according to your container choice
        _diContainer.RegisterType<TInterface, TService>();
    }

    public IResolver GetResolver()
    {
         // change according to your container choice
        return _diContainer.Resolve<IResolver>();
    }
}
internal class BootStrap
{
    // change to your container choice
    private UnityContainer _container = null;

    public IContainerRegister Init()
    {
        _container = new UnityContainer();
        _container.LoadConfiguration();
        _container.RegisterInstance<IUnityContainer>(_container);

        _container.RegisterType<IResolver, Resolver>();
        _container.RegisterType<IContainerRegister, ContainerRegister>();
        // register your modules here using reflection
        // resolve each modules and call register()
        return _container.Resolve<IContainerRegister>();
    }
}
public abstract class BaseModule {
    public BaseModule(IContainerRegister register){
        _register = register;
    }
    public abstract void Register();
}

Context

StackExchange Code Review Q#157056, answer score: 2

Revisions (0)

No revisions yet.