I have created a.Net Core MVC project and understand that how the dependency injection works for our MVC controller as shown below, but same like I wanted to create an object for my own class by calling the same injected interface/class as a parameter.
public class ShiftsController : BaseController
{
ShardingDbContext _dbContext;
public ShiftsController(ShardingDbContext ShardingDbContext) : base(ShardingDbContext)
{
_dbContext = ShardingDbContext;
ViewBag.Menu = BuildMenu();
}
I have injected the DbContext into my Startup.cs file as below,
//Entity Framework Core
services.AddDbContext<ShardingDbContext>(options => options.UseSqlServer(ConnectionString),
ServiceLifetime.Transient);
The ShiftsController is a C#-MVC controller and the DbContext is working perfectly when I run my app and go to Shift's page in my application, but when I try like below-given code, it's not working and gives an error. So I don't know how to pass the registered class's object while creating an object by using "new" keyword.
public class JobScheduler
{
ShardingDbContext _dbContext;
public JobScheduler(ShardingDbContext ShardingDbContext)
{
_dbContext = ShardingDbContext;
}...
This is my own class and tried to create an object for the class JobScheduler as shown below.
JobScheduler jobs = new JobScheduler();
So now I don't know how to pass the EF core's DbContext's object to the constructor JobScheduler, the DI works fine for the controller but not for a normal class. Can anyone help with this and I am eagerly waiting to understand this logic as well?.
You are right: Your DI works fine but your ShardingDbContext
is not passed into your JobScheduler
because you are not using DI to instanciate JobScheduler
. Whenever you are explicitly creating an object instance using the new
keyowrd you are not using DI.
You have two options:
new JobScheduler()
let DI inject you a ShardingDbContext
through the constructor and pass it to JobScheduler like so new JobScheduler(shardingDbContext)
JobScheduler
to the dependency injection as well and let DI build up the whole chain so you don't need to call new JobScheduler()
but rather get a JobScheduler
injected directly wherever you need itEdit
As requested here is the example for a timed job using a short lived DB context:
public class TimedBackgroundService : IHostedService, IDisposable
{
private readonly Timer timer;
private readonly IServiceProvider serviceProvider;
public TimedBackgroundService(IServiceProvider serviceProvider)
{
timer = new Timer(async state => await ExecuteAsync());
this.serviceProvider = serviceProvider;
}
public Task StartAsync(CancellationToken stoppingToken)
{
timer.Change(0, TimeSpan.FromMinutes(30));
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken stoppingToken)
{
timer.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose() => timer.Dispose();
private async Task ExecuteAsync()
{
try
{
using var scope = serviceProvider.CreateScope();
var job = scope.ServiceProvider.GetRequiredService<MyJob>();
await job.Execute();
}
catch (Exception exception)
{
// log error here
return;
}
}
}
The MyJob
class wil look something like this:
public class MyJob
{
private readonly ShardingDbContext dbContext;
public MyJob(ShardingDbContext dbContext)
{
this.dbContext = dbContext;
}
public Task Execute()
{
// Your logic goes here
}
}
Then you register your classes in the startup like so:
services
.AddHostedService<TimedBackgroundService>()
.AddScoped<MyJob>();
Now you have a job which runs every 30 minutes and uses a short lived db context.
Register your JobScheculer like this:
services.AddSingleton<JobScheduler>();
then use your dbContext like this:
public class JobScheduler
{
private readonly IServiceProvider provider;
public JobScheduler(IServiceProvider provider)
{
}...
public (or private etc) DoYourJob()
{
using (var scope = provider.CreateScope())
{
var dbContext = scope.GetService<ShardingDbContext>();
//use it here
}
}
At the end of the ConfigureServices method of the Startup.cs class, and I did not change anything in the JobSchedulerclass and passing the DbContext object from the service provider as shown below, thanks to everyone who tried to help with this question.
public void ConfigureServices(IServiceCollection services)
{
...
...
JobScheduler job = new
JobScheduler(services.BuildServiceProvider().CreateScope().ServiceProvider
.GetService<ShardingDbContext>());
job.Start();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.