.NET 中 ClientInterceptorContext 的生命周期/范围是多少?

问题描述 投票:0回答:1

我在 .net 4.6.2 上有一个使用

Grpc.Core
库的 .NET gRPC 客户端。

我已将 gRPC 通道注册为单例以按照[此建议]重用它。(https://learn.microsoft.com/en-us/aspnet/core/grpc/performance?view=aspnetcore-7.0#reuse- grpc 通道

这就是我创建通道实例的方法:

public static InvokerAndChannel<T> CreateGrpcCallInvokerAndChannel<T>(
    string endpoint, ChannelCredentials credentials, IServiceProvider serviceProvider)
    where T : class
{
    var licenseCode = serviceProvider.GetRequiredService<ILicenseCodeResolver>().GetLicenseCode();

    var channel = new Channel(endpoint, credentials, new ChannelOption(ChannelOptions.MaxSendMessageLength, "1mb").Yield());
    var callInvoker = channel
        .Intercept(
            new ClientTracingInterceptor(
                new ClientTracingInterceptorOptions { RecordMessageEvents = false }))
        .Intercept(new StaticMetadataInterceptor(licenseCode));

    return new InvokerAndChannel<T>(callInvoker, channel);
}

如您所见,管道包括

StaticMetadataInterceptor
,它将许可证标头添加到调用中。实际上它也是一个单例。

我对同一 gRPC 服务的各种方法进行了多个并行调用。我看到

StaticMetadataInterceptor
收到相同的
ClientInterceptorContext
。至少
context.Options.Headers
不断增长,因此在多次调用后它会多次包含相同的标头。 为什么?

这是拦截器的代码:

internal sealed class StaticMetadataInterceptor : Interceptor
{
    private readonly string _licenseCode;

    public StaticMetadataInterceptor(string licenseCode)
    {
        _licenseCode = licenseCode;
    }

    private void ExtendMetadata<TRequest, TResponse>(ref ClientInterceptorContext<TRequest, TResponse> context)
            where TRequest : class
            where TResponse : class
    {
        var metadata = context.Options.Headers;
        if (metadata == null)
        {
            metadata = new Metadata();
            context = new ClientInterceptorContext<TRequest, TResponse>(context.Method, context. Host, context.Options.WithHeaders(metadata));
        }

        metadata.Add(GrpcStandardMetadataKeys.License, _licenseCode);
    }

    public override TResponse BlockingUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, BlockingUnaryCallContinuation<TRequest, TResponse> continuation)
    {
        ExtendMetadata(ref context);

        return continuation(request, context);
    }

    public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
    {
        ExtendMetadata(ref context);

        return continuation(request, context);
    }

    public override AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncClientStreamingCallContinuation<TRequest, TResponse> continuation)
    {
        ExtendMetadata(ref context);

        return continuation(context);
    }

    public override AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(TRequest request, ClientInterceptorContext<TRequest, TResponse> context, AsyncServerStreamingCallContinuation<TRequest, TResponse> continuation)
    {
        ExtendMetadata(ref context);

        return continuation(request, context);
    }

    public override AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(ClientInterceptorContext<TRequest, TResponse> context, AsyncDuplexStreamingCallContinuation<TRequest, TResponse> continuation)
    {
        ExtendMetadata(ref context);

        return continuation(context);
    }
}
c# .net grpc .net-4.6 grpc-dotnet
1个回答
0
投票

我找到了标题集合不断增长的原因。

生成的Grpc客户端有一个

Metada
类型的可选参数。我的假设是该集合中的项目将被复制,并且如果拦截器将标头添加到传出请求中,则初始元数据不会受到影响。这个假设是错误的。

示例:

var metadata = new Metadata();
client.CallFoo(request, metadata);

如果拦截器向请求添加标头,

metadata
将会改变。

© www.soinside.com 2019 - 2024. All rights reserved.