使用 Autofac 将依赖项注入控制台应用程序的 Main 入口点

问题描述:

假设我有一个简单的控制台应用程序:

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!");
    }
}

我可以使用 Autofac 注入 Log 实例并确保 Log 属性在运行时不会为空的最简单方法是什么?问题是我无法通过 Main() 传递它,并且我试图避免使用容器的服务位置(只是因为).

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).

您应该做的是将 main 中的所有逻辑提取到一个类中.这个类可以有一个带有依赖关系的构造函数.您在 main 中解析这个类并调用它.这个类应该被视为整个应用程序.Program 类中发生的所有事情现在都可以视为您的 组合根.

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!");
}

请注意,container.Resolve()只是解析ApplicationLogic 类,它解析整个对象图包括ApplicationLogic所有的依赖,以及那些依赖的依赖等,不管图有多深.您唯一需要负责的是在 ConfigureContainer() 方法中注册这些依赖项.因此,有超过 1 个 Resolve() 方法调用控制台应用程序是有些不寻常的,如果有,它们应该始终在组合根内被调用或连接.

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.