Browse Source

Created Unit Of Work reservation system.

pull/112/head
Halil İbrahim Kalkan 9 years ago
parent
commit
f4394f9993
  1. 3
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs
  2. 2
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUnitOfWorkMiddleware.cs
  3. 25
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs
  4. 22
      src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs
  5. 12
      src/Volo.Abp/Volo/Abp/Uow/IUnitOfWork.cs
  6. 14
      src/Volo.Abp/Volo/Abp/Uow/IUnitOfWorkManager.cs
  7. 11
      src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs
  8. 14
      src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkExtensions.cs
  9. 52
      src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs
  10. 32
      src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManagerExtensions.cs
  11. 2
      src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkStartOptions.cs
  12. 31
      test/Volo.Abp.Tests/Volo/Abp/Uow/UnitOfWork_Ambient_Scope_Tests.cs

3
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpMvcOptionsExtensions.cs

@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; using Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
using Volo.Abp.AspNetCore.Mvc.Uow;
using Volo.Abp.AspNetCore.Mvc.Validation; using Volo.Abp.AspNetCore.Mvc.Validation;
namespace Volo.Abp.AspNetCore.Mvc namespace Volo.Abp.AspNetCore.Mvc
@ -24,7 +25,7 @@ namespace Volo.Abp.AspNetCore.Mvc
//options.Filters.AddService(typeof(AbpAuthorizationFilter)); //options.Filters.AddService(typeof(AbpAuthorizationFilter));
//options.Filters.AddService(typeof(AbpAuditActionFilter)); //options.Filters.AddService(typeof(AbpAuditActionFilter));
options.Filters.AddService(typeof(AbpValidationActionFilter)); options.Filters.AddService(typeof(AbpValidationActionFilter));
//options.Filters.AddService(typeof(AbpUowActionFilter)); options.Filters.AddService(typeof(AbpUowActionFilter));
options.Filters.AddService(typeof(AbpExceptionFilter)); options.Filters.AddService(typeof(AbpExceptionFilter));
//options.Filters.AddService(typeof(AbpResultFilter)); //options.Filters.AddService(typeof(AbpResultFilter));
} }

2
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUnitOfWorkMiddleware.cs

@ -15,7 +15,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Uow
public async Task Invoke(HttpContext httpContext, IUnitOfWorkManager unitOfWorkManager) public async Task Invoke(HttpContext httpContext, IUnitOfWorkManager unitOfWorkManager)
{ {
using (var uow = unitOfWorkManager.Begin()) using (var uow = unitOfWorkManager.Reserve(AbpUowActionFilter.UnitOfWorkReservationName))
{ {
await _next(httpContext); await _next(httpContext);
await uow.CompleteAsync(); await uow.CompleteAsync();

25
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUowActionFilter.cs

@ -0,0 +1,25 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace Volo.Abp.AspNetCore.Mvc.Uow
{
public class AbpUowActionFilter : IAsyncActionFilter, ITransientDependency
{
public const string UnitOfWorkReservationName = "_AbpActionUnitOfWork";
private readonly IUnitOfWorkManager _unitOfWorkManager;
public AbpUowActionFilter(IUnitOfWorkManager unitOfWorkManager)
{
_unitOfWorkManager = unitOfWorkManager;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
_unitOfWorkManager.BeginReserved(UnitOfWorkReservationName);
await next();
}
}
}

22
src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs

@ -9,6 +9,28 @@ namespace Volo.Abp.Uow
{ {
public Guid Id => _parent.Id; public Guid Id => _parent.Id;
public IUnitOfWork Outer
{
get => _parent.Outer;
}
public bool IsReserved
{
get => _parent.IsReserved;
set => _parent.IsReserved = value;
}
public string ReservationName
{
get => _parent.ReservationName;
set => _parent.ReservationName = value;
}
public void SetOuter(IUnitOfWork outer)
{
_parent.SetOuter(outer);
}
public event EventHandler Completed; public event EventHandler Completed;
public event EventHandler<UnitOfWorkFailedEventArgs> Failed; public event EventHandler<UnitOfWorkFailedEventArgs> Failed;
public event EventHandler Disposed; public event EventHandler Disposed;

12
src/Volo.Abp/Volo/Abp/Uow/IUnitOfWork.cs

@ -1,7 +1,15 @@
namespace Volo.Abp.Uow using JetBrains.Annotations;
namespace Volo.Abp.Uow
{ {
public interface IUnitOfWork : IBasicUnitOfWork, IDatabaseApiContainer public interface IUnitOfWork : IBasicUnitOfWork, IDatabaseApiContainer
{ {
IUnitOfWork Outer { get; }
bool IsReserved { get; set; }
string ReservationName { get; set; }
void SetOuter([CanBeNull] IUnitOfWork outer);
} }
} }

14
src/Volo.Abp/Volo/Abp/Uow/IUnitOfWorkManager.cs

@ -9,20 +9,8 @@ namespace Volo.Abp.Uow
[NotNull] [NotNull]
IBasicUnitOfWork Begin([NotNull] UnitOfWorkStartOptions options); IBasicUnitOfWork Begin([NotNull] UnitOfWorkStartOptions options);
}
public static class UnitOfWorkManagerExtensions
{
[NotNull]
public static IBasicUnitOfWork Begin(this IUnitOfWorkManager unitOfWorkManager)
{
return unitOfWorkManager.Begin(new UnitOfWorkStartOptions());
}
[NotNull] [NotNull]
public static IBasicUnitOfWork BeginNew(this IUnitOfWorkManager unitOfWorkManager) IBasicUnitOfWork BeginReserved([NotNull] string reservationName);
{
return unitOfWorkManager.Begin(new UnitOfWorkStartOptions {RequiresNew = true});
}
} }
} }

11
src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs

@ -10,6 +10,17 @@ namespace Volo.Abp.Uow
{ {
public Guid Id { get; } = Guid.NewGuid(); public Guid Id { get; } = Guid.NewGuid();
public IUnitOfWork Outer { get; private set; }
public bool IsReserved { get; set; }
public string ReservationName { get; set; }
public void SetOuter(IUnitOfWork outer)
{
Outer = outer;
}
public event EventHandler Completed; public event EventHandler Completed;
public event EventHandler<UnitOfWorkFailedEventArgs> Failed; public event EventHandler<UnitOfWorkFailedEventArgs> Failed;
public event EventHandler Disposed; public event EventHandler Disposed;

14
src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkExtensions.cs

@ -0,0 +1,14 @@
using JetBrains.Annotations;
namespace Volo.Abp.Uow
{
public static class UnitOfWorkExtensions
{
public static bool IsReservedFor([NotNull] this IUnitOfWork unitOfWork, string reservationName)
{
Check.NotNull(unitOfWork, nameof(unitOfWork));
return unitOfWork.IsReserved && unitOfWork.ReservationName == reservationName;
}
}
}

52
src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs

@ -6,7 +6,7 @@ namespace Volo.Abp.Uow
{ {
public class UnitOfWorkManager : IUnitOfWorkManager, ISingletonDependency public class UnitOfWorkManager : IUnitOfWorkManager, ISingletonDependency
{ {
public IUnitOfWork Current => _ambientUnitOfWork.UnitOfWork; public IUnitOfWork Current => GetCurrentUnitOfWork();
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private readonly IAmbientUnitOfWork _ambientUnitOfWork; private readonly IAmbientUnitOfWork _ambientUnitOfWork;
@ -21,18 +21,28 @@ namespace Volo.Abp.Uow
{ {
Check.NotNull(options, nameof(options)); Check.NotNull(options, nameof(options));
if (!options.RequiresNew && _ambientUnitOfWork.UnitOfWork != null) if (!options.RequiresNew && _ambientUnitOfWork.UnitOfWork != null && !_ambientUnitOfWork.UnitOfWork.IsReserved)
{ {
return new ChildUnitOfWork(_ambientUnitOfWork.UnitOfWork); return new ChildUnitOfWork(_ambientUnitOfWork.UnitOfWork);
} }
var parentUow = _ambientUnitOfWork.UnitOfWork; if (_ambientUnitOfWork.UnitOfWork != null)
{
//Requires new because there is already a current UOW but it's reserved
options.RequiresNew = true;
}
var outerUow = _ambientUnitOfWork.UnitOfWork;
var scope = _serviceProvider.CreateScope(); var scope = _serviceProvider.CreateScope();
IUnitOfWork unitOfWork; IUnitOfWork unitOfWork;
try try
{ {
unitOfWork = scope.ServiceProvider.GetRequiredService<IUnitOfWork>(); unitOfWork = scope.ServiceProvider.GetRequiredService<IUnitOfWork>();
unitOfWork.SetOuter(outerUow);
unitOfWork.IsReserved = options.ReservationName != null;
unitOfWork.ReservationName = options.ReservationName;
} }
catch catch
{ {
@ -44,11 +54,45 @@ namespace Volo.Abp.Uow
unitOfWork.Disposed += (sender, args) => unitOfWork.Disposed += (sender, args) =>
{ {
_ambientUnitOfWork.SetUnitOfWork(parentUow); _ambientUnitOfWork.SetUnitOfWork(outerUow);
scope.Dispose(); scope.Dispose();
}; };
return unitOfWork; return unitOfWork;
} }
public IBasicUnitOfWork BeginReserved(string reservationName)
{
Check.NotNull(reservationName, nameof(reservationName));
var uow = _ambientUnitOfWork.UnitOfWork;
//Find reserved unit of work starting from current and going to outers
while (uow != null && !uow.IsReservedFor(reservationName))
{
uow = uow.Outer;
}
if (uow == null)
{
throw new AbpException($"Could not find a reserved unit of work with reservation name: {reservationName}");
}
uow.IsReserved = false;
return uow;
}
private IUnitOfWork GetCurrentUnitOfWork()
{
var uow = _ambientUnitOfWork.UnitOfWork;
//Skip reserved unit of work
while (uow != null && uow.IsReserved)
{
uow = uow.Outer;
}
return uow;
}
} }
} }

32
src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManagerExtensions.cs

@ -0,0 +1,32 @@
using JetBrains.Annotations;
namespace Volo.Abp.Uow
{
public static class UnitOfWorkManagerExtensions
{
[NotNull]
public static IBasicUnitOfWork Begin([NotNull] this IUnitOfWorkManager unitOfWorkManager)
{
Check.NotNull(unitOfWorkManager, nameof(unitOfWorkManager));
return unitOfWorkManager.Begin(new UnitOfWorkStartOptions());
}
[NotNull]
public static IBasicUnitOfWork BeginNew([NotNull] this IUnitOfWorkManager unitOfWorkManager)
{
Check.NotNull(unitOfWorkManager, nameof(unitOfWorkManager));
return unitOfWorkManager.Begin(new UnitOfWorkStartOptions {RequiresNew = true});
}
[NotNull]
public static IBasicUnitOfWork Reserve([NotNull] this IUnitOfWorkManager unitOfWorkManager, [NotNull] string reservationName)
{
Check.NotNull(unitOfWorkManager, nameof(unitOfWorkManager));
Check.NotNull(reservationName, nameof(reservationName));
return unitOfWorkManager.Begin(new UnitOfWorkStartOptions { ReservationName = reservationName });
}
}
}

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

@ -3,5 +3,7 @@
public class UnitOfWorkStartOptions public class UnitOfWorkStartOptions
{ {
public bool RequiresNew { get; set; } public bool RequiresNew { get; set; }
public string ReservationName { get; set; }
} }
} }

31
test/Volo.Abp.Tests/Volo/Abp/Uow/UnitOfWork_Ambient_Scope_Tests.cs

@ -42,5 +42,36 @@ namespace Volo.Abp.Uow
_unitOfWorkManager.Current.ShouldBeNull(); _unitOfWorkManager.Current.ShouldBeNull();
} }
[Fact]
public async Task UnitOfWorkManager_Reservation_Test()
{
_unitOfWorkManager.Current.ShouldBeNull();
using (var uow1 = _unitOfWorkManager.Reserve("Reservation1"))
{
_unitOfWorkManager.Current.ShouldBeNull();
using (var uow2 = _unitOfWorkManager.Begin())
{
_unitOfWorkManager.Current.ShouldNotBeNull();
_unitOfWorkManager.Current.Id.ShouldNotBe(uow1.Id);
await uow2.CompleteAsync();
}
_unitOfWorkManager.Current.ShouldBeNull();
var reserverUow = _unitOfWorkManager.BeginReserved("Reservation1");
_unitOfWorkManager.Current.ShouldNotBeNull();
_unitOfWorkManager.Current.Id.ShouldBe(reserverUow.Id);
_unitOfWorkManager.Current.Id.ShouldBe(uow1.Id);
await uow1.CompleteAsync();
}
_unitOfWorkManager.Current.ShouldBeNull();
}
} }
} }

Loading…
Cancel
Save