Understanding Interceptors in C# and .NET

Introduction

Interceptors in C# and .NET are powerful tools for intercepting method calls, enabling developers to add cross-cutting concerns such as logging, validation, caching, and security to applications. These interceptors work by intercepting method invocations, allowing you to inject custom code before or after the execution of the target method.

What Are Interceptors?

Interceptors serve as intermediaries between the caller and the target method. They provide a way to modify the behaviour of methods without changing their code directly. Interceptors help achieve aspects of separation of concerns by adding functionalities without cluttering the main business logic.

In C# and .NET, there are various ways to implement interceptors. One common approach is by using libraries like Castle DynamicProxy or through native frameworks like Aspect-oriented Programming (AOP).

Implementing Interceptors Using Castle DynamicProxy

Castle DynamicProxy is a widely used library for creating dynamic proxies and implementing interceptors in C# applications. Below is an example demonstrating how to create a simple logging interceptor using Castle DynamicProxy:

Step 1. Install Castle.Core NuGet Package

Install-Package Castle.Core

Step 2. Create the Logging Interceptor

using Castle.DynamicProxy;
using System;
using System.Diagnostics;

public class LoggingInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        var method = invocation.Method.Name;
        var arguments = string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()));
        
        Console.WriteLine($"Calling method {method} with arguments: {arguments}");
        
        var stopwatch = Stopwatch.StartNew();
        invocation.Proceed(); // Calls the actual method
        
        Console.WriteLine($"Method {method} executed in {stopwatch.ElapsedMilliseconds} ms");
    }
}

Step 3. Apply the Interceptor to a Class

public interface ICalculator
{
    int Add(int a, int b);
}

public class Calculator : ICalculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}

class Program
{
    static void Main(string[] args)
    {
        var generator = new ProxyGenerator();
        var interceptor = new LoggingInterceptor();

        ICalculator calculator = generator.CreateInterfaceProxyWithTarget<ICalculator>(
            new Calculator(), interceptor);

        int result = calculator.Add(5, 10);
        Console.WriteLine($"Result: {result}");
    }
}

In this example, the LoggingInterceptor implements the IInterceptor interface from Castle DynamicProxy. It intercepts method calls made to the Calculator class and logs information about the method being called, its arguments, and the execution time.

Conclusion

Interceptors in C# and .NET offer a powerful way to add cross-cutting concerns to applications without tightly coupling them with the core business logic. Whether using libraries like Castle DynamicProxy or native AOP concepts, interceptors facilitate cleaner and more maintainable code by separating concerns effectively. With their flexibility and ease of implementation, interceptors remain an essential tool in the arsenal of modern C# developers.


Similar Articles