【问题标题】:How to inject dependency into NServiceBus pipeline behavior?如何将依赖项注入 NServiceBus 管道行为?
【发布时间】:2020-02-25 23:40:58
【问题描述】:

我一直在关注 NServiceBus 示例,特别是关于如何使用与 Sql Persistence 集成的实体框架(核心)DbContext,以便我可以将 dbcontext 状态更改与发件箱消息一起保存。这是示例:https://docs.particular.net/samples/entity-framework-core/

我稍微修改了工作单元代码以支持创建 aspnet 核心 DI 范围 DbContext。相关代码如下:

    public class UnitOfWork<TDbContext>
        where TDbContext : DbContext
    {
        private Func<SynchronizedStorageSession, IServiceProvider, TDbContext> _contextFactory;
        private TDbContext _context;
        private IServiceProvider _serviceProvider;

        public UnitOfWork(Func<SynchronizedStorageSession, IServiceProvider, TDbContext> contextFactory, IServiceProvider serviceProvider)
        {
            _contextFactory = contextFactory;
            _serviceProvider = serviceProvider;
        }

        public TDbContext GetDataContext(SynchronizedStorageSession storageSession)
        {
            if (_context == null)
            {
                _context = _contextFactory(storageSession, _serviceProvider);
            }
            return _context;
        }
    }

    public class UnitOfWorkSetupBehavior<TDbContext> : Behavior<IIncomingLogicalMessageContext>
        where TDbContext : DbContext
    {
        private readonly Func<SynchronizedStorageSession, IServiceProvider, TDbContext> _contextFactory;
        private readonly IServiceScopeFactory _serviceScopeFactory;

        public UnitOfWorkSetupBehavior(Func<SynchronizedStorageSession, IServiceProvider, TDbContext> contextFactory, IServiceScopeFactory serviceScopeFactory)
        {
            _contextFactory = contextFactory;
            _serviceScopeFactory = serviceScopeFactory;
        }

        public override async Task Invoke(IIncomingLogicalMessageContext context, Func<Task> next)
        {
            using (var scope = _serviceScopeFactory.CreateScope())
            {
                var uow = new UnitOfWork<TDbContext>(_contextFactory, scope.ServiceProvider);
                context.Extensions.Set(uow);

                await next().ConfigureAwait(false);

                context.Extensions.Remove<UnitOfWork<TDbContext>>();
            }
        }
    }

    public static class EndpointConfigurationExtensions
    {
        public static void RegisterUnitOfWork<TDbContext>(this EndpointConfiguration endpointConfiguration, IServiceScopeFactory serviceScopeFactory)
            where TDbContext : DbContext
        {
            var pipeline = endpointConfiguration.Pipeline;
            pipeline.Register(new UnitOfWorkSetupBehavior<TDbContext>((storageSession, serviceProvider) =>
            {
                var dbConnection = storageSession.SqlPersistenceSession().Connection;
                var dbContextFactory = serviceProvider.GetService<IDbContextConnectionFactory<TDbContext>>();
                var dbContext = dbContextFactory.GetDbContext(dbConnection);

                //Use the same underlying ADO.NET transaction
                dbContext.Database.UseTransaction(storageSession.SqlPersistenceSession().Transaction);

                //Call SaveChanges before completing storage session
                storageSession.SqlPersistenceSession().OnSaveChanges(x => dbContext.SaveChangesAsync());

                return dbContext;
            }, serviceScopeFactory), "Sets up unit of work for the message");
        }
    }

    public static class UnitOfWorkContextExtensions
    {
        public static TDbContext DataContext<TDbContext>(this IMessageHandlerContext context)
            where TDbContext : DbContext
        {
            var uow = context.Extensions.Get<UnitOfWork<TDbContext>>();
            return uow.GetDataContext(context.SynchronizedStorageSession);
        }
    }

为此,行为需要注入的 IServiceScopeFactory。

现在,我能够找到的所有行为注册示例仅显示手动实例化并传递到端点配置管道的类型。

有没有办法通过行为的 Invoke 方法获得对 IServiceScopeFactory 的访问权限(可能通过上下文通过某些扩展?),或者是否可以注册行为本身,以便我可以使用由创建的服务构建它DI 容器?

仅供参考,我查看了this Q&A,它让我想到了注入 IServiceScopeFactory。不幸的是,答案没有显示如何实际获取接口的实例。

【问题讨论】:

    标签: nservicebus


    【解决方案1】:

    您可以在Invoke 方法中使用context.builder.Build&lt;T&gt;(); 来解析任何对象,例如IServiceScopeFactory

    确保IServiceScopeFactory 已在 DI 容器中注册。例如,在您的端点初始化期间:

    endpointConfiguration.RegisterComponents(registration: x =>
        {
            x.ConfigureComponent<IServiceScopeFactory>(yourServiceScopeFactory);
        });
    

    您也可以通过创建功能来做到这一点

    【讨论】:

    • Ramon,不确定第一行说我应该使用什么,但多租户链接帮助了我。我假设它的意思是写“context.builder.Build()”,因为这就是我使用的那个有效?如果你修好这条线,我会标记为正确的。补充一下,我不需要组件注册,因为我使用 MS DI 在 dotnet 核心通用主机中托管。不过,我会在您的回答中留下信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-27
    相关资源
    最近更新 更多