首页 > 解决方案 > 了解控制台应用程序中的 .net Core 依赖注入

问题描述

控制台应用程序不会像 Web 应用程序那样将启动文件与配置服务一起使用,我正在努力理解依赖注入的关键概念。

(请注意以下示例无法编译)

这是我认为它应该如何工作的一个基本示例(请指出任何非常规或错误的地方):

        static void Main(string[] args)
        {
            var builder = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddUserSecrets<Settings>()
                .Build();

            var services = new ServiceCollection()
                .AddLogging(b => b
                    .AddConsole())
                .AddDbContext<UnderstandingDIContext>(options =>
                    options.UseSqlite(builder.GetConnectionString("DefaultConnection")))
                .BuildServiceProvider();

            var logger = services.GetService<ILoggerFactory>()
                .CreateLogger<Program>();

            logger.LogInformation("Starting Application");

            var worker = new Worker();

            logger.LogInformation("Closing Application");
        }

但是我如何在我的“工人”类中使用这些服务?:

        public Worker(ILogger logger, IConfiguration configuration)
        {
            logger.LogInformation("Inside Worker Class");
            var settings = new Settings()
            {
                Secret1 = configuration["Settings:Secret1"],
                Secret2 = configuration["Settings:Secret2"]
            };
            logger.LogInformation($"Secret 1 is '{settings.Secret1}'");
            logger.LogInformation($"Secret 2 is '{settings.Secret2}'");

            using (var context = new UnderstandingDIContext())
            {
                context.Add(new UnderstandingDIModel()
                {
                    Message = "Adding a message to the database."
                });
            }
        }

了解DI上下文

    public class UnderstandingDIContext : DbContext
    {
        public UnderstandingDIContext(DbContextOptions<UnderstandingDIContext> options)
            : base(options)
        { }

        public DbSet<UnderstandingDIModel> UnderstandingDITable { get; set; }
    }

这段代码的问题如下:

Worker() 期望传递 ILogger 和 IConfiguration 参数,但我认为依赖注入应该涵盖这一点?

我无法运行'dotnet ef migrations add Initial',因为我没有正确传递连接字符串(错误:'无法创建'UnderstandingDIContext'类型的对象。')

'using (var context = new UnderstandingDIContext())' 将无法编译,因为我误解了 DbContext 位。

我搜索了很多,有很多关于 Web 应用程序的示例,但对于控制台应用程序却很少。我只是完全误解了依赖注入的整个概念吗?

标签: c#asp.net-coredependency-injection

解决方案


使用构造函数注入时,只有当您创建的对象实际上是通过依赖注入本身创建时,才会解析依赖关系。因此,使依赖注入在你的内部工作的关键是通过依赖注入容器Worker来实际解决。Worker

这实际上很简单:

var services = new ServiceCollection()
    .AddLogging(b => b.AddConsole())
    .AddDbContext<UnderstandingDIContext>(options =>
        options.UseSqlite(builder.GetConnectionString("DefaultConnection")));

// register `Worker` in the service collection
services.AddTransient<Worker>();

// build the service provider
var serviceProvider = services.BuildServiceProvider();

// resolve a `Worker` from the service provider
var worker = serviceProvider.GetService<Worker>();

var logger = serviceProvider.GetService<ILogger<Program>>();
logger.LogInformation("Starting Application");

worker.Run();

logger.LogInformation("Closing Application");

此外,由于您使用的是默认注册为作用域依赖项的数据库上下文,因此我建议您也创建一个服务作用域,或者在注册时更改数据库上下文的生命周期。

var serviceProvider = services.BuildServiceProvider();

using (var scope = serviceProvider.CreateScope())
{
    var worker = serviceProvider.GetService<Worker>();
    worker.Run();
}

请注意,我还在Run您的工作人员上创建了一个显式方法,因此您在构造函数中没有逻辑。

public class Worker
{
    private readonly ILogger<Worker> _logger = logger;
    private readonly IConfiguration _configuration = configuration;
    private readonly UnderstandingDIContext _dbContext = dbContext;

    public Worker(ILogger<Worker> logger, IConfiguration configuration, UnderstandingDIContext dbContext)
    {
        _logger = logger;
        _configuration = configuration;
        _dbContext = dbContext;
    }

    public void Run()
    {
        _logger.LogInformation("Inside Worker Class");
        var settings = new Settings()
        {
            Secret1 = configuration["Settings:Secret1"],
            Secret2 = configuration["Settings:Secret2"]
        };

        _logger.LogInformation($"Secret 1 is '{settings.Secret1}'");
        _logger.LogInformation($"Secret 2 is '{settings.Secret2}'");

        _dbContext.Add(new UnderstandingDIModel()
        {
            Message = "Adding a message to the database."
        });
        _dbContext.SaveChanges();
    }
}

推荐阅读