question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

IRemoteRequestHandler.InvokeAsync() never returns when using AddMessagePipeNamedPipeInterprocess

See original GitHub issue

Hi, I’m having a bit of trouble bringing up MessagePipe for IPC-RPC using named pipes. I’ve attempted to use the code described in the README, but to no avail.

I have create two projects, Client and Server using dotnet new worker. Code is below. Server seems to run successfully, but never executes IAsyncRequestHandler.InvokeAsync . Client never returns from the call to InvokeAsync. Using MessagePipe 1.7.4, and .NET 6.0.

My apologies if I’m missing something obvious!

Client

Program.cs

using Client;
using MessagePipe;

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddMessagePipe();
        services.AddMessagePipeNamedPipeInterprocess("sample-pipe", config => config.InstanceLifetime = InstanceLifetime.Singleton );
        services.AddHostedService<Worker>();
    })
    .Build();

host.Run();

Worker.cs

using MessagePipe;

namespace Client;

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private readonly IRemoteRequestHandler<int, string> _remoteHandler;

    public Worker(ILogger<Worker> logger, IRemoteRequestHandler<int, string> remoteHandler)
    {
        _logger = logger;
        _remoteHandler = remoteHandler;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            var result = await _remoteHandler.InvokeAsync(1234);
            _logger.LogInformation("Received: {result}", result);
            await Task.Delay(1000, stoppingToken);
        }
    }
}

Server

Program.cs

using MessagePipe;
using Server;

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHostedService<Worker>();
        services.AddMessagePipe();
        services.AddMessagePipeNamedPipeInterprocess("sample-pipe");
    })
    .Build();

host.Run();

public class MyAsyncHandler : IAsyncRequestHandler<int, string>
{
    public async ValueTask<string> InvokeAsync(int request, CancellationToken cancellationToken = default)
    {
        await Task.Delay(1);
        if (request == -1)
        {
            throw new Exception("NO -1");
        }
        else
        {
            return "ECHO:" + request.ToString();
        }
    }
}

Worker.cs is unmodified from the template.

Issue Analytics

  • State:open
  • Created 7 months ago
  • Comments:5

github_iconTop GitHub Comments

2reactions
E-Rooijackerscommented, Apr 21, 2023

The problem seems to be that the NamedPipeWorker on the server side never gets initialized, thus not listens for connections. NamedPipeWorker will only be initialized by DI when a named pipe based request handler is created, but since no requests can be received, no request handler will get initialized. This is also the case with TCP based request handling.

Workaround for this problem is forcing initialization of NamedPipeWorker/TcpWorker by requesting an instance from the service provider. This way it will start listening for connections and requests can be received.

Also config.HostAsServer should be set to true for server side.

So server side code would then look like this:

using MessagePipe;
using MessagePipe.Interprocess.Workers;
using Server;

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddMessagePipe();
        services.AddMessagePipeNamedPipeInterprocess("sample-pipe", config => 
		{	
			config.InstanceLifetime = InstanceLifetime.Singleton;
			config.HostAsServer = true; // Should be true for server side.
		});
        services.AddHostedService<Worker>();
    })
    .Build();
	
using var namedPipeWorker = host.Services.GetRequiredService<NamedPipeWorker>(); // Initialize NamedPipeWorker
//using var tcpWorker = host.Services.GetRequiredService<TcpWorker>(); // Or TcpWorker for TCP based communication

host. Run();
1reaction
TaviTrumancommented, Apr 14, 2023

It seems like you have not registered your MyAsyncHandler in the dependency injection container on the server-side. You need to register the handler in the ConfigureServices method of your server’s Program.cs like this:

services.AddSingleton<IAsyncRequestHandler<int, string>, MyAsyncHandler>();

Here’s the updated Program.cs for the server:

using MessagePipe;
using Server;

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddHostedService<Worker>();
        services.AddMessagePipe();
        services.AddMessagePipeNamedPipeInterprocess("sample-pipe");
        services.AddSingleton<IAsyncRequestHandler<int, string>, MyAsyncHandler>();
    })
    .Build();

host. Run();

With these changes, your server should now execute the IAsyncRequestHandler.InvokeAsync method, and the client should receive the response.

Read more comments on GitHub >

github_iconTop Results From Across the Web

No results found

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found