【问题标题】:How to configure MassTransit with Mediator to publish messages?如何使用 Mediator 配置 MassTransit 以发布消息?
【发布时间】:2020-11-11 13:51:36
【问题描述】:

我是 MassTransit 和 Mediator 的新手,我有一系列事件要按顺序执行,我正在使用 MassTransit进程内和内存中,对于我的用例,不需要传输。

我想通过Mediator向消费者、sagas、activity发送和发布消息,我有下面的代码,但我想通过在startup.cs注册MassTransit来改进它:

//asp net core 3.1 Controller

 [ApiController]
 public class MyController : ControllerBase
 {    
    private readonly IProductService _productService ;
    private readonly IMediator mediator;
    public MyController(IProductService productService)
    {
       _productService = productService;
      var repository = new InMemorySagaRepository<ApiSaga>();
      mediator = Bus.Factory.CreateMediator(cfg =>
      {
          cfg.Saga<ProductSaga>(repository);
      });
    }
   
     [HttpPost]
     public async Task<IActionResult> Post([FromBody] ProductContract productContract)
     {            
         try
         {
             var result = await _productService.DoSomeThingAsync(productContract);
             await mediator.Publish<ProductSubmittedEvent>(new { CorrelationId = Guid.NewGuid(), result.Label });
         return Ok();
         }
         catch (Exception ex)
         {
             return BadRequest(ex.Message);
         }
      }
 }

//My saga
public class ProductSaga :
        ISaga,
        InitiatedBy<ProductSubmittedEvent>
    {
        public Guid CorrelationId { get; set; }
        public string State { get; private set; } = "Not Started";

        public Task Consume(ConsumeContext<ProductSubmittedEvent> context)
        {
            var label= context.Message.Label;
            State = "AwaitingForNextStep";
            //...
           //send next command
        }
    }

像这样它可以工作,但它不正确,我想在我的startup.cs 中使用 Mediator 配置 masstransit 以获得一个正确的实例,为此我首先删除了 IMediator,使用 IPublishEndpoint 发布消息到Saga 并配置我的startup.cs,但它没有按预期工作:

//startup.cs

 public void ConfigureServices(IServiceCollection services)
 {
      services.AddMediator(cfg =>
            {
                cfg.AddSaga<ProductSaga>().InMemoryRepository();
            });
 }

//in controller using:
private readonly IPublishEndpoint _publishEndpoint;

//then
await _publishEndpoint.Publish<ProductSubmittedEvent>(
    new { CorrelationId = Guid.NewGuid(), result.Label });

我收到了System.InvalidOperationException:

在尝试激活“GaaS.API.Controllers.ManageApiController”时无法解析“MassTransit.IPublishEndpoint”类型的服务。

我尝试更新我的startup.cs:

var repository = new InMemorySagaRepository<ApiSaga>();
            services.AddMassTransit(cfg =>
            {
                cfg.AddBus(provider =>
                {
                    return Bus.Factory.CreateMediator(x =>
                    {
                        x.Saga<ProductSaga>(repository);
                    });
                });
            });

我明白了:

无法将类型“MassTransit.Mediator.IMediator”隐式转换为“MassTransit.IBusControl”。

如果你有任何推荐想法感谢分享和挑战我????

【问题讨论】:

    标签: c# dependency-injection masstransit


    【解决方案1】:

    在您的项目中配置 MassTransit Mediator 的正确方法是通过 Startup.cs 文件,您似乎已经尝试过。

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMediator(cfg =>
        {
            cfg.AddSaga<ProductSaga>().InMemoryRepository();
        });
    }
    

    使用调解器,您需要依赖IMediator 接口。您不能使用IPublishEndpoint 或ISendEndpointProvider,因为它们是总线接口。由于您可以在容器中同时拥有调解器和总线实例,因此在从容器中解析服务时会导致混乱。

    [ApiController]
    public class MyController : ControllerBase
    {    
        private readonly IProductService _productService ;
        private readonly IMediator _mediator;
    
        public MyController(IProductService productService, IMediator mediator)
        {
            _productService = productService;
            _mediator = mediator;
        }
    
        [HttpPost]
        public async Task<IActionResult> Post([FromBody] ProductContract productContract)
        {            
            try
            {
                var result = await _productService.DoSomeThingAsync(productContract);
                
                await _mediator.Publish<ProductSubmittedEvent>(new { CorrelationId = NewId.NextGuid(), result.Label });
    
                return Ok();
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }
    }
    

    如果您只使用调解器,并且想使用IPublishEndpoint,您可以自己将其添加到容器中并委托它。

    services.AddSingleton<IPublishEndpoint>(provider => provider.GetService<IMediator>());
    

    【讨论】:

    • 感谢您的澄清并回复我
    • 在这个用例中使用services.AddMediator(...)时如何使用services.AddMassTransitHostedService()?
    • 不需要,mediator既不启动也不停止,立即可用。
    【解决方案2】:

    我从(优秀的)youtube video - MassTransit starting with Mediator 得到这个,在那个示例中有一行代码

    AddMediator()
    

    我找不到。我相信以下设置提供了根据该视频使代码正常工作所需的一切...

                services.AddMassTransit(config =>
                {
                    config.AddRequestClient<ISubmitOrder>();
                    config.AddConsumersFromNamespaceContaining<SubmitOrderConsumer>();
    
                    config.UsingInMemory(ConfigureBus);
                });
    

    然后ConfigureBus 是:

            private void ConfigureBus(IBusRegistrationContext context, IInMemoryBusFactoryConfigurator configurator)
            {
                configurator.ConfigureEndpoints(context);
            }
    

    我在别处找不到这个,所以在这里发帖。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-19
      • 1970-01-01
      • 2012-08-06
      • 1970-01-01
      • 1970-01-01
      • 2023-03-29
      • 2017-11-18
      • 1970-01-01
      相关资源
      最近更新 更多