Ниже приведен код из метода Intercept для настраиваемого типа, который реализует IInterceptor библиотеки Castle Dynamic Proxy. Этот фрагмент представлен из AOP, основанного на протоколе верификации консольного приложения, которое опубликовано .
public void Intercept(IInvocation invocation)
{
if (Log.IsDebugEnabled) Log.Debug(CreateInvocationLogString("Called", invocation));
try
{
invocation.Proceed();
if (Log.IsDebugEnabled)
if (invocation.Method.ReturnType != typeof(void))
Log.Debug("Returning with: " + invocation.ReturnValue);
}
catch (Exception ex)
{
if (Log.IsErrorEnabled) Log.Error(CreateInvocationLogString("ERROR", invocation), ex);
throw;
}
}
Это работает как ожидалось при регулярных вызовах методов, но не при использовании методов async (используя ключевые слова async/await из С# 5.0). И я верю, я понимаю причины этого.
Для работы async/await компилятор добавляет функциональное тело метода в конечный автомат за кулисами, и элемент управления вернется к вызывающему, как только первое выражение awaitable, которое невозможно выполнить синхронно, встречается.
Кроме того, мы можем опросить тип возвращаемого значения и выяснить, имеем ли мы дело с методом async следующим образом:
if (invocation.Method.ReturnType == typeof(Task) ||
(invocation.Method.ReturnType.IsGenericType &&
invocation.Method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)))
Log.Info("Asynchronous method found...");
Это работает только для тех методов async, которые возвращают либо Task, либо Task<>, а не void, но я в порядке с этим.
Какие изменения необходимо внести в метод Intercept, чтобы awaiter вернулся туда, а не исходный вызывающий?