Masstransit как получить ILifetimeScope в настраиваемом фильтре - PullRequest
0 голосов
/ 13 июля 2020

Я использую MT версии 6.3.2.

Я создал веб-API, который затем отправляет сообщение в очередь потребителя. У меня есть другой процесс, который потребляет сообщение.

Отправить в api:

var endpoint = await Bus.GetSendEndpoint(QueueUri);                        
await endpoint.Send(command);

В процессе потребителя я использую HostBuilder для регистрации autofa c

var host = new HostBuilder()
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())                  
            .ConfigureContainer<ContainerBuilder>((hostBuilderContext, builder) =>
            {                
                builder.RegisterModule(module);
            }

В модуле, который я регистрирую экземпляр IBus, я добавил такой фильтр:

builder.Register(cc =>
    {return Bus.Factory.CreateUsingRabbitMq(rabbit =>
        {
            rabbit.Durable = true;
            rabbit.Host(ServerName, h =>
            {
                h.Username(Username);
                h.Password(Password);
            });
            
            rabbit.ReceiveEndpoint(Queue, rec =>
                {
                    rec.AddPipeSpecification(new MyFilterSpecification<T>());
                    rec.Consumer<TConsumer>(cc);
                });
        });
    })
    .As<IBusControl>()
    .As<IBus>()
    .SingleInstance();

Я также зарегистрировал BackgroundService для запуска и остановки шины.

В MyFilter я хотел бы для разрешения зависимости, зарегистрированной с помощью InstancePerLifetimeScope в методе Send фильтра.

public class MyFilter<T> : IFilter<T> where T : class, PipeContext
{

    public Task Send(T context, IPipe<T> next)
    {
        context.TryGetPayload(out ILifetimeScope scope);
        // scope here is null
    }
}

Как и выше, область равна нулю. Однако позже в конвейере тот же код в моем Consumer.Consume () возвращает значение. Я видел образцы кода, в которых вы можете использовать ILifetimeScope в фильтре, я не уверен, почему он не работает для меня.

Как я могу разрешить мою зависимость в фильтрах? Я не могу использовать внедрение конструктора, так как это работает только для одноэлементных зависимостей.

1 Ответ

0 голосов
/ 13 июля 2020

Если вы отправляете за пределы потребителя, используя ISendEndpointProvider, вам необходимо создать область, как показано ниже. Область времени жизни будет включена в полезные данные и доступна фильтру.

public static async Task Main()
{    
    var builder = new ContainerBuilder();
    builder.AddMassTransit(x =>
    {
        x.AddBus(provider => Bus.Factory.CreateUsingInMemory(cfg =>
        {
            cfg.ConfigureSend(s => s.UseFilter(new MySendFilter()));
        }));
    });

    var container = builder.Build();

    var busControl = container.Resolve<IBusControl>();

    await busControl.StartAsync();

    try
    {
        using var scope = container.BeginLifetimeScope();

        var provider = scope.Resolve<ISendEndpointProvider>();

        var endpint = await provider.GetSendEndpoint(new Uri("queue:some-address"));

        await endpoint.Send<SomeMessage>(new { Value = "Hello"});
    }
    finally
    {
        await busControl.StopAsync();
    }
}

class MySendFilter :
    IFilter<SendContext>
{
    public async Task Send(SendContext context, IPipe<SendContext> next)
    {
        var lifetimeScope = context.GetPayload<ILifetimeScope>();

        await next.Send(context);
    }

    public void Probe(ProbeContext context)
    {
    }
}
...