Search code examples
c#exceptionasynchronous.net-6.0interceptor

C# - How to solve the "Interceptors failed to set a return value, or swallowed the exception thrown by the target" error?


Cannot seem to get the last piece of the puzzle into place. Appreciate any assistance :)

I have an interceptor that is logging the parameters and the return of the methods that I want to intercept. The interceptor method is as per below code (I am using .Net 6):

public override async void Intercept(IInvocation invocation)
{
            //Initial Logging

            object? result = null;
            Exception? taskException = null;
            try
            {
                invocation.Proceed();
                //This method retrieves the result from the invocation.Result according to whether the method being intercepted is synchronous, asynchronous returning void (Task) or asynchronous returning T (Task<T>).
                result = await Result(invocation);
            }
            catch
            {
                //Only throw the exception if the method is not asynchronous
                Type returnType = invocation.Method.ReturnType;
                if (!(returnType == typeof(Task) || (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))))
                {
                    throw;
                }
            }
            finally
            {
                //More logging
            }
}

I have 6 scenarios (methods with different return types) as per below:

# Description Result
1 Asynchronous method with return Task and return a successful response I manage to get the result as expected
2 Asynchronous method with return Task and return an exception I manage to capture the exception as expected
3 Asynchronous method with return Task and no exception returned Working as expected
4 Asynchronous method with return Task and return an exception I manage to capture the exception as expected
5 Synchronous method with return bool and return a successful response I manage to get the result as expected
6 Synchronous method with return bool and return an exception Application is crashing due to error 'Interceptors failed to set a return value, or swallowed the exception thrown by the target'

5 scenarios seem to work without any issue, but scenario 6 is returning an exception.

When I tried to remove the async keyword, scenario 6 worked a but as expected but scenarios 1 and 3, in the finally block statement, I was not able to get the actual result that the intercepted method was returning since I am never awaiting the result of the method.

Possible solutions that I can think of:

  1. the interceptor will be async and manage to return the exception of synchronous methods without getting the error mentioned in scenario 6
  2. the interceptor will not be async and manage to get the actual results of intercepted async methods
  3. any other possible solution is more than welcome

If more information is required, let me know and I'll try to provide as much information as possible.

Thanks in advance


Solution

  • You could move the content of Interceptor into an inner logic, like

    protected void InterceptCore(IInvocation invocation)
    {
                //Initial Logging
    
                object? result = null;
                Exception? taskException = null;
                try
                {
                    invocation.Proceed();
                    //This method retrieves the result from the invocation.Result according to whether the method being intercepted is synchronous, asynchronous returning void (Task) or asynchronous returning T (Task<T>).
                    result = await Result(invocation);
                }
                catch
                {
                    //Only throw the exception if the method is not asynchronous
                    Type returnType = invocation.Method.ReturnType;
                    if (!(returnType == typeof(Task) || (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))))
                    {
                        throw;
                    }
                }
                finally
                {
                    //More logging
                }
    }
    

    And implement another asynchronous method for doing it asynchronously:

    public async void InterceptCoreAsync(IInvocation invocation)
    {
        InterceptCore(invocation);
    }
    

    Now, let's overload and override Intercept:

    public override void Intercept(IInvocation invocation)
    {
        Intercept(invocation, true);
    }
    
    public void Intercept(IInvocation invocation, bool IsAsync)
    {
        IsAsync ? InterceptCoreAsync(invocation) : InterceptCore(invocation);
    }