ASP.Net 在 HostedService 中配置核心 DbContext

ASP.Net Core DbContext disposed in HostedService

我有一个 ASP.Net 核心应用程序,我试图在其中收听来自 RabbitMQ 的消息。为了做到这一点,我添加了一个 HostedService,监听器在其中等待接收消息。当收到一条消息时,我想使用 Entity Framework Core 将其保存到数据库中。问题是 dbContext 在我保存之前就被处理掉了。正常的 http 请求可以很好地访问 dbContext 只有来自 HostedService 的消息有这个问题。

为了收听来自 RabbitMQ 的消息,我添加了一个名为 RabbitMqConsumer 的 HostedService。

Program.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>
     Host.CreateDefaultBuilder(args)
         .ConfigureWebHostDefaults(webBuilder =>
         {
             webBuilder.UseStartup<Startup>();
         })
         .ConfigureServices(services =>
         {
             services.AddHostedService<RabbitMqConsumer>();
         });

RabbitMqConsumer的实现如下图:

public class RabbitMqConsumer : BackgroundService
    {
        public readonly IServiceScopeFactory _serviceScopeFactory;
        public RabbitMqConsumer(IServiceScopeFactory serviceScopeFactory)
        {
            _serviceScopeFactory = serviceScopeFactory;
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            using (var scope = _serviceScopeFactory.CreateScope())
            {
                await Process(scope.ServiceProvider, stoppingToken);
            }
        }
        private async Task Process(IServiceProvider provider,CancellationToken stoppingToken)
        {
            var queueListenerService =
                provider.GetRequiredService<IMachineLearningQueueListener>();
            await queueListenerService.StartAsync(stoppingToken);
        }
    }

在这个消费者中,我们要开始监听在 MachineLearningQueueListener 中实现的队列

        public IDocumentService _documentService { get; set; }

        public MachineLearningQueueListener(IDocumentService documentService)
        {
            _documentService = documentService;
            factory = new ConnectionFactory() { HostName = Host, Port = Port };
            connection = factory.CreateConnection();
            channel = connection.CreateModel();
        }
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            await StartListeningToQueue();
        }
        public async Task StopAsync(CancellationToken cancellationToken)
        {
            connection.Close();
        }
        private async Task StartListeningToQueue()
        {
            channel.QueueDeclare(queue: "ClassificationResult",
                durable: false,
                exclusive: false,
                autoDelete: false,
                arguments: null);
            var classificationConsumer = new EventingBasicConsumer(channel);
            classificationConsumer.Received += (model, ea) =>
            {
                ConsumeClassificationResult(ea.Body.ToArray());
            };
            channel.BasicConsume(queue: "ClassificationResult",
                autoAck: true,
                consumer: classificationConsumer);
         }

依赖注入在Startup.cs中是这样设置的:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<IMachineLearningQueueListener, MachineLearningQueueListener>();
            services.AddScoped<IDocumentService, DocumentService>();
            services.AddScoped<IDocumentRepository, DocumentRepository>();
            services.AddDbContext<DocumentContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DocumentContext")));
        }

我正在使用存储库模式,因此侦听器使用 DocumentService,服务使用 DocumentRepository,存储库使用 DbContext。

抛出的错误如下图所示: ObjectDisposedException

非常感谢解决此问题的任何帮助。

解决方法是在StartListeningToQueue函数的末尾添加Console.Readline()以防止其退出。它不会阻止来自 EventingBasicConsumer 的基于事件的触发器,因此它可以接收消息。

RabbitMQ 的控制台应用程序教程中对此进行了记录:https://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html

我不知道是否有更清洁的解决方案,但目前可以使用。