My project is a Windows background service with .NET 8.
I want to use Microsoft Entity Framework Core in my current project. I also want to use the DbContextFactory to create an instance where needed.
Therefore I need to set this up in my Program.cs file.
Actually I need to explain a little bit more my current setup of my project. In appsettings.json there is a property value, which controls which database should be used.
This is my appsettings.json:
...
{
"AppSettings": {
"DaysBetweenExecution": 1,
"ExecutionHour": 3,
"ExecutionMinute": 0,
"Environment": "Dev"
},
...
As you can see here, the Environment is set to Dev.
So I setup this AppSettings in my Program.cs like this:
...
builder.Services.AddOptions<AppSettings>()
.BindConfiguration("AppSettings");
...
to use these settings in my application.
The AppSettings class looks like this:
namespace BrochureCreationService.ApplicationLogic.Models.AppSettings
{
public class AppSettings
{
public int DaysBetweenExecution { get; set; } = -1;
public int ExecutionHour { get; set; } = -1;
public int ExecutionMinute { get; set; } = -1;
public string Environment { get; set; } = "Dev";
}
}
This value Dev is being handled by the class Environment.
This is the Environment class:
using Microsoft.Extensions.Options;
namespace BrochureCreationService.ApplicationLogic.Models.Enviroment
{
public class Environment : IEnvironment
{
private IOptions<AppSettings.AppSettings> _AppSettings;
public Enums.Environment Current { get; set; }
public Environment(IOptions<AppSettings.AppSettings> appSettings) {
_AppSettings = appSettings;
Current = GetEnvironmentFromAppSettings();
}
public Enums.Environment GetEnvironmentFromAppSettings()
{
switch(_AppSettings.Value.Environment.ToLower())
{
case "dev":
return Enums.Environment.Dev;
case "test":
return Enums.Environment.Test;
case "ittest":
case "it-test":
return Enums.Environment.ITTest;
case "live":
case "production":
return Enums.Environment.Live;
default:
return Enums.Environment.Dev;
}
}
public string GetConnectionString()
{
switch (_Environment.Current)
{
case Enums.Environment.Live:
return "connection string";
case Enums.Environment.Test:
return "connection string test";
case Enums.Environment.ITTest:
return "connection string it test";
case Enums.Environment.Dev:
return "connection string dev";
default:
return "connection string dev";
}
}
}
}
As you can see, the AppSettings are injected in the constructor. This class provides me the correct connection string based on the Environment setting in appsettings.json.
Now my issue: I need to setup the factory for Entity Framework Core in Program.cs.
I want to do it like this :
builder.Services.AddDbContextFactory<IMP_GG_Context>(options =>
{
var environment = new BrochureCreationService.ApplicationLogic.Models.Enviroment.Environment();
options.UseSqlServer(environment.GetConnectionString());
}, ServiceLifetime.Scoped);
The issue here is, that this line is not working:
var environment = new BrochureCreationService.ApplicationLogic.Models.Enviroment.Environment();
...because Environment needs the AppSettings or better IOptions<AppSettings.AppSettings> in the constructor. How can I manage that in Program.cs?
Or are there better ways to do this?
Maybe, if it helps. Here is my full current code of Program.cs:
using Microsoft.Extensions.Logging.Configuration;
using Microsoft.Extensions.Logging.EventLog;
using BrochureCreationService.GUI;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddWindowsService(options =>
{
options.ServiceName = "Brochure Creation Service";
});
LoggerProviderOptions.RegisterProviderOptions<EventLogSettings, EventLogLoggerProvider>(builder.Services);
builder.Services.AddOptions<AppSettings>().BindConfiguration("AppSettings");
builder.Services.AddOptions<WordSettings>().BindConfiguration("WordSettings");
builder.Services.AddOptions<PdfSettings>().BindConfiguration("PdfSettings");
builder.Services.AddOptions<EmailSettings>().BindConfiguration("EmailSettings");
builder.Services.AddSingleton<IEnvironment, BrochureCreationService.ApplicationLogic.Models.Enviroment.Environment>();
builder.Services.AddSingleton<IServiceController, ServiceController>();
builder.Services.AddTransient<IExecution, Execution>();
//... some more dependencies with AddTransient
builder.Services.AddScoped<IIMP_GG_Context, IMP_GG_Context>();
builder.Services.AddDbContextFactory<IMP_GG_Context>(options =>
{
var appSettingsOptions = Configuration.GetSection("AppSettings").Get<AppSettings>();
var environment = new BrochureCreationService.ApplicationLogic.Models.Enviroment.Environment(appSettingsOptions);
options.UseSqlServer(environment.GetConnectionString());
}, ServiceLifetime.Scoped);
builder.Services.AddHostedService<WindowsBackgroundService>();
IHost host = builder.Build();
host.Run();
There is another overload for
AddDbContextFactorywhich you can injectIServiceProvider, so easily it's possible to get theIEnvironmentservice from DI: