AspNetCore.Docs/aspnetcore/grpc/interprocess-namedpipes.md

3.6 KiB

title author description monikerRange ms.author ms.date uid
Inter-process communication with gRPC and Named pipes jamesnk Learn how to use gRPC for inter-process communication with Named pipes. >= aspnetcore-8.0 jamesnk 01/18/2023 grpc/interprocess-namedpipes

Inter-process communication with gRPC and Named pipes

By James Newton-King

.NET supports inter-process communication (IPC) using gRPC. For more information about getting started with using gRPC to communicate between processes, see Inter-process communication with gRPC.

Named pipes is an IPC transport that is supported on all versions of Windows. Named pipes integrate well with Windows security to control client access to the pipe. This article discusses how to configure gRPC communication over named pipes.

Prerequisites

  • .NET 8 or later
  • Windows

Server configuration

Named pipes are supported by Kestrel, which is configured in Program.cs:

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
    serverOptions.ListenNamedPipe("MyPipeName", listenOptions =>
    {
        listenOptions.Protocols = HttpProtocols.Http2;
    });
});

The preceding example:

Client configuration

GrpcChannel supports making gRPC calls over custom transports. When a channel is created, it can be configured with a xref:System.Net.Http.SocketsHttpHandler that has a custom xref:System.Net.Http.SocketsHttpHandler.ConnectCallback. The callback allows the client to make connections over custom transports and then send HTTP requests over that transport.

Named pipes connection factory example:

public class NamedPipesConnectionFactory
{
    private readonly string pipeName;

    public NamedPipesConnectionFactory(string pipeName)
    {
        this.pipeName = pipeName;
    }

    public async ValueTask<Stream> ConnectAsync(SocketsHttpConnectionContext _,
        CancellationToken cancellationToken = default)
    {
        var clientStream = new NamedPipeClientStream(
            serverName: ".",
            pipeName: this.pipeName,
            direction: PipeDirection.InOut,
            options: PipeOptions.WriteThrough | PipeOptions.Asynchronous,
            impersonationLevel: TokenImpersonationLevel.Anonymous);

        try
        {
            await clientStream.ConnectAsync(cancellationToken).ConfigureAwait(false);
            return clientStream;
        }
        catch
        {
            clientStream.Dispose();
            throw;
        }
    }
}

Using the custom connection factory to create a channel:

public static GrpcChannel CreateChannel()
{
    var connectionFactory = new NamedPipesConnectionFactory("MyPipeName");
    var socketsHttpHandler = new SocketsHttpHandler
    {
        ConnectCallback = connectionFactory.ConnectAsync
    };

    return GrpcChannel.ForAddress("http://localhost", new GrpcChannelOptions
    {
        HttpHandler = socketsHttpHandler
    });
}

Channels created using the preceding code send gRPC calls over named pipes.