Skip to content

C# Async Interceptor Null Reference Exception Issue ​

Problem Description ​

When using AOP frameworks like Castle DynamicProxy to intercept asynchronous methods, if the interceptor returns prematurely (without calling invocation.Proceed()), for example, by directly returning, methods that return Task<T> will return null. This leads to a NullReferenceException when the caller awaits the result.

Error Characteristics ​

plain
System.NullReferenceException: Object reference not set to an instance of an object.
   at YourNamespace.YourClass.YourMethod() in YourFile.cs:line XX
  • The exception line points to await someAsyncMethod()
  • The actual problem is that the interceptor returned null
  • It's difficult to pinpoint the root cause through stack traces because the error occurs within the await operation.

Solution ​

Properly handle the return value of asynchronous methods within the interceptor:

csharp
// Handle return values when the intercepted interface is disabled
if (settings?.IsEnabled == false)
{
    // For methods returning Task<T>
    if (invocation.Method.ReturnType.IsGenericType && 
        invocation.Method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
    {
        var returnType = invocation.Method.ReturnType.GetGenericArguments()[0];
        var defaultValue = returnType.IsValueType ? Activator.CreateInstance(returnType) : null;
        var tcs = typeof(TaskCompletionSource<>).MakeGenericType(returnType);
        var taskCompletionSource = Activator.CreateInstance(tcs);
        tcs.GetMethod("SetResult").Invoke(taskCompletionSource, new[] { defaultValue });
        invocation.ReturnValue = tcs.GetProperty("Task").GetValue(taskCompletionSource);
    }
    // For methods returning Task
    else if (invocation.Method.ReturnType == typeof(Task))
    {
        invocation.ReturnValue = Task.CompletedTask;
    }
    return;
}

Defensive Programming ​

Check the return value after calling a potentially intercepted method:

csharp
var response = await _service.SomeMethodAsync();
if (response == null)
{
    // Handle cases where the interceptor returns null
    return;
}

Last updated: