【问题标题】:Adding DBContext Service to program.cs in Worker Project将 DBContext 服务添加到 Worker Project 中的 program.cs
【发布时间】:2021-06-11 12:07:40
【问题描述】:

对这一切都很陌生,如果我做了任何愚蠢的事情,请道歉。

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

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

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "ConnectionStrings": {
    "DBConnection": "Server=localhost\\SQLEXPRESS;Database=TwitterTesting;Trusted_Connection=True;"
  }
}

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

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

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

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

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

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

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

【问题讨论】:

  • 您在哪里定义 WorkerService1.DataContext 以及如何将其添加到 DI?
  • @SaeedEsmaeelinejad 抱歉,我不太清楚你的意思?

标签: c# sql-server entity-framework-core


【解决方案1】:

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

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

虽然这些都没有明确说明如何将服务添加到 DI,但 AddHostedService&lt;Worker&gt; 正在将 Worker 类注册为单例 - 永远只会创建 Worker 的一个实例. AddDbContextPool&lt;DataContext&gt; 正在将 DataContext 注册为一个作用域服务 - 每次创建一个请求 DataContext 的作用域时都应该构建该服务。

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

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

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
        var scope = _serviceProvider.CreateScope().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 = scope.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, scope.GetService<DataContext>());
        context.Dispose();
    }
}

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

【讨论】:

    猜你喜欢
    • 2020-05-02
    • 1970-01-01
    • 1970-01-01
    • 2022-11-09
    • 1970-01-01
    • 2022-11-22
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多