Skip to content

Instantly share code, notes, and snippets.

@hikalkan
Created October 15, 2014 05:42
Show Gist options
  • Save hikalkan/1e5d0f0142484da994e0 to your computer and use it in GitHub Desktop.
Save hikalkan/1e5d0f0142484da994e0 to your computer and use it in GitHub Desktop.
Castle Windsor interceptor for async methods
class Program
{
static void Main(string[] args)
{
using (var container = new WindsorContainer())
{
container.Register(
Component.For<MyInterceptor>().LifestyleTransient(),
Component.For<MyTester>().Interceptors<MyInterceptor>().LifestyleTransient()
);
var tester = container.Resolve<MyTester>();
var r = tester.Test();
Console.WriteLine("2");
r.Wait();
Console.WriteLine("4");
}
Console.ReadLine();
}
}
public class MyTester
{
public virtual async Task Test()
{
using (var str = new StreamWriter(@"c:\_test_delete_later.txt"))
{
Console.WriteLine("1");
for (int i = 0; i < 1000000; i++)
{
await str.WriteLineAsync("Test " + i);
}
Console.WriteLine("3");
}
}
}
public class MyInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
}
}
@BringerOD
Copy link

Failed again. LOL

I tried this. I feel I am getting closer. The static function is messing with me at this point.

using System.Reflection;
using Abp.Dependency;
using Castle.DynamicProxy;

namespace Abp.Domain.Uow
{
using System;
using System.Threading.Tasks;

///

/// This interceptor is used to manage database connection and transactions.
/// </summary>


public class UnitOfWorkInterceptor : IInterceptor
{
    /// <summary>


    /// Intercepts a method.
    /// </summary>


    /// <param name="invocation">Method invocation arguments</param>
    public void Intercept(IInvocation invocation)
    {
        var unitOfWorkAttr = UnitOfWorkAttribute.GetUnitOfWorkAttributeOrDefault(invocation.MethodInvocationTarget);
        if (unitOfWorkAttr == null || unitOfWorkAttr.IsDisabled)
        {
            //No need to a uow
            invocation.Proceed();
            return;
        }
        if (UnitOfWorkScope.Current == null)
        {
            //No current uow, run a new one
            PerformUow(invocation, unitOfWorkAttr.IsTransactional != false);
        }
        else
        {
            //Continue with current uow
            invocation.Proceed();
        }
    }


    private static void PerformUow(IInvocation invocation, bool isTransactional)
    {



        using (var unitOfWork = IocHelper.ResolveAsDisposable<IUnitOfWork>())
        {
            try
            {
                UnitOfWorkScope.Current = unitOfWork.Object;
                UnitOfWorkScope.Current.Initialize(isTransactional);
                UnitOfWorkScope.Current.Begin();

                try
                {


                   try
                   {

                      invocation.Proceed();

                      var returnType = invocation.Method.ReturnType;
                      if (returnType != typeof(void))
                      {
                         var returnValue = invocation.ReturnValue;
                         if (returnType == typeof(Task))
                         {
                            var task = (Task)returnValue;
                            task.ContinueWith((task1, o) =>
                            {
                               UnitOfWorkScope.Current.End();

                            }, TaskContinuationOptions.ExecuteSynchronously);
                         }
                         else if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
                         {
                            var task = (Task)returnValue;
                            task.ContinueWith((task1, o) => 
                            {
                               UnitOfWorkScope.Current.End();

                            },TaskContinuationOptions.ExecuteSynchronously);
                         }
                         else
                         {
                            UnitOfWorkScope.Current.End();
                         }
                      }


                   }
                   catch (Exception ex)
                   {
                      var tcs = new TaskCompletionSource<object>();
                      tcs.SetException(ex);
                      throw;
                   }



                }
                catch
                {
                    try { UnitOfWorkScope.Current.Cancel(); } catch { } //Hide exceptions on cancelling
                    throw;
                }
            }
            finally
            {
                UnitOfWorkScope.Current = null;
            }
        }
    }
}

}

@BringerOD
Copy link

Ok getting closer but the task.Wait() is an issue since it is synchronously waiting. This defeats the whole purpose of awaiting, since it locks up a thread waiting for it to complete.

namespace Abp.Domain.Uow
{
using System;
using System.Threading.Tasks;
using Castle.DynamicProxy;
using Dependency;

///

/// This interceptor is used to manage database connection and transactions.
///

public class UnitOfWorkInterceptor : IInterceptor
{
///

  ///    Intercepts a method.
  /// </summary>


  /// <param name="invocation">Method invocation arguments</param>
  public async void Intercept(IInvocation invocation)
  {
     var unitOfWorkAttr = UnitOfWorkAttribute.GetUnitOfWorkAttributeOrDefault(invocation.MethodInvocationTarget);
     if (unitOfWorkAttr == null || unitOfWorkAttr.IsDisabled)
     {
        //No need to a uow
        invocation.Proceed();
        return;
     }
     if (UnitOfWorkScope.Current == null)
     {
        //No current uow, run a new one
        PerformUow(invocation, unitOfWorkAttr.IsTransactional != false);
     }
     else
     {
        //Continue with current uow
        invocation.Proceed();
     }
  }


  private static void PerformUow(IInvocation invocation, bool isTransactional)
  {
     bool isAsync = false;

     using (var unitOfWork = IocHelper.ResolveAsDisposable<IUnitOfWork>())
     {
        try
        {
           UnitOfWorkScope.Current = unitOfWork.Object;
           UnitOfWorkScope.Current.Initialize(isTransactional);
           UnitOfWorkScope.Current.Begin();

           try
           {
              try
              {
                 invocation.Proceed();

                 var returnType = invocation.Method.ReturnType;
                 if (returnType != typeof (void))
                 {
                    var returnValue = invocation.ReturnValue;

                    if (returnType == typeof (Task) || returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof (Task<>))
                    {
                       isAsync = true;

                       var task = (Task) returnValue;

                       task.ContinueWith((task1, o) =>
                       {
                          var current = (IUnitOfWork) o;

                          current.End();

                       }, UnitOfWorkScope.Current,TaskContinuationOptions.AttachedToParent);

                       task.Wait();
                    }

                    else
                    {
                       UnitOfWorkScope.Current.End();
                    }
                 }
              }
              catch (Exception ex)
              {
                 var tcs = new TaskCompletionSource<object>();
                 tcs.SetException(ex);
                 throw;
              }
           }
           catch
           {
              try
              {
                 UnitOfWorkScope.Current.Cancel();
              }
              catch
              {
              } //Hide exceptions on cancelling
              throw;
           }
        }
        finally
        {
           if (!isAsync)
           {
              UnitOfWorkScope.Current = null;
           }
        }
     }
  }

}
}

@webzfactory
Copy link

I did exactly the same thing and got the same errors, so I used task.wait()... and I am now disappointed of not being able to make it work as it should... but we are close to the solution I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment