微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Autofac 在 MediatR 处理程序完成工作之前处理我的 DbContext

如何解决Autofac 在 MediatR 处理程序完成工作之前处理我的 DbContext

我有一个 MediatR 通知处理程序。当用户发出请求时会调用通知,因此我想在后台处理该事件。从 MediatR wiki 中,我采用了一个类来并行调用处理程序,而无需等待它们的完成。见here

需要延迟一秒钟才能完成请求并演示我的问题。没有延迟,它随机发生。

存储库是通过注入传输的,一切都很好。但是来自 EFCore 的 DbContext 在用户请求完成后被标记为已处理。因此,无法保存结果。

我只想在后台完成这项工作。

Mediator 和 Repository 的代码注入:

builder.RegisterGeneric(typeof(EfRepository<>))
                .As(typeof(IRepository<>))
                .As(typeof(IReadRepository<>))
                .InstancePerLifetimeScope();

            builder
                .RegisterType<CustomMediator>()
                .As<IMediator>()
                .InstancePerLifetimeScope();

            builder.Register<ServiceFactory>(context =>
            {
                var c = context.Resolve<IComponentContext>();
                return t => c.Resolve(t);
            });

            var mediatrOpenTypes = new[]
            {
                typeof(IRequestHandler<,>),typeof(IRequestExceptionHandler<,typeof(IRequestExceptionAction<,typeof(INotificationHandler<>),};

            foreach (var mediatrOpenType in mediatrOpenTypes)
            {
                builder
                .RegisterassemblyTypes(_assemblies.ToArray())
                .AsClosedTypesOf(mediatrOpenType)
                .AsImplementedInterfaces();
            }

DbContext 的代码注入:

public static void AddDbContext(this IServiceCollection services,string connectionString) =>
            services.AddDbContext<AppDbContext>(options =>
                options.Usesqlite(connectionString)); // will be created in web project root

来自我的 CustomMediator 的方法 PublishCore 的代码

protected override Task PublishCore(IEnumerable<Func<INotification,CancellationToken,Task>> allHandlers,INotification notification,CancellationToken cancellationToken)
   {
     foreach (var handler in allHandlers)
     {
       _ = Task.Run(() => handler(notification,cancellationToken));
     }
     return Task.CompletedTask;
   }

来自我的 INotificationHandler 的方法代码

public async Task Handle(NewCaptchaAddedEvent domainEvent,CancellationToken cancellationToken)
{
   Guard.Against.Null(domainEvent,nameof(domainEvent));
   var captcha = domainEvent.Captcha;
   await Task.Delay(1000);
   var solution = await _vkCaptchaSolver.solveCaptcha(captcha.CaptchaUri);
   captcha.MarkSolved(solution);
   await _repository.UpdateAsync(captcha);
   return;
}

更新 1 我找到了这种行为的原因。重点是在LifetimeScope中,MediatR在创建时使用当前的,这是web请求的范围,所以所有的子节点都被销毁了。我做了一个小黑客。它很脏。当中介想要接收服务时,只需在根作用域中创建一个新作用域:

builder.Register<ServiceFactory>(context =>
            {
                var c = context.Resolve<ILifetimeScope>();
                var newl = (c as LifetimeScope).RootLifetimeScope.BeginLifetimeScope();
                return t => newl.Resolve(t);
            });

但这只是一个临时解决方案,问题仍然存在,如何正确创建范围或不将其销毁?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。