Can I receive a scoped dependency for a C# gRPC Client Interceptor?

87 Views Asked by At

I am using a gRPC client inside a web API controller method to make a call out to a database and I want all of the calls made to add some common metadata in a transparent fashion. That is, I don't want to have to consciously add Metadata to every gRPC client call. A gRPC Interceptor seems perfect for this but to add that common metadata for each call, I need to resolve a scoped dependency that gives me the data I need to put in the gRPC call metadata.

Just as a similar example, in a .NET Core Middleware, I can resolve scoped dependencies by adding parameters to the InvokeAsync(...) method like this:

    public async Task InvokeAsync(HttpContext context, IMyScopedDependency myService)
    {

However, I am not sure if / how I can do the same thing with a gRPC Client Interceptor as those override methods from the base Interceptor class and I can't add arbitrary extra parameters to them.

Is there some clever way I am missing to inject a scoped lifetime dependency into the interceptor public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(...) method?

1

There are 1 best solutions below

0
BearsEars On BEST ANSWER

I figured this out by doing the following...

Registering my interceptor with a scoped lifetime:

builder.Services.AddScoped<MyInterceptor>();

Registering my dependency with a scoped lifetime:

builder.Services.AddScoped<IMyDependencyService, MyDependencyService>();

In my interceptor, I receive the scoped dependency via DI in the constructor:

internal class MyInterceptor: Interceptor
{
    private readonly IMyDependencyService _dependency;

    public MyInterceptor(IMyDependencyService dependency)
    {
        _dependency = dependency;
    }

I used Grpc.Net.ClientFactory to register my gRPC client with an interceptor using the InterceptorScope.Client lifetime option:

services.AddGrpcClient<MyGrpcClient>(o =>
{
    o.Address = new Uri("http://localhost:5000");
}).AddInterceptor(Grpc.Net.ClientFactory.InterceptorScope.Client, (sp) => sp.GetRequiredService<MyInterceptor>());

Finally, in my Web API controller, I receive the client via DI in the constructor and then I can use it in the controller methods:

[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
    private readonly MyGrpcClient _client;
    private readonly ILogger<TestController> _logger;

    public TestController(MyGrpcClient client, ILogger<TestController> logger)
    {
        _client = client;
        _logger = logger;
    }