次の方法で共有


gRPC および名前付きパイプとのプロセス間通信

作成者: James Newton-King

.NET では、gRPC を使用したプロセス間通信 (IPC) がサポートされています。 gRPC を使用してプロセス間の通信を開始する方法の詳細については、 gRPC とのプロセス間通信を参照してください。

名前付きパイプ は、すべてのバージョンの Windows でサポートされている IPC トランスポートです。 名前付きパイプは 、Windows セキュリティ とうまく統合され、パイプへのクライアント アクセスを制御します。 この記事では、名前付きパイプを介して gRPC 通信を構成する方法について説明します。

[前提条件]

  • .NET 8 以降
  • ウィンドウズ

サーバー構成

名前付きパイプは、Kestrelで構成されているProgram.csでサポートされています。

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

上記の例の場合:

  • KestrelでConfigureKestrelのエンドポイントを構成します。
  • ListenNamedPipeを呼び出して、指定した名前の名前付きパイプをリッスンします。
  • HTTPS を使用するように構成されていない名前付きパイプ エンドポイントを作成します。 HTTPS の有効化の詳細については、HTTPS エンドポイントの構成Kestrel参照してください。

名前付きパイプの PipeSecurity の構成

接続できるユーザーまたはグループを制御するには、 NamedPipeTransportOptions クラスを使用します。 これにより、カスタム PipeSecurity オブジェクトを指定できます。

例:

using Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes;
using System.IO.Pipes;
using System.Security.AccessControl;

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

        // Configure PipeSecurity
        listenOptions.UseNamedPipes(options =>
        {
            var pipeSecurity = new PipeSecurity();
            // Grant read/write access to the Users group
            pipeSecurity.AddAccessRule(new PipeAccessRule(
                "Users",
                PipeAccessRights.ReadWrite,
                AccessControlType.Allow));
            // Add additional rules as needed

            options.PipeSecurity = pipeSecurity;
        });
    });
});

上記の例の場合:

  • UseNamedPipesを使用して、NamedPipeTransportOptionsにアクセスして構成します。
  • 名前付きパイプに接続できるユーザーまたはグループを制御する PipeSecurity プロパティを設定します。
  • Users グループへの読み取り/書き込みアクセスを許可します。 シナリオでは、必要に応じて追加のセキュリティ規則を追加できます。

Kestrel 名前付きパイプ エンドポイントをカスタマイズする

Kestrelの名前付きパイプのサポートにより、高度なカスタマイズが可能になり、 CreateNamedPipeServerStream オプションを使用してエンドポイントごとに異なるセキュリティ設定を構成できます。 この方法は、複数の名前付きパイプ エンドポイントで一意のアクセス制御が必要なシナリオに最適です。 .NET 9 以降では、エンドポイントごとにパイプをカスタマイズする機能を使用できます。

これが役立つ例は、アクセス セキュリティが異なる 2 つのパイプ エンドポイントを必要とする Kestrel アプリです。 CreateNamedPipeServerStream オプションを使用すると、パイプ名に応じて、カスタム セキュリティ設定でパイプを作成できます。


var builder = WebApplication.CreateBuilder();
builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenNamedPipe("pipe1");
    options.ListenNamedPipe("pipe2");
});

builder.WebHost.UseNamedPipes(options =>
{
    options.CreateNamedPipeServerStream = (context) =>
    {
        var pipeSecurity = CreatePipeSecurity(context.NamedPipeEndpoint.PipeName);

        return NamedPipeServerStreamAcl.Create(context.NamedPipeEndpoint.PipeName, PipeDirection.InOut,
            NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte,
            context.PipeOptions, inBufferSize: 0, outBufferSize: 0, pipeSecurity);
    };
});

クライアントの構成

GrpcChannel では、カスタム トランスポートに対する gRPC 呼び出しの作成がサポートされています。 チャネルが作成されると、カスタム SocketsHttpHandlerを持つConnectCallbackを使用してチャネルを構成できます。 コールバックを使用すると、クライアントはカスタム トランスポート経由で接続を行い、そのトランスポート経由で HTTP 要求を送信できます。

クライアント側の負荷分散やチャネルの状態など、 GrpcChannelの一部の接続機能を名前付きパイプと一緒に使用することはできません。

名前付きパイプ接続工場の例:

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;
        }
    }
}

カスタム接続ファクトリを使用してチャネルを作成する:

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
    });
}

上記のコードを使用して作成されたチャネルは、名前付きパイプ経由で gRPC 呼び出しを送信します。