0

My goal is to make the communication between two applications (WebAPI and Worker) via MassTransit's Request/Response technique. The problem is that I'm never getting inside the consumer (request client), I'm getting a timeout instead.

I found a similar question already but the answer included a link to a github repository which no longer exists. I also tried following a sample but for some reason most samples are created as console applications which is useless for me since I have two WebAPIs trying to communicate with each other.

Anyway, here's my code:

WebAPI.Startup

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddMassTransit(massTransitConfig =>
        {
            massTransitConfig.UsingAzureServiceBus((ctx, cfg) =>
            {
                cfg.Host("Endpoint=sb://----.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=----");
            });
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

Worker.Startup

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddMassTransit(massTransitConfig =>
        {
            massTransitConfig.UsingAzureServiceBus((ctx, cfg) =>
            {
                cfg.Host("Endpoint=sb://----.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=----");
            });

            massTransitConfig.AddConsumer<CreateScheduleRequestClient>();
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

WebAPI.RequestController

[Route("api/requests")]
public class RequestsController : ControllerBase
{
    private readonly IBus _bus;

    public RequestsController(IBus bus)
    {
        _bus = bus;
    }

    [HttpPost("create-schedule")]
    public async Task<IActionResult> CreateSchedule()
    {
        var client = _bus.CreateRequestClient<CreateScheduleRequest>();
        var response = await client.GetResponse<ScheduleCreatedResponse>(new CreateScheduleRequest());

        return Ok(response.Message.Succeeded);
    }
}

DataTransferObjects.CreateScheduleRequest

public class CreateScheduleRequest
{
    public string CommandName { get; set; }
    public string Cron { get; set; }
}

Worker.RequestClients.CreateScheduleRequestClient

public class CreateScheduleRequestClient : IConsumer<CreateScheduleRequest>
{
    public async Task Consume(ConsumeContext<CreateScheduleRequest> context)
    {
        await context.RespondAsync(new ScheduleCreatedResponse(true));
    }
}

DataTransferObjects.ScheduleCreatedResponse

public class ScheduleCreatedResponse
{
    public bool Succeeded { get; }

    public ScheduleCreatedResponse(bool succeeded)
    {
        Succeeded = succeeded;
    }
}

When I call the only endpoint in the RequestsController, I'm getting MassTransit.RequestTimeoutException: Timeout waiting for response, RequestId: 27f60000-167b-00ff-ea0f-08d8e3a0832e after a short period. I'm not able to verify much more about it, I thought it outght to work out of the box but perhaps I'm missing some parameters when initializing the bus in my Startup classes?

================EDIT================ I changed my code a little with regards to what Chris Patterson suggested and to specify that I'd like to go with the IBus approach. The code still throws the same exception after the change.

Aranha
  • 2,903
  • 3
  • 14
  • 29

1 Answers1

0

First, I'd suggest reviewing the request documentation, in particular the controller example that injects IRequestClient<T> into the controller. That will fix your controller code, which shouldn't be using IBus.

Second, your response should be an actual message type, it can't be true. You need to create a second message contract, such as ScheduleRequestCreated and respond with that message type. Then, your GetResponse would change to

GetResponse<ScheduleRequestCreated>(new CreateScheduleRequest(...))

And your response would be:

RespondAsync(new ScheduleRequestCreated(...))

Chris Patterson
  • 28,659
  • 3
  • 47
  • 59
  • Thank you for your response! I'll try that tomorrow in the morning. Just one question, though - why shouldn't I use `IBus`? If I had a controller that has 20 endpoints and 20 different MassTransit requests can be sent from them, I'd end up having a constructor with 20 parameters which is insane. Could you briefly explain? – Aranha Mar 10 '21 at 21:04
  • That's a different situation, but given you're calling `AddRequestClient` you should use it. If you're going to create the client in the controller, don't bother registering it. – Chris Patterson Mar 10 '21 at 23:44
  • I did exactly what you described (added a response dto, used it in `GetResponse`, removed injection of `IBus` in the controller and replaced it with `IRequestClient`) but that did not the trick, still getting the timeout. I also tried removing injection of IRequestClient (removed `AddRequestClient` as well) and injected IBus but this approached ended up the same way. I'll update my original question with the new code (I'd rather go with the `IBus` approach) – Aranha Mar 11 '21 at 08:09