I am busy on a asp net core application where I need to perform a background task on my database once a day. So reading https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio
I made a background service that's working fine. But in order to do something with it I need to access my database with the database context. I wanted to use Dependency injection like I do with all my other classes. But then I get a runtime error : HTTP
Error 500.30 ANCM In-Process start failure.
The relevant code:
public class BackgroundService : IHostedService, IDisposable
{
private readonly Data.ApplicationDbContext _DB;
private int executionCount = 0;
private readonly ILogger<BackgroundService> _logger;
private Timer _timer;
//public BackgroundService(Data.ApplicationDbContext DB, ILogger<BackgroundService> logger) //this fails!!
public BackgroundService( ILogger<BackgroundService> logger) //This works
{
_logger = logger;
// _DB = DB;
}
....
how did you register the db context? the constructor only support singleton objects. If you need scoped object, then you need to create a scoped service:
for the singleton, you create an instance of an object. depending on your needs, you pass the factory, or you call the factory and pass an dbcontext instance created by the factory. see the factory example link above.
public class BloggingContextFactory : IDesignTimeDbContextFactory<BloggingContext>
{
public BloggingContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlite("Data Source=blog.db");
return new BloggingContext(optionsBuilder.Options);
}
}
using (var dbcontext = factory.CreateDbContext(args))
{
}
note: as a Factory is a major concept in DI, you should study the DI pattern (inversion of control)
hint: you should add a connection string to Factory constructor that you can be used by CreateDbContext(). I'd probably use a delegate for the option builder, so it can be set in startup.cs
1. I have created a new class RoosterContextFactory, containing:
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace RoosterApp.Data
{
public class RoosterContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
public ApplicationDbContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
optionsBuilder.UseSqlServer("Data Source= Server=xxxxxxxxxxx; Database=xxxxxx; User Id=xxxxxx ; Password = xxxxx");
return new ApplicationDbContext(optionsBuilder.Options);
}
}
And then in my BackgroundService where I need to access the database :
using (var dbcontext = RoosterContextFactory.CreateDbContext(args)) //This args argument is not accepted
{
// I will enter my Linq query here.
}
Here, the argument args is not accepted. I have tried to leave it out, or enter an empty string. But it keeps saying "The name 'args' does not exist in the current context".
I have read the note that the args parameter is unused, But it will not build like this. do you have a solution for this?
second question: the database connection string is now copy - past from my Appsettings file. is there a neat way to prevent this and refer to the appsettingsfile directly?
public class BackgroundService : IHostedService, IDisposable
{
private int executionCount = 0;
private readonly ILogger<BackgroundService> _logger;
private readonly IServiceProvider _provider;
private Timer _timer;
public BackgroundService(ILogger<BackgroundService> logger,IServiceProvider provider) //This works
{
_logger = logger;
_provider = provider;
}
...
private void DoWork(object state)
{
using (var scope = _provider.CreateScope())
{
var dbcontxt = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
var data = dbcontxt.Employee.ToList();
}
var count = Interlocked.Increment(ref executionCount);
_logger.LogInformation(
"Timed Hosted Service is working. Count: {Count}", count);
}
...
}
Best Regards,
Sherry
MSDN Community Support
Please remember to click "Mark as Answer" the responses that resolved your issue.
If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.
Your input has directed me into the right direction. The injection of IServiceProvider works as you stated. But the syntax to create a scope does not work this way in core 2.2.
After a lot of reading I came up with the following:
private void DoWork(object state)
{using (var scope = ServiceProviderServiceExtensions.CreateScope(_provider))
{
var DBcontext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
List<Mutation> mut = (from m in DBcontext.Mutations
where m.DateStartOn < DateTime.Today
where m.ApprovedOn == null
select m).ToList();
foreach (Mutation M in mut)
...
Member
14 Points
36 Posts
Dependency injection in HostedService failing
Apr 14, 2020 03:22 PM|Rob warning|LINK
Hi,
I am busy on a asp net core application where I need to perform a background task on my database once a day. So reading https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio I made a background service that's working fine. But in order to do something with it I need to access my database with the database context. I wanted to use Dependency injection like I do with all my other classes. But then I get a runtime error : HTTP Error 500.30 ANCM In-Process start failure.
The relevant code:
Can somebody tell me what I do wrong?
thanks i advance.
Rob
All-Star
58174 Points
15647 Posts
Re: Dependency injection in HostedService failing
Apr 14, 2020 03:33 PM|bruce (sqlwork.com)|LINK
how did you register the db context? the constructor only support singleton objects. If you need scoped object, then you need to create a scoped service:
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio
Member
14 Points
36 Posts
Re: Dependency injection in HostedService failing
Apr 14, 2020 04:45 PM|Rob warning|LINK
Hi Bruce, I registered my DB Context in the Startup as follow:
All-Star
58174 Points
15647 Posts
Re: Dependency injection in HostedService failing
Apr 14, 2020 04:52 PM|bruce (sqlwork.com)|LINK
but that a transient scope (every request gets a unique dbcontext), not a singleton. you should register dbcontext factory as a singleton.
factory:
https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/dbcontext-creation
Member
14 Points
36 Posts
Re: Dependency injection in HostedService failing
Apr 14, 2020 05:27 PM|Rob warning|LINK
OK, I know the services,addSingleton<> but where to put the options??
What is exactly the correct syntax ??
All-Star
58174 Points
15647 Posts
Re: Dependency injection in HostedService failing
Apr 14, 2020 05:43 PM|bruce (sqlwork.com)|LINK
for the singleton, you create an instance of an object. depending on your needs, you pass the factory, or you call the factory and pass an dbcontext instance created by the factory. see the factory example link above.
Member
14 Points
36 Posts
Re: Dependency injection in HostedService failing
Apr 14, 2020 06:01 PM|Rob warning|LINK
Sorry Bruce,
It's like Chinese to me.
what is a factory? how do I pass one?
Do I need to change my ApplicationDbContext class?
All I want is to run a Linq query once a day.
I appreciate your help but my level of knowledge is not the same
All-Star
58174 Points
15647 Posts
Re: Dependency injection in HostedService failing
Apr 14, 2020 07:48 PM|bruce (sqlwork.com)|LINK
the sample looks pretty simple:
then its:
then in service:
public BackgroundService( ILogger<BackgroundService> logger, BloggingContextFactory factory)
then when the service needs a context:
note: as a Factory is a major concept in DI, you should study the DI pattern (inversion of control)
hint: you should add a connection string to Factory constructor that you can be used by CreateDbContext(). I'd probably use a delegate for the option builder, so it can be set in startup.cs
Member
14 Points
36 Posts
Re: Dependency injection in HostedService failing
Apr 15, 2020 07:56 AM|Rob warning|LINK
Thanks Bruce,
the light is slowly starting to shine.
What I did:
1. I have created a new class RoosterContextFactory, containing:
then in my startup I added the line:
And then in my BackgroundService where I need to access the database :
Here, the argument args is not accepted. I have tried to leave it out, or enter an empty string. But it keeps saying "The name 'args' does not exist in the current context".
I have read the note that the args parameter is unused, But it will not build like this. do you have a solution for this?
second question: the database connection string is now copy - past from my Appsettings file. is there a neat way to prevent this and refer to the appsettingsfile directly?
Regards
Rob
Contributor
2070 Points
606 Posts
Re: Dependency injection in HostedService failing
Apr 15, 2020 10:12 AM|Sherry Chen|LINK
Hi Rob warning ,
You could create scoped service in BackgroundService instead of registering it in Constructor.The doc of Consuming a scoped service in a background task has explained it.
Best Regards,
Sherry
Please remember to click "Mark as Answer" the responses that resolved your issue.
If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.
Member
14 Points
36 Posts
Re: Dependency injection in HostedService failing
Apr 15, 2020 02:59 PM|Rob warning|LINK
Tanks Cherry,
Your input has directed me into the right direction. The injection of IServiceProvider works as you stated. But the syntax to create a scope does not work this way in core 2.2.
After a lot of reading I came up with the following:
Now everything works as it should.