using System;
using System.Reflection;
using System.Threading.Tasks;
using Abp.Threading;
using Castle.DynamicProxy;
namespace Abp.Domain.Uow
{
///
/// This interceptor is used to manage database connection and transactions.
///
internal class UnitOfWorkInterceptor : IInterceptor
{
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IUnitOfWorkDefaultOptions _unitOfWorkOptions;
public UnitOfWorkInterceptor(IUnitOfWorkManager unitOfWorkManager, IUnitOfWorkDefaultOptions unitOfWorkOptions)
{
_unitOfWorkManager = unitOfWorkManager;
_unitOfWorkOptions = unitOfWorkOptions;
}
///
/// Intercepts a method.
///
/// Method invocation arguments
public void Intercept(IInvocation invocation)
{
MethodInfo method;
try
{
method = invocation.MethodInvocationTarget;
}
catch
{
method = invocation.GetConcreteMethod();
}
var unitOfWorkAttr = _unitOfWorkOptions.GetUnitOfWorkAttributeOrNull(method);
if (unitOfWorkAttr == null || unitOfWorkAttr.IsDisabled)
{
//No need to a uow
invocation.Proceed();
return;
}
//No current uow, run a new one
PerformUow(invocation, unitOfWorkAttr.CreateOptions());
}
private void PerformUow(IInvocation invocation, UnitOfWorkOptions options)
{
if (invocation.Method.IsAsync())
{
PerformAsyncUow(invocation, options);
}
else
{
PerformSyncUow(invocation, options);
}
}
private void PerformSyncUow(IInvocation invocation, UnitOfWorkOptions options)
{
using (var uow = _unitOfWorkManager.Begin(options))
{
invocation.Proceed();
uow.Complete();
}
}
private void PerformAsyncUow(IInvocation invocation, UnitOfWorkOptions options)
{
var uow = _unitOfWorkManager.Begin(options);
try
{
invocation.Proceed();
}
catch
{
uow.Dispose();
throw;
}
if (invocation.Method.ReturnType == typeof(Task))
{
invocation.ReturnValue = InternalAsyncHelper.AwaitTaskWithPostActionAndFinally(
(Task) invocation.ReturnValue,
async () => await uow.CompleteAsync(),
exception => uow.Dispose()
);
}
else //Task
{
invocation.ReturnValue = InternalAsyncHelper.CallAwaitTaskWithPostActionAndFinallyAndGetResult(
invocation.Method.ReturnType.GenericTypeArguments[0],
invocation.ReturnValue,
async () => await uow.CompleteAsync(),
exception => uow.Dispose()
);
}
}
}
}