MassTransit 建议以 IServiceProvider 作为负载提供与容器无关的 Scope Provider

MassTransit suggestion to provide a container agnostic Scope Provider with IServiceProvider as a payload

我在向 MassTransit 存储库提交问题之前在这里问这个问题...

目前,有许多 MassTransit 容器扩展提供范围提供程序的实现,这些提供程序将容器特定接口添加到 ConsumeContext 的有效负载。

例如:

相反,如果所有这些扩展将 IServiceProvider 添加到上下文负载而不是它们的容器特定接口,以便下游消费者可以将自己与容器框架分离,那不是更好吗?

现在,我们必须使用以下逻辑来访问底层 IServiceProvider

interface IWidgetService
{
    Task DoSomethingAsync();
}

class WidgetService : IWidgetService
{
    public Task DoSomethingAsync()
    {
        throw new NotImplementedException();
    }
}

private static void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IWidgetService, WidgetService>();

    services.AddTransient<IConsumerScopeProvider, DependencyInjectionConsumerScopeProvider>();
    services.AddTransient(typeof(IConsumerFactory<>), typeof(ScopeConsumerFactory<>));
}

private static IBusControl CreateBus(IServiceProvider serviceProviderRoot)
{
    var busControl = Bus.Factory.CreateUsingRabbitMq(bus =>
    {
        var host = bus.Host("127.0.0.1", "/", configurator =>
        {
            configurator.Username("guest");
            configurator.Password("guest");
        });

        bus.ReceiveEndpoint(host, "test-queue", configurator =>
        {
            configurator.UseExecuteAsync(async context =>
            {
                var consumerScopeProvider = serviceProviderRoot.GetRequiredService<IConsumerScopeProvider>();
                using (var scope = consumerScopeProvider.GetScope(context))
                {
                    // this next line of code is where we must access the payload
                    // using a container specific interface to get access to the
                    // scoped IServiceProvider
                    var serviceScope = scope.Context.GetPayload<IServiceScope>();
                    var serviceProviderScoped = serviceScope.ServiceProvider;

                    var widgetService = serviceProviderScoped.GetRequiredService<IWidgetService>();

                    await widgetService.DoSomethingAsync().ConfigureAwait(false);
                }
            });

            // additional receive endpoint configuration...
        });
    });

    return busControl;
}

此外,我不确定这是否是一个错误,但是 DependencyInjectionStateMachineActivityFactory 的当前实现不会总是抛出异常,因为当前没有任何内容将 IServiceProvider 添加到有效负载上下文中吗?

public class DependencyInjectionStateMachineActivityFactory :
    IStateMachineActivityFactory
{
    public Activity<TInstance, TData> GetActivity<TActivity, TInstance, TData>(BehaviorContext<TInstance, TData> context)
        where TActivity : Activity<TInstance, TData>
    {
        // this next line will always fail, correct?
        var serviceProvider = context.GetPayload<IServiceProvider>();

        return serviceProvider.GetRequiredService<TActivity>();
    }

    public Activity<TInstance> GetActivity<TActivity, TInstance>(BehaviorContext<TInstance> context) where TActivity : Activity<TInstance>
    {
        // this next line will always fail, correct?
        var serviceProvider = context.GetPayload<IServiceProvider>();

        return serviceProvider.GetRequiredService<TActivity>();
    }
}

Microsoft Extensions Dependency Injection 包缺少一些扩展方法,我已添加并随 5.0.2 一起发布。