c# - 了解控制台应用程序中的 .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 应用程序的示例,但对于控制台应用程序却很少。我只是完全误解了依赖注入的整个概念吗?
解决方案
使用构造函数注入时,只有当您创建的对象实际上是通过依赖注入本身创建时,才会解析依赖关系。因此,使依赖注入在你的内部工作的关键是通过依赖注入容器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();
}
}
推荐阅读
- c# - 值已读取,或尝试从 Stream 读取时没有值
- javascript - ReactTs如何在组件上多次执行get请求
- javascript - 角度js数据表将行数据传递给函数
- rust - 将 println 设为宏有什么好处?
- azure - Azure B2C 自定义策略 Rest API 客户端证书
- python - tkinter 使用默认的 Mac 主题
- python - 应用 SciPy 牛顿法优化熊猫数据框 Weibull 和
- android - IDE 无法识别 Android Kotlin checkBox.isChecked
- r - 在 R 中为海洋添加颜色
- nginx - 无法使用 Laravel 使用 Nginx 将图像转发到 webp