From 790ed478dae852929f8d6f74635a36870c0a296c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 22 Sep 2017 10:39:01 +0300 Subject: [PATCH] Refactored and improved UOW. Added simple UOW middleware. Created a unit test for UOW. --- .../Mvc/Uow/AbpUnitOfWorkMiddleware.cs | 25 +++++++++++ .../Volo/Abp/Uow/AmbientUnitOfWork.cs | 8 ++-- src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs | 7 +++ src/Volo.Abp/Volo/Abp/Uow/IBasicUnitOfWork.cs | 2 + .../Volo/Abp/Uow/IDatabaseApiContainer.cs | 2 +- src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs | 41 ++++++++++-------- .../Volo/Abp/Uow/UnitOfWorkManager.cs | 19 +------- .../Abp/Uow/UnitOfWork_Ambient_Scope_Tests.cs | 43 +++++++++++++++++++ 8 files changed, 108 insertions(+), 39 deletions(-) create mode 100644 src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUnitOfWorkMiddleware.cs create mode 100644 test/Volo.Abp.Tests/Volo/Abp/Uow/UnitOfWork_Ambient_Scope_Tests.cs diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUnitOfWorkMiddleware.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUnitOfWorkMiddleware.cs new file mode 100644 index 0000000000..0a19330cd4 --- /dev/null +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Uow/AbpUnitOfWorkMiddleware.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Volo.Abp.Uow; + +namespace Volo.Abp.AspNetCore.Mvc.Uow +{ + class AbpUnitOfWorkMiddleware + { + private readonly RequestDelegate _next; + + public AbpUnitOfWorkMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task Invoke(HttpContext httpContext, IUnitOfWorkManager unitOfWorkManager) + { + using (var uow = unitOfWorkManager.Begin()) + { + await _next(httpContext); + await uow.CompleteAsync(); + } + } + } +} diff --git a/src/Volo.Abp/Volo/Abp/Uow/AmbientUnitOfWork.cs b/src/Volo.Abp/Volo/Abp/Uow/AmbientUnitOfWork.cs index 6c01daf350..7b3a45b20c 100644 --- a/src/Volo.Abp/Volo/Abp/Uow/AmbientUnitOfWork.cs +++ b/src/Volo.Abp/Volo/Abp/Uow/AmbientUnitOfWork.cs @@ -6,18 +6,18 @@ namespace Volo.Abp.Uow [ExposeServices(typeof(IAmbientUnitOfWork), typeof(IUnitOfWorkAccessor))] public class AmbientUnitOfWork : IAmbientUnitOfWork, ISingletonDependency { - public IUnitOfWork UnitOfWork => _currentUowInfo.Value; + public IUnitOfWork UnitOfWork => _currentUow.Value; - private readonly AsyncLocal _currentUowInfo; + private readonly AsyncLocal _currentUow; public AmbientUnitOfWork() { - _currentUowInfo = new AsyncLocal(); + _currentUow = new AsyncLocal(); } public void SetUnitOfWork(IUnitOfWork unitOfWork) { - _currentUowInfo.Value = unitOfWork; + _currentUow.Value = unitOfWork; } } } \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs b/src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs index 47dc909581..c20d106e4e 100644 --- a/src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs +++ b/src/Volo.Abp/Volo/Abp/Uow/ChildUnitOfWork.cs @@ -7,6 +7,8 @@ namespace Volo.Abp.Uow { internal class ChildUnitOfWork : IUnitOfWork { + public Guid Id => _parent.Id; + public event EventHandler Completed; public event EventHandler Failed; public event EventHandler Disposed; @@ -60,5 +62,10 @@ namespace Volo.Abp.Uow { } + + public override string ToString() + { + return $"[UnitOfWork {Id}]"; + } } } \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Uow/IBasicUnitOfWork.cs b/src/Volo.Abp/Volo/Abp/Uow/IBasicUnitOfWork.cs index 60038cae2b..11d26a7640 100644 --- a/src/Volo.Abp/Volo/Abp/Uow/IBasicUnitOfWork.cs +++ b/src/Volo.Abp/Volo/Abp/Uow/IBasicUnitOfWork.cs @@ -7,6 +7,8 @@ namespace Volo.Abp.Uow //TODO: Find a better naming :( public interface IBasicUnitOfWork : IDisposable { + Guid Id { get; } + event EventHandler Completed; event EventHandler Failed; diff --git a/src/Volo.Abp/Volo/Abp/Uow/IDatabaseApiContainer.cs b/src/Volo.Abp/Volo/Abp/Uow/IDatabaseApiContainer.cs index 536823fd57..c24fe41797 100644 --- a/src/Volo.Abp/Volo/Abp/Uow/IDatabaseApiContainer.cs +++ b/src/Volo.Abp/Volo/Abp/Uow/IDatabaseApiContainer.cs @@ -10,6 +10,6 @@ namespace Volo.Abp.Uow IDatabaseApi FindDatabaseApi([NotNull] string id); [NotNull] - IDatabaseApi GetOrAddDatabaseApi(string id, Func factory); + IDatabaseApi GetOrAddDatabaseApi([NotNull] string id, [NotNull] Func factory); } } \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs b/src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs index a94faba0d7..2207f94fcc 100644 --- a/src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs +++ b/src/Volo.Abp/Volo/Abp/Uow/UnitOfWork.cs @@ -8,6 +8,8 @@ namespace Volo.Abp.Uow { public class UnitOfWork : IUnitOfWork, ITransientDependency { + public Guid Id { get; } = Guid.NewGuid(); + public event EventHandler Completed; public event EventHandler Failed; public event EventHandler Disposed; @@ -27,23 +29,6 @@ namespace Volo.Abp.Uow _databaseApis = new Dictionary(); } - public void Dispose() - { - if (_isDisposed) - { - return; - } - - _isDisposed = true; - - if (!_isCompleted || _exception != null) - { - OnFailed(_exception); - } - - OnDisposed(); - } - public void SaveChanges() { foreach (var databaseApi in _databaseApis.Values) @@ -122,6 +107,23 @@ namespace Volo.Abp.Uow Disposed.InvokeSafely(this); } + public void Dispose() + { + if (_isDisposed) + { + return; + } + + _isDisposed = true; + + if (!_isCompleted || _exception != null) + { + OnFailed(_exception); + } + + OnDisposed(); + } + private void PreventMultipleComplete() { if (_isCompleted) @@ -131,5 +133,10 @@ namespace Volo.Abp.Uow _isCompleted = true; } + + public override string ToString() + { + return $"[UnitOfWork {Id}]"; + } } } \ No newline at end of file diff --git a/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs b/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs index 534b1c0db8..46c1ec9c1d 100644 --- a/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs +++ b/src/Volo.Abp/Volo/Abp/Uow/UnitOfWorkManager.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.DependencyInjection; @@ -41,27 +40,13 @@ namespace Volo.Abp.Uow _ambientUnitOfWork.SetUnitOfWork(unitOfWork); - Debug.Assert( - _ambientUnitOfWork.UnitOfWork != null, - "_ambientUnitOfWork.UnitOfWork can not be null since it's set by _ambientUnitOfWork.SetUnitOfWork method!" - ); - - unitOfWork.Completed += (sender, args) => - { - _ambientUnitOfWork.SetUnitOfWork(parentUow); - }; - - unitOfWork.Failed += (sender, args) => - { - _ambientUnitOfWork.SetUnitOfWork(parentUow); - }; - unitOfWork.Disposed += (sender, args) => { + _ambientUnitOfWork.SetUnitOfWork(parentUow); scope.Dispose(); }; - return _ambientUnitOfWork.UnitOfWork; + return unitOfWork; } } } \ No newline at end of file diff --git a/test/Volo.Abp.Tests/Volo/Abp/Uow/UnitOfWork_Ambient_Scope_Tests.cs b/test/Volo.Abp.Tests/Volo/Abp/Uow/UnitOfWork_Ambient_Scope_Tests.cs new file mode 100644 index 0000000000..160c390186 --- /dev/null +++ b/test/Volo.Abp.Tests/Volo/Abp/Uow/UnitOfWork_Ambient_Scope_Tests.cs @@ -0,0 +1,43 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Modularity; +using Volo.Abp.TestBase; +using Xunit; + +namespace Volo.Abp.Uow +{ + public class UnitOfWork_Ambient_Scope_Tests : AbpIntegratedTest + { + private readonly IUnitOfWorkManager _unitOfWorkManager; + + public UnitOfWork_Ambient_Scope_Tests() + { + _unitOfWorkManager = ServiceProvider.GetRequiredService(); + } + + [Fact] + public async Task UnitOfWorkManager_Current_Should_Set_Correctly() + { + _unitOfWorkManager.Current.ShouldBeNull(); + + using (var uow1 = _unitOfWorkManager.Begin()) + { + _unitOfWorkManager.Current.ShouldNotBeNull(); + _unitOfWorkManager.Current.ShouldBe(uow1); + + using (var uow2 = _unitOfWorkManager.Begin()) + { + _unitOfWorkManager.Current.ShouldNotBeNull(); + _unitOfWorkManager.Current.Id.ShouldBe(uow1.Id); + + await uow2.CompleteAsync(); + } + + await uow1.CompleteAsync(); + } + + _unitOfWorkManager.Current.ShouldBeNull(); + } + } +}