In ASP.NET Core applications, the services can be scoped, that can be resolved or instantiated at the start of a request, and disposed of at the end of a request. But in Worker Service type of applications, the definition of scope is not clear. That’s why we need to implement scoping ourselves. Let’s say every time the code runs, we assume it is a request.
1. Register DbContext in services
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureServices((hostContext, services) => { var configuration = hostContext.Configuration; services.AddHostedService<Worker>(); services.AddScoped<MyDbContext>(s => new MyDbContext(configuration)); });
2. Create the scope in the Worker
private readonly IServiceProvider _provider; public Worker(ILogger<Worker> logger, IServiceProvider provider) { _logger = logger; _provider = provider; }
….
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now); using var scope = _provider.CreateScope(); var db = scope.ServiceProvider.GetRequiredService<PodiumDb>(); var notes= db.Notes.AsNoTracking().FirstOrDefault(p => p.NoteId== 340); await Task.Delay(1000, stoppingToken); } }
This is all. The DI container will create a new instance for us everytime the worker service loops.
Note that I used “using” statement without braces, it is a new feature of C# 8.0 https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#using-declarations1 The variable will be disposed at the end of enclosing scope, which means just after “await…” line.
#net-core #worker-service #entityframework-core
Leave a comment