diff --git a/common.props b/common.props index a7029c6..5d06b6b 100644 --- a/common.props +++ b/common.props @@ -1,6 +1,6 @@ - 2.3.1 + 2.3.2 $(NoWarn);CS1591 https://raw.githubusercontent.com/osoykan/Stove/master/stove.png https://github.com/osoykan/Stove diff --git a/src/Stove/StoveComponentBase.cs b/src/Stove/StoveComponentBase.cs index 84558ea..e091bee 100644 --- a/src/Stove/StoveComponentBase.cs +++ b/src/Stove/StoveComponentBase.cs @@ -8,6 +8,7 @@ using Stove.Log; using Stove.MQ; using Stove.ObjectMapping; +using Stove.Threading.Extensions; namespace Stove { @@ -68,7 +69,7 @@ public IUnitOfWorkManager UnitOfWorkManager public IMessageBus MessageBus { get; set; } /// - /// The accessor + /// The accessor /// public IStoveCommandContextAccessor CommandContextAccessor { get; set; } @@ -80,6 +81,14 @@ protected void CorrelatingBy(Action act, string correlationId) } } + protected TResponse CorrelatingBy(Func func, string correlationId) + { + using (CommandContextAccessor.Use(correlationId)) + { + return func(); + } + } + protected Task CorrelatingBy(Func func, string correlationId) { using (CommandContextAccessor.Use(correlationId)) @@ -88,6 +97,14 @@ protected Task CorrelatingBy(Func func, string correlationId) } } + protected Task CorrelatingBy(Func> func, string correlationId) + { + using (CommandContextAccessor.Use(correlationId)) + { + return func(); + } + } + protected void UseUow(Action act, Action optsCallback = null) { var options = new UnitOfWorkOptions(); @@ -102,21 +119,51 @@ protected void UseUow(Action act, Action optsCallback = null) } } - protected Task UseUow(Func func, Action optsAction = null, CancellationToken cancellationToken = default) + protected TResponse UseUow(Func func, Action optsCallback = null) + { + var options = new UnitOfWorkOptions(); + + optsCallback?.Invoke(options); + + TResponse response; + using (IUnitOfWorkCompleteHandle uow = UnitOfWorkManager.Begin(options)) + { + response = func(); + + uow.Complete(); + } + + return response; + } + + protected async Task UseUow(Func func, Action optsAction = null, CancellationToken cancellationToken = default) { var options = new UnitOfWorkOptions(); optsAction?.Invoke(options); - Task task; using (IUnitOfWorkCompleteHandle uow = UnitOfWorkManager.Begin(options)) { - task = func(); + await func().NotOnCapturedContext(); - uow.CompleteAsync(cancellationToken); + await uow.CompleteAsync(cancellationToken).NotOnCapturedContext(); } + } + + protected async Task UseUow(Func> func, Action optsAction = null, CancellationToken cancellationToken = default) + { + var options = new UnitOfWorkOptions(); + optsAction?.Invoke(options); - return task; + TResponse response; + using (IUnitOfWorkCompleteHandle uow = UnitOfWorkManager.Begin(options)) + { + response = await func().NotOnCapturedContext(); + + await uow.CompleteAsync(cancellationToken).NotOnCapturedContext(); + } + + return response; } protected void UseUowIfNot(Action act, Action optsAction = null) @@ -139,27 +186,70 @@ protected void UseUowIfNot(Action act, Action optsAction = nu } } - protected Task UseUowIfNot(Func func, Action optsAction = null, CancellationToken cancellationToken = default) + protected TResponse UseUowIfNot(Func func, Action optsAction = null) + { + var options = new UnitOfWorkOptions(); + optsAction?.Invoke(options); + + TResponse response; + if (UnitOfWorkManager.Current == null) + { + using (IUnitOfWorkCompleteHandle uow = UnitOfWorkManager.Begin(options)) + { + response = func(); + + uow.Complete(); + } + } + else + { + response = func(); + } + + return response; + } + + protected async Task UseUowIfNot(Func func, Action optsAction = null, CancellationToken cancellationToken = default) + { + var options = new UnitOfWorkOptions(); + optsAction?.Invoke(options); + + if (UnitOfWorkManager.Current == null) + { + using (IUnitOfWorkCompleteHandle uow = UnitOfWorkManager.Begin(options)) + { + await func().NotOnCapturedContext(); + + await uow.CompleteAsync(cancellationToken).NotOnCapturedContext(); + } + } + else + { + await func().NotOnCapturedContext(); + } + } + + protected async Task UseUowIfNot(Func> func, Action optsAction = null, CancellationToken cancellationToken = default) { var options = new UnitOfWorkOptions(); optsAction?.Invoke(options); - Task task; + TResponse response; if (UnitOfWorkManager.Current == null) { using (IUnitOfWorkCompleteHandle uow = UnitOfWorkManager.Begin(options)) { - task = func(); + response = await func().NotOnCapturedContext(); - uow.CompleteAsync(cancellationToken); + await uow.CompleteAsync(cancellationToken).NotOnCapturedContext(); } } else { - task = func(); + response = await func().NotOnCapturedContext(); } - return task; + return response; } protected void OnUowCompleted(Action action) diff --git a/src/Stove/Threading/Extensions/TaskExtensions.cs b/src/Stove/Threading/Extensions/TaskExtensions.cs new file mode 100644 index 0000000..dacd7fc --- /dev/null +++ b/src/Stove/Threading/Extensions/TaskExtensions.cs @@ -0,0 +1,27 @@ +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +namespace Stove.Threading.Extensions +{ + /// + /// Represents extensions on Tasks. + /// + public static class TaskExtensions + { + /// + /// ConfigureAwait(false) + /// + public static ConfiguredTaskAwaitable NotOnCapturedContext(this Task task) + { + return task.ConfigureAwait(false); + } + + /// + /// ConfigureAwait(false) + /// + public static ConfiguredTaskAwaitable NotOnCapturedContext(this Task task) + { + return task.ConfigureAwait(false); + } + } +} diff --git a/test/Stove.Tests.SampleApplication/Domain/SomeDomainService.cs b/test/Stove.Tests.SampleApplication/Domain/SomeDomainService.cs index b8aee9e..99ecccf 100644 --- a/test/Stove.Tests.SampleApplication/Domain/SomeDomainService.cs +++ b/test/Stove.Tests.SampleApplication/Domain/SomeDomainService.cs @@ -22,10 +22,7 @@ public SomeDomainService(IRepository repository, IRepository mess public User GetUserByName(string name) { User user = null; - UseUow(() => - { - user = _repository.FirstOrDefault(x => x.Name == name); - }); + UseUow(() => { user = _repository.FirstOrDefault(x => x.Name == name); }); return user; } @@ -33,10 +30,7 @@ public User GetUserByName(string name) public async Task GetUserByName_async(string name) { User user = null; - await UseUow(async () => - { - user = await _repository.FirstOrDefaultAsync(x => x.Name == name); - }, options => { }, CancellationToken.None); + await UseUow(async () => { user = await _repository.FirstOrDefaultAsync(x => x.Name == name); }, options => { }, CancellationToken.None); return user; } @@ -45,10 +39,7 @@ public async Task GetUserByName_async_With_IsolationLevel(string name) { User user = null; - await UseUow(async () => - { - user = await _repository.FirstOrDefaultAsync(x => x.Name == name); - }, options => { options.IsolationLevel = IsolationLevel.ReadCommitted; }); + await UseUow(async () => { user = await _repository.FirstOrDefaultAsync(x => x.Name == name); }, options => { options.IsolationLevel = IsolationLevel.ReadCommitted; }); return user; } @@ -57,10 +48,7 @@ public User GetUserByName_with_isolationlevel(string name) { User user = null; - UseUow(() => - { - user = _repository.FirstOrDefault(x => x.Name == name); - }, options => { options.IsolationLevel = IsolationLevel.Chaos; }); + UseUow(() => { user = _repository.FirstOrDefault(x => x.Name == name); }, options => { options.IsolationLevel = IsolationLevel.Chaos; }); return user; } @@ -69,45 +57,26 @@ public User GetUserByName_isTransactional(string name) { User user = null; - UseUow(() => - { - user = _repository.FirstOrDefault(x => x.Name == name); - }); + UseUow(() => { user = _repository.FirstOrDefault(x => x.Name == name); }); return user; } - public async Task GetUserByName_async_isTransactional(string name) + public Task GetUserByName_async_isTransactional(string name) { - User user = null; - - await UseUow(async () => - { - user = await _repository.FirstOrDefaultAsync(x => x.Name == name); - }); - - return user; + return UseUow(() => { return _repository.FirstOrDefaultAsync(x => x.Name == name); }); } public async Task CreateMessageAndGet(string message) { - Message msg = null; - await UseUowIfNot(async () => - { - msg = await _messageRepository.InsertAsync(new Message(message)); - }); - - return msg; + return await UseUowIfNot(async () => await _messageRepository.InsertAsync(new Message(message))); } - public Task CreateUserByCorrelating(string name, string surname, string email, string correlationId) + public Task CreateUserByCorrelating(string name, string surname, string email, string correlationId) { return CorrelatingBy(() => { - return UseUow(() => - { - return _repository.InsertAsync(User.Create(name, surname, email)); - }); + return UseUow(() => _repository.InsertAsync(User.Create(name, surname, email))); }, correlationId); } } diff --git a/test/Stove.Tests.SampleApplication/StoveComponentBase_Tests.cs b/test/Stove.Tests.SampleApplication/StoveComponentBase_Tests.cs index f160a28..fee17f6 100644 --- a/test/Stove.Tests.SampleApplication/StoveComponentBase_Tests.cs +++ b/test/Stove.Tests.SampleApplication/StoveComponentBase_Tests.cs @@ -78,7 +78,7 @@ public async Task UseUow_and_correlatingBy_should_work() string correlationId = Guid.NewGuid().ToString(); The().Register((@event, headers) => { - headers[StoveConsts.Events.CorrelationId].ShouldBe(correlationId); + headers[StoveConsts.Events.CausationId].ShouldBe(correlationId); }); await The().CreateUserByCorrelating("oguzhan", "soykan", "oguzhansoykan@gmail.com", correlationId);