将DBContext服务添加到Worker项目中的program.cs中

Pau*_*mes 7 c# sql-server entity-framework-core

对于这一切还相当陌生,所以如果我做了任何愚蠢的事情,我深表歉意。

我正在尝试实现一个与我设置的本地 SQL Server Express 数据库进行通信的工作项目。

我将连接字符串存储在 my 中AppSettings.Json,如下所示

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "ConnectionStrings": {
    "DBConnection": "Server=localhost\\SQLEXPRESS;Database=TwitterTesting;Trusted_Connection=True;"
  }
}
Run Code Online (Sandbox Code Playgroud)

然后我有一个DBContext.cs存储数据库结构的文件。目前我只有一张表“推文”。

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WorkerService1.Entities;

namespace WorkerService1
{
    public class DataContext : DbContext
    {
        public DataContext(DbContextOptions options) : base(options)
        {
        }

        public DbSet<tweets> tweets { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

Tweets.cs仅具有列结构。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace WorkerService1
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddDbContextPool<DataContext>(
                        options => options.UseSqlServer(hostContext.Configuration.GetConnectionString("DBConnection"))
                    );
                    services.AddHostedService<Worker>();
                });
    }
}
Run Code Online (Sandbox Code Playgroud)

上面是我的program.cs文件,我试图在其中添加 的实现DBContext,但在编译时出现以下错误:

System.AggregateException:“无法构造某些服务(验证服务描述符时出错”ServiceType:Microsoft.Extensions.Hosting.IHostedService Lifetime:Singleton ImplementType:WorkerService1.Worker”:无法使用范围内的服务“WorkerService1.DataContext”单例“Microsoft.Extensions.Hosting.IHostedService”。)

我从网上看的理解是这与依赖注入有关,但我真的很困惑我需要做什么。

任何帮助将不胜感激!:)

Str*_*iax 10

问题是您正在尝试创建ScopedDbContext 的服务,但要使用它的类 ( Worker) 是一个Singleton类 - 请注意以下两行。

services.AddDbContextPool<DataContext>( /*omitted*/ );
services.AddHostedService<Worker>();

Run Code Online (Sandbox Code Playgroud)

虽然这些都没有明确说明如何将服务添加到 DI,AddHostedService<Worker>但都将类注册为单例 -永远只会创建Worker一个实例。正在注册为范围服务 - 每次创建所需范围时都应该构建该服务。WorkerAddDbContextPool<DataContext>DataContextDataContext

问题是,如果在构造函数中Worker要求,您将得到一个将在 - 的持续时间内生存的单例- 这将永远存在,因为它是单例。DataContextDataContextWorkerWorker

DataContext要在类中获取作用域Worker,您需要从 DI 获取服务提供者,并在每次Worker在主方法中迭代时创建一个作用域 - 例如:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Management.Infrastructure;
using Microsoft.Management.Infrastructure.Options;
using System;
using System.Threading;
using System.Threading.Tasks;
private readonly ILogger<Worker> _logger;
private readonly IServiceProvider _serviceProvider;

public Worker (ILogger<Worker> logger, IServiceProvider serviceProvider)
{
    _logger = logger;
    _serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    while (!stoppingToken.IsCancellationRequested)
    {
        _logger.Log("Creating scope to get a new DataContext.");
        // this will give us a scoped service
        using var scope = _serviceProvider.CreateScope();
        var services = scope.ServiceProvider;
        // if DataContext were configured as singleton through AddSingleton<DataContext> 
        // in ConfigureServices, this would always be the same instance. Since it's added 
        // as Scoped, we'll get the same instance every time we ask for the service from 
        // our scope but each time we create a new scope it'll be a new instance.
        var context = services.GetService<DataContext>();
        // do something with context
        // we can validate that within our scope it's always the same object reference:
        _logger.Log("Get scoped service multiple times yields the same reference: {0}", object.ReferenceEquals(context, services.GetService<DataContext>());
        context.Dispose();
    }
}
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请查看以下页面 - 特别注意提及“Scoped”、“Transient”和“Singleton”。 https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-5.0