Browse Source

#80: Created Unit Of Work Interceptor.

pull/81/head
Halil İbrahim Kalkan 10 years ago
parent
commit
0292287fe3
  1. 33
      src/AbpDesk/AbpDesk.Application/AbpDesk/Tickets/TicketAppService.cs
  2. 2
      src/Volo.Abp/Volo/Abp/Threading/AsyncHelper.cs
  3. 181
      src/Volo.Abp/Volo/Abp/Threading/InternalAsyncHelper.cs
  4. 2
      src/Volo.Abp/Volo/Abp/Uow/IBasicUnitOfWork.cs
  5. 65
      src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkInterceptor.cs
  6. 6
      test/Volo.Abp.Tests/Volo/Abp/Threading/AsyncHelper_Tests.cs

33
src/AbpDesk/AbpDesk.Application/AbpDesk/Tickets/TicketAppService.cs

@ -3,8 +3,8 @@ using System.Threading.Tasks;
using AbpDesk.Tickets.Dtos; using AbpDesk.Tickets.Dtos;
using Volo.Abp.Application.Services.Dtos; using Volo.Abp.Application.Services.Dtos;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
using Volo.Abp.Linq.Extensions; using Volo.Abp.Linq.Extensions;
using Volo.Abp.Uow;
using Volo.ExtensionMethods; using Volo.ExtensionMethods;
namespace AbpDesk.Tickets namespace AbpDesk.Tickets
@ -12,33 +12,32 @@ namespace AbpDesk.Tickets
public class TicketAppService : ITicketAppService public class TicketAppService : ITicketAppService
{ {
private readonly IQueryableRepository<Ticket, int> _ticketRepository; private readonly IQueryableRepository<Ticket, int> _ticketRepository;
private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly IAsyncQueryableExecuter _asyncQueryableExecuter;
public TicketAppService( public TicketAppService(
IQueryableRepository<Ticket, int> ticketRepository, IQueryableRepository<Ticket, int> ticketRepository,
IUnitOfWorkManager unitOfWorkManager IAsyncQueryableExecuter asyncQueryableExecuter
) )
{ {
_ticketRepository = ticketRepository; _ticketRepository = ticketRepository;
_unitOfWorkManager = unitOfWorkManager; _asyncQueryableExecuter = asyncQueryableExecuter;
} }
public async Task<ListResultDto<TicketDto>> GetAll(GetAllTicketsInput input) public async Task<ListResultDto<TicketDto>> GetAll(GetAllTicketsInput input)
{ {
//Use conventional unit of work for application services when it's available! var tickets = await _asyncQueryableExecuter.ToListAsync(_ticketRepository
using (var unitOfWork = _unitOfWorkManager.Begin()) .WhereIf(
{ !input.Filter.IsNullOrWhiteSpace(),
var tickets = _ticketRepository t => t.Title.Contains(input.Filter) || t.Body.Contains(input.Filter)
.WhereIf( )
!input.Filter.IsNullOrWhiteSpace(), .Select(t => new TicketDto
t => t.Title.Contains(input.Filter) || t.Body.Contains(input.Filter) {
).Select(t => new TicketDto { Id = t.Id, Title = t.Title, Body = t.Body }) Id = t.Id,
.ToList(); Title = t.Title,
Body = t.Body
}));
await unitOfWork.CompleteAsync(); return new ListResultDto<TicketDto>(tickets);
return new ListResultDto<TicketDto>(tickets);
}
} }
} }
} }

2
src/Volo.Abp/Volo/Abp/Threading/AsyncHelper.cs

@ -15,7 +15,7 @@ namespace Volo.Abp.Threading
/// Checks if given method is an async method. /// Checks if given method is an async method.
/// </summary> /// </summary>
/// <param name="method">A method to check</param> /// <param name="method">A method to check</param>
public static bool IsAsyncMethod([NotNull] this MethodInfo method) public static bool IsAsync([NotNull] this MethodInfo method)
{ {
return method.ReturnType == typeof(Task) || return method.ReturnType == typeof(Task) ||
(method.ReturnType.GetTypeInfo().IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)); (method.ReturnType.GetTypeInfo().IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>));

181
src/Volo.Abp/Volo/Abp/Threading/InternalAsyncHelper.cs

@ -0,0 +1,181 @@
using System;
using System.Reflection;
using System.Threading.Tasks;
namespace Volo.Abp.Threading
{
internal static class InternalAsyncHelper
{
public static async Task AwaitTaskWithFinally(Task actualReturnValue, Action<Exception> finalAction)
{
Exception exception = null;
try
{
await actualReturnValue;
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
finalAction(exception);
}
}
public static async Task AwaitTaskWithPostActionAndFinally(Task actualReturnValue, Func<Task> postAction, Action<Exception> finalAction)
{
Exception exception = null;
try
{
await actualReturnValue;
await postAction();
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
finalAction(exception);
}
}
public static async Task AwaitTaskWithPreActionAndPostActionAndFinally(Func<Task> actualReturnValue, Func<Task> preAction = null, Func<Task> postAction = null, Action<Exception> finalAction = null)
{
Exception exception = null;
try
{
if (preAction != null)
{
await preAction();
}
await actualReturnValue();
if (postAction != null)
{
await postAction();
}
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
if (finalAction != null)
{
finalAction(exception);
}
}
}
public static async Task<T> AwaitTaskWithFinallyAndGetResult<T>(Task<T> actualReturnValue, Action<Exception> finalAction)
{
Exception exception = null;
try
{
return await actualReturnValue;
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
finalAction(exception);
}
}
public static object CallAwaitTaskWithFinallyAndGetResult(Type taskReturnType, object actualReturnValue, Action<Exception> finalAction)
{
return typeof(InternalAsyncHelper)
.GetTypeInfo()
.GetMethod("AwaitTaskWithFinallyAndGetResult", BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(taskReturnType)
.Invoke(null, new object[] { actualReturnValue, finalAction });
}
public static async Task<T> AwaitTaskWithPostActionAndFinallyAndGetResult<T>(Task<T> actualReturnValue, Func<Task> postAction, Action<Exception> finalAction)
{
Exception exception = null;
try
{
var result = await actualReturnValue;
await postAction();
return result;
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
finalAction(exception);
}
}
public static object CallAwaitTaskWithPostActionAndFinallyAndGetResult(Type taskReturnType, object actualReturnValue, Func<Task> action, Action<Exception> finalAction)
{
return typeof (InternalAsyncHelper)
.GetTypeInfo()
.GetMethod("AwaitTaskWithPostActionAndFinallyAndGetResult", BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(taskReturnType)
.Invoke(null, new object[] { actualReturnValue, action, finalAction });
}
public static async Task<T> AwaitTaskWithPreActionAndPostActionAndFinallyAndGetResult<T>(Func<Task<T>> actualReturnValue, Func<Task> preAction = null, Func<Task> postAction = null, Action<Exception> finalAction = null)
{
Exception exception = null;
try
{
if (preAction != null)
{
await preAction();
}
var result = await actualReturnValue();
if (postAction != null)
{
await postAction();
}
return result;
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
if (finalAction != null)
{
finalAction(exception);
}
}
}
public static object CallAwaitTaskWithPreActionAndPostActionAndFinallyAndGetResult(Type taskReturnType, Func<object> actualReturnValue, Func<Task> preAction = null, Func<Task> postAction = null, Action<Exception> finalAction = null)
{
return typeof(InternalAsyncHelper)
.GetTypeInfo()
.GetMethod("AwaitTaskWithPreActionAndPostActionAndFinallyAndGetResult", BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(taskReturnType)
.Invoke(null, new object[] { actualReturnValue, preAction, postAction, finalAction });
}
}
}

2
src/Volo.Abp/Volo/Abp/Uow/IBasicUnitOfWork.cs

@ -4,7 +4,7 @@ using System.Threading.Tasks;
namespace Volo.Abp.Uow namespace Volo.Abp.Uow
{ {
//Find a better naming :( //TODO: Find a better naming :(
public interface IBasicUnitOfWork : IDisposable public interface IBasicUnitOfWork : IDisposable
{ {
event EventHandler Completed; event EventHandler Completed;

65
src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkInterceptor.cs

@ -1,13 +1,74 @@
using Volo.Abp.DynamicProxy; using System.Threading.Tasks;
using Volo.Abp.DynamicProxy;
using Volo.Abp.Threading;
using Volo.DependencyInjection; using Volo.DependencyInjection;
namespace Volo.Abp.Uow namespace Volo.Abp.Uow
{ {
public class UnitOfWorkInterceptor : IAbpInterceptor, ITransientDependency public class UnitOfWorkInterceptor : IAbpInterceptor, ITransientDependency
{ {
private readonly IUnitOfWorkManager _unitOfWorkManager;
public UnitOfWorkInterceptor(IUnitOfWorkManager unitOfWorkManager)
{
_unitOfWorkManager = unitOfWorkManager;
}
public void Intercept(IAbpMethodInvocation invocation) public void Intercept(IAbpMethodInvocation invocation)
{ {
invocation.Proceed(); //TODO: Check UOW attribute and other conditions!
if (invocation.Method.IsAsync())
{
PerformAsyncUow(invocation);
}
else
{
PerformSyncUow(invocation);
}
}
private void PerformSyncUow(IAbpMethodInvocation invocation)
{
using (var uow = _unitOfWorkManager.Begin())
{
invocation.Proceed();
uow.Complete();
}
}
private void PerformAsyncUow(IAbpMethodInvocation invocation)
{
var uow = _unitOfWorkManager.Begin();
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<TResult>
{
invocation.ReturnValue = InternalAsyncHelper.CallAwaitTaskWithPostActionAndFinallyAndGetResult(
invocation.Method.ReturnType.GenericTypeArguments[0],
invocation.ReturnValue,
async () => await uow.CompleteAsync(),
exception => uow.Dispose()
);
}
} }
} }
} }

6
test/Volo.Abp.Tests/Volo/Abp/Threading/AsyncHelper_Tests.cs

@ -26,17 +26,17 @@ namespace Volo.Abp.Threading
GetType().GetMethod( GetType().GetMethod(
"MyTaskWithoutReturnValueAsync", "MyTaskWithoutReturnValueAsync",
BindingFlags.NonPublic | BindingFlags.Static BindingFlags.NonPublic | BindingFlags.Static
).IsAsyncMethod().ShouldBe(true); ).IsAsync().ShouldBe(true);
GetType().GetMethod( GetType().GetMethod(
"MyTaskWithReturnValueAsync", "MyTaskWithReturnValueAsync",
BindingFlags.NonPublic | BindingFlags.Static BindingFlags.NonPublic | BindingFlags.Static
).IsAsyncMethod().ShouldBe(true); ).IsAsync().ShouldBe(true);
GetType().GetMethod( GetType().GetMethod(
"MyTaskWithReturnValue2", "MyTaskWithReturnValue2",
BindingFlags.NonPublic | BindingFlags.Instance BindingFlags.NonPublic | BindingFlags.Instance
).IsAsyncMethod().ShouldBe(false); ).IsAsync().ShouldBe(false);
} }
private static async Task MyTaskWithoutReturnValueAsync() private static async Task MyTaskWithoutReturnValueAsync()

Loading…
Cancel
Save