Skip to content
This repository was archived by the owner on May 7, 2020. It is now read-only.

Commit

Permalink
Merge pull request #84 from stoveproject/dev
Browse files Browse the repository at this point in the history
dev to master
  • Loading branch information
osoykan authored Oct 4, 2017
2 parents 01a30f0 + d05e939 commit b954141
Show file tree
Hide file tree
Showing 8 changed files with 353 additions and 163 deletions.
2 changes: 1 addition & 1 deletion common.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<VersionPrefix>2.0.2</VersionPrefix>
<VersionPrefix>2.0.3</VersionPrefix>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<PackageIconUrl>https://raw.githubusercontent.com/osoykan/Stove/master/stove.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/osoykan/Stove</PackageProjectUrl>
Expand Down
174 changes: 85 additions & 89 deletions src/Stove/Domain/Uow/AsyncLocalCurrentUnitOfWorkProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,93 +6,89 @@

namespace Stove.Domain.Uow
{
/// <summary>
/// CallContext implementation of <see cref="ICurrentUnitOfWorkProvider" />.
/// This is the default implementation.
/// </summary>
public class AsyncLocalCurrentUnitOfWorkProvider : ICurrentUnitOfWorkProvider, ITransientDependency
{
private static readonly AsyncLocal<LocalUowWrapper> AsyncLocalUow = new AsyncLocal<LocalUowWrapper>();

public AsyncLocalCurrentUnitOfWorkProvider()
{
Logger = NullLogger.Instance;
}

public ILogger Logger { get; set; }

/// <inheritdoc />
[DoNotInject]
public IUnitOfWork Current
{
get { return GetCurrentUow(); }
set { SetCurrentUow(value); }
}

private static IUnitOfWork GetCurrentUow()
{
var uow = AsyncLocalUow.Value?.UnitOfWork;
if (uow == null)
{
return null;
}

if (uow.IsDisposed)
{
AsyncLocalUow.Value = null;
return null;
}

return uow;
}

private static void SetCurrentUow(IUnitOfWork value)
{
lock (AsyncLocalUow)
{
if (value == null)
{
if (AsyncLocalUow.Value == null)
{
return;
}

if (AsyncLocalUow.Value.UnitOfWork?.Outer == null)
{
AsyncLocalUow.Value.UnitOfWork = null;
AsyncLocalUow.Value = null;
return;
}

AsyncLocalUow.Value.UnitOfWork = AsyncLocalUow.Value.UnitOfWork.Outer;
}
else
{
if (AsyncLocalUow.Value?.UnitOfWork == null)
{
if (AsyncLocalUow.Value != null)
{
AsyncLocalUow.Value.UnitOfWork = value;
}

AsyncLocalUow.Value = new LocalUowWrapper(value);
return;
}

value.Outer = AsyncLocalUow.Value.UnitOfWork;
AsyncLocalUow.Value.UnitOfWork = value;
}
}
}

private class LocalUowWrapper
{
public LocalUowWrapper(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}

public IUnitOfWork UnitOfWork { get; set; }
}
}
public class AsyncLocalCurrentUnitOfWorkProvider : ICurrentUnitOfWorkProvider
{
private static readonly AsyncLocal<LocalUowWrapper> asyncLocalUow = new AsyncLocal<LocalUowWrapper>();

public AsyncLocalCurrentUnitOfWorkProvider()
{
Logger = NullLogger.Instance;
}

public ILogger Logger { get; set; }

/// <inheritdoc />
[DoNotInject]
public IUnitOfWork Current
{
get => GetCurrentUow();
set => SetCurrentUow(value);
}

private static IUnitOfWork GetCurrentUow()
{
IUnitOfWork uow = asyncLocalUow.Value?.UnitOfWork;
if (uow == null)
{
return null;
}

if (uow.IsDisposed)
{
asyncLocalUow.Value = null;
return null;
}

return uow;
}

private static void SetCurrentUow(IUnitOfWork value)
{
lock (asyncLocalUow)
{
if (value == null)
{
if (asyncLocalUow.Value == null)
{
return;
}

if (asyncLocalUow.Value.UnitOfWork?.Outer == null)
{
asyncLocalUow.Value.UnitOfWork = null;
asyncLocalUow.Value = null;
return;
}

asyncLocalUow.Value.UnitOfWork = asyncLocalUow.Value.UnitOfWork.Outer;
}
else
{
if (asyncLocalUow.Value?.UnitOfWork == null)
{
if (asyncLocalUow.Value != null)
{
asyncLocalUow.Value.UnitOfWork = value;
}

asyncLocalUow.Value = new LocalUowWrapper(value);
return;
}

value.Outer = asyncLocalUow.Value.UnitOfWork;
asyncLocalUow.Value.UnitOfWork = value;
}
}
}

private class LocalUowWrapper
{
public LocalUowWrapper(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}

public IUnitOfWork UnitOfWork { get; set; }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System.Collections.Concurrent;

using Autofac.Extras.IocManager;

using Stove.Log;
using Stove.Threading;

namespace Stove.Domain.Uow
{
public class CallContextDrivenAsyncLocalCurrentUnitOfWorkProvider : ICurrentUnitOfWorkProvider, ITransientDependency
{
private const string ContextKey = "Stove.UnitOfWork.Current";
private static readonly ConcurrentDictionary<string, IUnitOfWork> unitOfWorkDictionary = new ConcurrentDictionary<string, IUnitOfWork>();

public CallContextDrivenAsyncLocalCurrentUnitOfWorkProvider()
{
Logger = NullLogger.Instance;
}

public ILogger Logger { get; set; }

[DoNotInject]
public IUnitOfWork Current
{
get => GetCurrentUow(Logger);
set => SetCurrentUow(value, Logger);
}

private static IUnitOfWork GetCurrentUow(ILogger logger)
{
if (!(CallContext.GetData(ContextKey) is string unitOfWorkKey))
{
return null;
}

if (!unitOfWorkDictionary.TryGetValue(unitOfWorkKey, out IUnitOfWork unitOfWork))
{
CallContext.SetData(ContextKey, null);
return null;
}

if (unitOfWork.IsDisposed)
{
logger.Warn("There is a unitOfWorkKey in CallContext but the UOW was disposed!");
unitOfWorkDictionary.TryRemove(unitOfWorkKey, out unitOfWork);
CallContext.SetData(ContextKey, null);
return null;
}

return unitOfWork;
}

private static void SetCurrentUow(IUnitOfWork value, ILogger logger)
{
if (value == null)
{
ExitFromCurrentUowScope(logger);
return;
}

if (CallContext.GetData(ContextKey) is string unitOfWorkKey)
{
if (unitOfWorkDictionary.TryGetValue(unitOfWorkKey, out IUnitOfWork outer))
{
if (outer == value)
{
logger.Warn("Setting the same UOW to the CallContext, no need to set again!");
return;
}

value.Outer = outer;
}
}

unitOfWorkKey = value.Id;
if (!unitOfWorkDictionary.TryAdd(unitOfWorkKey, value))
{
throw new StoveException("Can not set unit of work! UnitOfWorkDictionary.TryAdd returns false!");
}

CallContext.SetData(ContextKey, unitOfWorkKey);
}

private static void ExitFromCurrentUowScope(ILogger logger)
{
if (!(CallContext.GetData(ContextKey) is string unitOfWorkKey))
{
logger.Warn("There is no current UOW to exit!");
return;
}

if (!unitOfWorkDictionary.TryGetValue(unitOfWorkKey, out IUnitOfWork unitOfWork))
{
CallContext.SetData(ContextKey, null);
return;
}

unitOfWorkDictionary.TryRemove(unitOfWorkKey, out unitOfWork);
if (unitOfWork.Outer == null)
{
CallContext.SetData(ContextKey, null);
return;
}

//Restore outer UOW
string outerUnitOfWorkKey = unitOfWork.Outer.Id;
if (!unitOfWorkDictionary.TryGetValue(outerUnitOfWorkKey, out unitOfWork))
{
//No outer UOW
logger.Warn("Outer UOW key could not found in UnitOfWorkDictionary!");
CallContext.SetData(ContextKey, null);
return;
}

CallContext.SetData(ContextKey, outerUnitOfWorkKey);
}
}
}
Loading

0 comments on commit b954141

Please sign in to comment.