Question

Say I have a simple console application:

public static class Program
{
    private static ILog Log { get; set; }

    public static void Main()
    {
        Log.Write("Hello, world!");
    }
}

What is the simplest way I can use Autofac to inject the Log instance and ensure that the Log property will not be null at run time? The issue is that I can't pass it in through Main() and I'm trying to avoid service location using the container (just because).

Was it helpful?

Solution

What you should do is extract all logic from your main into a class. This class can have a constructor with dependencies. You resolve this class in the main and call it. This class should then be considered to be the entire application. Everything that happens inside the Program class can now be considered your Composition Root.

// ** Begin composition root
public static class Program
{
    public static void Main(string[] args) 
    {
        var container = ConfigureContainer();
        var application = container.Resolve<ApplicationLogic>();

        application.Run(args); // Pass runtime data to application here
    }

    private static IContainer ConfigureContainer()
    {
        var builder = new ContainerBuilder();
        
        builder.RegisterType<ApplicationLogic>.AsSelf();
        builder.RegisterType<Log>().As<ILog>();
        // Register all dependencies (and dependencies of those dependencies, etc)

        return builder.Build();
    }
}
// ** End composition root

public class ApplicationLogic
{
    private readonly ILog log;

    public ApplicationLogic(ILog log) => this.log = log;

    public void Run(string[] args) => this.log.Write("Hello, world!");
}

Note that container.Resolve<ApplicationLogic>() doesn't just resolve the ApplicationLogic class, it resolves the entire object graph including all of ApplicationLogic's dependencies, and dependencies of those dependencies, etc. no matter how deep the graph is. The only thing you are responsible for is registering those dependencies in the ConfigureContainer() method. Therefore, it is somewhat unusual to have any more than 1 Resolve() method call a console application, and if there are, they should always be called or wired up inside the Composition Root.

OTHER TIPS

Had to change builder.RegisterType.AsSelf(); to builder.RegisterType().AsSelf(); to get this to work for me

You have to configure a container somewhere. In console apps, Main() is usually that place.

I have created a startup file to register all the autofac stuff to make it cleaner.

Also created a template in nuget that you can install directly using dotnet install.

Here is my post to describe what is exactly included in the template, hope it helps to make clearer to use autofac with console apps.

https://medium.com/@mrkevin.wang/create-a-dotnet-core-cosnole-app-template-with-autofac-dependency-injections-60e09f27df17?source=friends_link&sk=d831e88acc36319e2a43e8c7dac70238

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top