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