Correct use of Autofac in C# console application

17,107

Solution 1

Static is the problem

The main issue with a console program is that the main Program class is mostly static. This is not good for unit testing and it's not good for IoC; a static class is never constructed, for example, so there is no chance for constructor injection. As a result, you end up using new in the main code base, or pull instances from the IoC container, which is a violation of the pattern (it's more of a service locator pattern at that point). We can get out of this mess by returning to practice of putting our code in instance methods, which means we need an object instance of something. But what something?

A two-class pattern

I follow a particular, lightweight pattern when writing a console app. You're welcome to follow this pattern which works pretty well for me.

The pattern involves two classes:

  1. The original Program class, which is static, very brief, and excluded from code coverage. This class acts as a "pass through" from O/S invocation to invocation of the application proper.
  2. An instanced Application class, which is fully injected and unit-testable. This is where your real code should live.

The Program Class

The O/S requires a Main entry point, and it has to be static. The Program class exists only to meet this requirement.

Keep your static program very clean; it should contain (1) the composition root and (2) a simple, "pass-through" entry point that calls the real application (which is instanced, as we will see).

None of the code in Program is worthy of unit testing, since all it does is compose the object graph (which would be different when under test anyway) and call the main entry point for the application. And by sequestering the non-unit-testable code, you can now exclude the entire class from code coverage (using the ExcludeFromCodeCoverageAttribute).

Here is an example:

[ExcludeFromCodeCoverage]
static class Program
{
    private static IContainer CompositionRoot()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<Application>();
        builder.RegisterType<EmployeeService>().As<IEmployeeService>();
        builder.RegisterType<PrintService>().As<IPrintService>();
        return builder.Build();
    }

    public static void Main()  //Main entry point
    {
        CompositionRoot().Resolve<Application>().Run();
    }
}

As you can see, extremely simple.

The Application class

Now to implement your Application class as if it were the One and Only Program. Only now, because it is instanced, you can inject dependencies per the usual pattern.

class Application
{
    protected readonly IEmployeeService _employeeService;
    protected readonly IPrintService _printService;

    public Application(IEmployeeService employeeService, IPrintService printService)
    {
        _employeeService = employeeService; //Injected
        _printService = printService; //Injected
    }

    public void Run()
    {
        var employee = _employeeService.GetEmployee();
        _printService.Print(employee);
    }
}

This approach keeps separation of concerns, avoids too much static "stuff," and lets you follow the IoC pattern without too much bother. And you'll notice-- my code example doesn't contain a single instance of the new keyword, except to instantiate a ContainerBuilder.

What if the dependencies have dependencies of their own?

Because we follow this pattern, if PrintService or EmployeeService have their own dependencies, the container will now take care of it all. You don't have to instantiate or write any code to get those services injected, as long as you register them under the appropriate interface in the composition root.

class EmployeeService : IEmployeeService
{
    protected readonly IPrintService _printService;

    public EmployeeService(IPrintService printService)
    {
        _printService = printService; //injected
    }

    public void Print(Employee employee)
    {
        _printService.Print(employee.ToString());
    }
}

This way the container takes care of everything and you don't have to write any code, just register your types and interfaces.

Solution 2

You can use inject dependencies via constructor (Autofac also supports property and method injection).

Usually when dependency registration is done, you should not use container inside classes, as it makes your class to be coupled to container, there could be some cases that you want to use child container (inner scope) in which you can define a specific class which does that and make your code independent of container.

In your example you just need to resolve IEmployeeService and all its dependencies will be resolved by container automatically.

Here is an example to demonstrate how you can achieve this:

using Autofac;
using System;
using System.Collections.Generic;
using System.Linq;

namespace AutofacExample
{
    public class Employee
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public interface IEmployeeRepository
    {
        Employee FindById(int id);
    }

    public interface IEmployeeService
    {
        void Print(int employeeId);
    }

    public class EmployeeRepository : IEmployeeRepository
    {
        private readonly List<Employee> _data = new List<Employee>()
        {
            new Employee { Id = 1, Name = "Employee 1"},
            new Employee { Id = 2, Name = "Employee 2"},
        };
        public Employee FindById(int id)
        {
            return _data.SingleOrDefault(e => e.Id == id);
        }
    }

    public class EmployeeService : IEmployeeService
    {
        private readonly IEmployeeRepository _repository;
        public EmployeeService(IEmployeeRepository repository)
        {
            _repository = repository;
        }
        public void Print(int employeeId)
        {
            var employee = _repository.FindById(employeeId);
            if (employee != null)
            {
                Console.WriteLine($"Id:{employee.Id}, Name:{employee.Name}");
            }
            else
            {
                Console.WriteLine($"Employee with Id:{employeeId} not found.");
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var container = BuildContainer();
            var employeeSerive = container.Resolve<IEmployeeService>();
            employeeSerive.Print(1);
            employeeSerive.Print(2);
            employeeSerive.Print(3);
            Console.ReadLine();
        }

        static IContainer BuildContainer()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<EmployeeRepository>()
                   .As<IEmployeeRepository>()
                   .InstancePerDependency();
            builder.RegisterType<EmployeeService>()
                   .As<IEmployeeService>()
                   .InstancePerDependency();
            return builder.Build();
        }
    }
}
Share:
17,107
Sebastian Garcia
Author by

Sebastian Garcia

Updated on June 05, 2022

Comments

  • Sebastian Garcia
    Sebastian Garcia almost 2 years

    I'm new using Autofac so my apologies for the noob question. I read every manual in Internet explaining the basics when using Autofac (or any other tool like Structuremap, Unity, etc). But all the examples that I found are basics. I need to know how to implement Autofac deeper in my code. Let me try to explain what I need to know with this example, a console application.

    class Program
    {
        static void Main(string[] args)
        {
            var container = BuildContainer();
            var employeeService = container.Resolve<EmployeeService>();
            Employee employee = new Employee
            {
                EmployeeId = 1,
                FirstName = "Peter",
                LastName = "Parker",
                Designation = "Photographer"
            };
    
            employeeService.Print(employee);
        }
    
        static IContainer BuildContainer()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<EmployeeRepository>().As<IEmployeeRepository>();
            builder.RegisterType<EmployeeService>();
            return builder.Build();
        }
    }
    

    This is simple and easy. What I'm trying to figure out is how do you implement this when you go deeper in the code. In this example, when you execute this line

    employeeService.Print(employee);
    

    Let's assume the "Print" method is a little bit complex and need to use another dependencies/classes to accomplish his task. We are still using Autofac so I suppose we need to do something like the example above to create that dependencies. Is that correct? Inside my "print" method, when I need to use another class, I must create another container, fill it, use it with Resolve() and so on? There is an easier way to do that? A static class with all the dependencies needed can be consumed across all the solution? How? I hope to be clear. Maybe neither I can express what I need. :( Sorry for my poor English. I'm still learning it while I learn Autofac.

  • Sebastian Garcia
    Sebastian Garcia over 6 years
    Thanks. This show me how I must do it. Thanks again for your time and great explanation.
  • Alexcei Shmakov
    Alexcei Shmakov over 4 years
    @SebastianGarcia, it seems like you need to mark answer as true by clicking on the tick. Thank you John.