Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolving dependencies dynamically using Autofac

Is it good to resolve the dependencies dynamically like the way i'm doing. Everywhere, it is suggested to use Constructor injection. I really don't understand the drawbacks of doing it the way i'm doing it. Code snippets as below..

Employee.cs

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public Department Department { get; set; }
}

IRepository.cs

public interface IRepository<TModel> where TModel : class
    {
        void Add();
        IEnumerable<TModel> GetAll();
        IEnumerable<TModel> GetByID();
    }

Repository.cs

public class Repository<TModel> : IRepository<TModel> where TModel : class
{
    public void Add()
    {
        throw new NotImplementedException();
    }

    public IEnumerable<TModel> GetAll()
    {
        throw new NotImplementedException();
    }

    public IEnumerable<TModel> GetByID()
    {
        throw new NotImplementedException();
    }
}

EmployeeController.cs

public class HomeController : ApiController
{
    IComponentContext _container;

    public HomeController(IComponentContext container)
    {
        this._container = container;
    }

    public Repository<TModel> Using<TModel>() where TModel :class
    {
        var repository = _container.Resolve(typeof(IRepository<TModel>));
        return repository as Repository<TModel>;
    }

    [HttpGet]
    public IEnumerable<Employee> GetEmployees()
    {
        return Using<Employee>().GetAll();
    }
}

Global.asax

protected void Application_Start()
{
    GlobalConfiguration.Configure(WebApiConfig.Register);

    var builder = new ContainerBuilder();
    builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

    builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));

    var container = builder.Build(Autofac.Builder.ContainerBuildOptions.None);
    var webApiResolver = new AutofacWebApiDependencyResolver(container);
    GlobalConfiguration.Configuration.DependencyResolver = webApiResolver;
}

Say i've 5 repositories, Constructor injection will resolve all the 5 dependencies for a request i make. I might not use 5 repositories for each and every request. SO i thought of resolving dependencies dynamically by passing the type like i'm doing it in Using<TModel>(). Any suggestions would be appreciated..!! Thank you...!!

like image 595
Praveen Avatar asked Mar 11 '23 10:03

Praveen


1 Answers

Refrain from using the container directly inside your application components; this leads to all kinds of troubles such as maintainability and testability issues. Directly resolving instances from within application code is a well-known anti-pattern known as Service Locator.

As a first refactoring, you can instead apply the Unit of Work pattern. A Unit of Work allows access to underlying repositories. For instance:

public interface IUnitOfWork
{
    IRepository<TModel> Repository<TModel>();
}

public sealed class HomeController : ApiController
{
    private readonly IUnitOfWork _unitOfWork;

    public HomeController(IUnitOfWork unitOfWork)
    {
        this._unitOfWork = unitOfWork;
    }

    [HttpGet]
    public IEnumerable<Employee> GetEmployees()
    {
        return this._unitOfWork.Repository<Employee>().GetAll();
    }
}

Within the Composition Root (where it is allowed to access the container), we can now create an IUnitOfWork implementation that resolves repositories dynamically:

private sealed class AutofacUnitOfWork : IUnitOfWork
{
    private readonly IComponentContext _container;

    public AutofacUnitOfWork(IComponentContext container)
    {
        this._container = container;
    }

    public IRepository<TModel> Repository<TModel>()
    {
        return _container.Resolve<IRepository<TModel>>();
    }
}

This pattern simplifies your application components considerably and prevents downsides that the Service Locator anti-pattern typically causes.

Although applying the Unit of Work pattern might be a useful step into the right direction, an even better approach is to skip the Unit of Work directly and simply inject a required repository directly into application components:

public sealed class HomeController : ApiController
{
    private readonly IRepository<Employee> _employeeRepository;

    public HomeController(IRepository<Employee> employeeRepository)
    {
        this._employeeRepository = employeeRepository;
    }

    [HttpGet]
    public IEnumerable<Employee> GetEmployees()
    {
        return this._employeeRepository.GetAll();
    }
}

Say i've 5 repositories, Constructor injection will resolve all the 5 dependencies for a request i make. I might not use 5 repositories for each and every request.

Note that from a performance perspective, you should typically not be concerned whether dependencies are used or not. Autofac is in most cases fast enough and it is unlikely that this will actually cause any performance problems in your production systems.

From a design perspective however you should be more worried if a class has many dependencies, while methods just use a few of them. This means that the methods in the class have little cohesion. This is an indication that the class should be split up into multiple smaller classes; it has multiple responsibilities.

like image 107
Steven Avatar answered Mar 19 '23 05:03

Steven