Understanding Interceptors in .NET

DotNet Full Stack Dev
3 min readJun 19, 2024

--

Interceptors play a crucial role in modern software development by allowing developers to add cross-cutting concerns (like logging, caching, and transaction management) in a clean and reusable manner. In this blog, we’ll explore what interceptors are, why they are useful, and how to implement them in .NET with practical code snippets.

Embark on a journey of continuous learning and exploration with DotNet-FullStack-Dev. Uncover more by visiting our https://dotnet-fullstack-dev.blogspot.com reach out for further information.

What are Interceptors?

Interceptors are a design pattern that allows you to intercept and manipulate method calls, property access, or other actions before they reach their intended target. They enable you to add pre- and post-processing logic around these actions without modifying the actual business logic.

Why Use Interceptors?

  1. Separation of Concerns: Keep business logic clean by separating cross-cutting concerns.
  2. Reusability: Reuse common logic (e.g., logging, caching) across different parts of the application.
  3. Maintainability: Centralize common functionalities making the code easier to maintain and update.

Implementing Interceptors in .NET

In .NET, you can implement interceptors using various libraries, such as Castle Windsor, Autofac, or DynamicProxy. For simplicity, we’ll focus on using Castle DynamicProxy to create a basic logging interceptor.

Step-by-Step Implementation

Step 1: Install Castle Core

First, install the Castle Core package using NuGet. This package provides the DynamicProxy functionality that we’ll use for our interceptors.

dotnet add package Castle.Core

Step 2: Define the Interceptor

Create a logging interceptor that will log method calls.

using Castle.DynamicProxy;
using System;

public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine($"Calling method {invocation.Method.Name} with parameters {string.Join(", ", invocation.Arguments)}");

invocation.Proceed();

Console.WriteLine($"Method {invocation.Method.Name} returned {invocation.ReturnValue}");
}
}

Step 3: Create an Interface and Class

Define an interface and a class to demonstrate the interceptor.

public interface IOrderService
{
void PlaceOrder(string product, int quantity);
}

public class OrderService : IOrderService
{
public void PlaceOrder(string product, int quantity)
{
Console.WriteLine($"Order placed: {product}, Quantity: {quantity}");
}
}

Step 4: Create a Proxy Generator

Use the proxy generator to create a proxy of the OrderService with the logging interceptor.

public class Program
{
public static void Main(string[] args)
{
var proxyGenerator = new ProxyGenerator();
var orderService = proxyGenerator.CreateInterfaceProxyWithTarget<IOrderService>(
new OrderService(),
new LoggingInterceptor());

orderService.PlaceOrder("Laptop", 1);
}
}

Explanation of Code Snippets

  1. LoggingInterceptor: This class implements IInterceptor from Castle DynamicProxy. The Intercept method is called before and after the target method execution. It logs the method name, parameters, and return value.
  2. IOrderService and OrderService: These represent the business logic. OrderService implements the IOrderService interface.
  3. Proxy Generator: In the Main method, we use ProxyGenerator to create a proxy for OrderService. This proxy includes the logging logic provided by LoggingInterceptor.

Additional Use Cases

Caching Interceptor

You can create a caching interceptor to cache method results and return the cached result on subsequent calls.

using System.Collections.Generic;

public class CachingInterceptor : IInterceptor
{
private readonly Dictionary<string, object> _cache = new Dictionary<string, object>();

public void Intercept(IInvocation invocation)
{
var key = $"{invocation.Method.Name}-{string.Join("-", invocation.Arguments)}";

if (_cache.TryGetValue(key, out var cachedResult))
{
invocation.ReturnValue = cachedResult;
return;
}

invocation.Proceed();
_cache[key] = invocation.ReturnValue;
}
}

Usage with Caching Interceptor

var orderService = proxyGenerator.CreateInterfaceProxyWithTarget<IOrderService>(
new OrderService(),
new LoggingInterceptor(),
new CachingInterceptor());

orderService.PlaceOrder("Laptop", 1);
orderService.PlaceOrder("Laptop", 1); // This will return the cached result

Conclusion

Interceptors are a powerful tool in .NET for handling cross-cutting concerns like logging, caching, and transaction management. By using libraries like Castle DynamicProxy, you can implement interceptors in a clean and maintainable way. This blog demonstrated how to create and apply interceptors with practical code examples, illustrating their benefits and versatility. Whether you need to log method calls, cache results, or handle transactions, interceptors provide a reusable and modular approach to enhance your application’s functionality.

--

--

DotNet Full Stack Dev
DotNet Full Stack Dev

Written by DotNet Full Stack Dev

Join me to master .NET Full Stack Development & boost your skills by 1% daily with insights, examples, and techniques! https://dotnet-fullstack-dev.blogspot.com

No responses yet