EF Core:通过将注入的 DbContext 对象作为参数传递来创建对象

EF Core: Create an object by passing an injected DbContext object as parameter

我已经创建了一个 .Net Core MVC 项目并了解依赖注入如何为我们的 MVC 控制器工作,如下所示,但就像我想通过调用同样注入 interface/class 作为参数。

public class ShiftsController : BaseController
{
  ShardingDbContext _dbContext;

   public ShiftsController(ShardingDbContext ShardingDbContext) : base(ShardingDbContext)
  {
   _dbContext = ShardingDbContext;
    ViewBag.Menu = BuildMenu();
  }

我已经将 DbContext 注入到我的 Startup.cs 文件中,如下所示,

 //Entity Framework Core
 services.AddDbContext<ShardingDbContext>(options => options.UseSqlServer(ConnectionString), 
 ServiceLifetime.Transient);

ShiftsController 是一个 C#-MVC 控制器,当我 运行 我的应用程序并转到我的应用程序中的 Shift 页面时,DbContext 工作正常,但是当我尝试下面给出的代码时,它不起作用并给出错误。所以我不知道如何在使用“new”关键字创建对象时传递已注册的class的对象。

public class JobScheduler
{
  ShardingDbContext _dbContext;


  public JobScheduler(ShardingDbContext ShardingDbContext)
  {
      _dbContext = ShardingDbContext;

  }...

这是我自己的 class 并尝试为 class JobScheduler 创建一个对象,如下所示。

  JobScheduler  jobs = new JobScheduler();

所以现在我不知道如何将 EF 核心的 DbContext 对象传递给构造函数 JobScheduler,DI 对于控制器工作正常但对于普通 class。任何人都可以帮助解决这个问题吗?我也热切地等待着理解这个逻辑?

你是对的:你的 DI 工作正常但你的 ShardingDbContext 没有传递到你的 JobScheduler 因为你没有使用 DI 来实例化 JobScheduler。每当您使用 new 关键字显式创建对象实例时,您都没有使用 DI.

您有两个选择:

  1. 无论你在哪里调用 new JobScheduler() 让 DI 通过构造函数给你注入一个 ShardingDbContext 并像这样将它传递给 JobScheduler new JobScheduler(shardingDbContext)
  2. 也将 JobScheduler 注册到依赖注入,让 DI 构建整个链,这样你就不需要调用 new JobScheduler() 而是直接在任何地方注入 JobScheduler你需要它

编辑

此处要求的是使用短暂数据库上下文的定时作业示例:

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;
        }
    }
}

MyJob class 看起来像这样:

public class MyJob
{
    private readonly ShardingDbContext dbContext;

    public MyJob(ShardingDbContext dbContext)
    {
        this.dbContext = dbContext;
    }

    public Task Execute()
    {
        // Your logic goes here
    }      
}

然后你像这样在启动中注册你的 classes:

services
    .AddHostedService<TimedBackgroundService>()
    .AddScoped<MyJob>();

现在您有一个每 30 分钟运行一次并使用短期数据库上下文的作业。

像这样注册您的 JobScheculer:

services.AddSingleton<JobScheduler>();

然后像这样使用您的 dbContext:

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
        }
   }

在 Startup.cs class 的 ConfigureServices 方法的末尾,我没有更改 JobSchedulerclass 中的任何内容并从服务提供商传递 DbContext 对象,如图所示下面,感谢所有试图帮助解决这个问题的人。

 public void ConfigureServices(IServiceCollection services)
 { 
   ...
   ...

   JobScheduler job = new 
   JobScheduler(services.BuildServiceProvider().CreateScope().ServiceProvider
   .GetService<ShardingDbContext>());
   
   job.Start();
  }