.NET  

What are gRPC interceptors in .NET and how do I use them?

Introduction

When building gRPC services in .NET, you often need to run common logic across multiple requests, such as logging, authentication checks, or error handling. Writing this logic inside every method can make your code messy and hard to maintain.

This is where gRPC interceptors come in.

In this article, we will understand what interceptors are, how they work, and how to use them effectively in ASP.NET Core in simple and clear language.

What are gRPC Interceptors?

Interceptors in gRPC are similar to middleware in ASP.NET Core.

They allow you to:

  • Intercept incoming requests before they reach the service

  • Intercept outgoing responses before they are sent back to the client

  • Add common logic in one central place

This helps you keep your service methods clean and focused only on business logic.

How Interceptors Work Internally

When a request is sent to a gRPC service, it goes through a pipeline.

  • First, interceptors get a chance to process the request

  • Then, the actual service method is executed

  • After that, the response passes back through interceptors

This means interceptors can run logic both before and after the service method.

Types of Interceptors in gRPC

In .NET, you can use interceptors for different types of calls:

  • Unary calls (single request and response)

  • Server streaming

  • Client streaming

  • Bidirectional streaming

Each type has its own handler method in the interceptor class.

Creating a Basic Interceptor

Let’s create a simple logging interceptor.

public class LoggingInterceptor : Interceptor
{
    public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
        TRequest request,
        ServerCallContext context,
        UnaryServerMethod<TRequest, TResponse> continuation)
    {
        Console.WriteLine("Request received");

        var response = await continuation(request, context);

        Console.WriteLine("Response sent");

        return response;
    }
}

Here’s what is happening:

  • Code before continuation runs before the service method

  • Code after continuation runs after the service method

Registering an Interceptor

To use the interceptor, register it in your application.

builder.Services.AddGrpc(options =>
{
    options.Interceptors.Add<LoggingInterceptor>();
});

Now, this interceptor will run for all gRPC calls.

Using Interceptors for Authentication

Interceptors are commonly used for authentication.

public class AuthInterceptor : Interceptor
{
    public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
        TRequest request,
        ServerCallContext context,
        UnaryServerMethod<TRequest, TResponse> continuation)
    {
        var token = context.RequestHeaders.FirstOrDefault(h => h.Key == "authorization")?.Value;

        if (string.IsNullOrEmpty(token))
        {
            throw new RpcException(new Status(StatusCode.Unauthenticated, "Token missing"));
        }

        return await continuation(request, context);
    }
}

This ensures that every request is validated before reaching the service.

Using Interceptors for Error Handling

You can also use interceptors for centralized error handling.

public class ExceptionInterceptor : Interceptor
{
    public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
        TRequest request,
        ServerCallContext context,
        UnaryServerMethod<TRequest, TResponse> continuation)
    {
        try
        {
            return await continuation(request, context);
        }
        catch (Exception)
        {
            throw new RpcException(new Status(StatusCode.Internal, "Something went wrong"));
        }
    }
}

This avoids repeating try-catch blocks in every service method.

Chaining Multiple Interceptors

You can register multiple interceptors.

builder.Services.AddGrpc(options =>
{
    options.Interceptors.Add<LoggingInterceptor>();
    options.Interceptors.Add<AuthInterceptor>();
});

They will execute in the order they are registered.

Best Practices for Using Interceptors

  • Keep interceptors focused on a single responsibility

  • Avoid heavy processing inside interceptors

  • Use them for cross-cutting concerns like logging and security

  • Do not put business logic inside interceptors

Following these practices keeps your code clean and maintainable.

Common Mistakes to Avoid

  • Adding too much logic inside interceptors

  • Not handling exceptions properly

  • Forgetting to register interceptors

Avoiding these mistakes will help you use interceptors effectively.

When Should You Use Interceptors?

You should use interceptors when you need:

  • Logging across all requests

  • Authentication and authorization checks

  • Error handling

  • Request/response modification

They are very useful in large applications with multiple services.

Summary

gRPC interceptors in .NET are a powerful way to handle cross-cutting concerns like logging, authentication, and error handling in a centralized way. They work like middleware and allow you to intercept requests and responses. By using interceptors properly, you can keep your service methods clean, improve maintainability, and build scalable applications.