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

Commit b954141

Browse files
authored
Merge pull request #84 from stoveproject/dev
dev to master
2 parents 01a30f0 + d05e939 commit b954141

File tree

8 files changed

+353
-163
lines changed

8 files changed

+353
-163
lines changed

common.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<VersionPrefix>2.0.2</VersionPrefix>
3+
<VersionPrefix>2.0.3</VersionPrefix>
44
<NoWarn>$(NoWarn);CS1591</NoWarn>
55
<PackageIconUrl>https://raw.githubusercontent.com/osoykan/Stove/master/stove.png</PackageIconUrl>
66
<PackageProjectUrl>https://github.com/osoykan/Stove</PackageProjectUrl>

src/Stove/Domain/Uow/AsyncLocalCurrentUnitOfWorkProvider.cs

Lines changed: 85 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -6,93 +6,89 @@
66

77
namespace Stove.Domain.Uow
88
{
9-
/// <summary>
10-
/// CallContext implementation of <see cref="ICurrentUnitOfWorkProvider" />.
11-
/// This is the default implementation.
12-
/// </summary>
13-
public class AsyncLocalCurrentUnitOfWorkProvider : ICurrentUnitOfWorkProvider, ITransientDependency
14-
{
15-
private static readonly AsyncLocal<LocalUowWrapper> AsyncLocalUow = new AsyncLocal<LocalUowWrapper>();
16-
17-
public AsyncLocalCurrentUnitOfWorkProvider()
18-
{
19-
Logger = NullLogger.Instance;
20-
}
21-
22-
public ILogger Logger { get; set; }
23-
24-
/// <inheritdoc />
25-
[DoNotInject]
26-
public IUnitOfWork Current
27-
{
28-
get { return GetCurrentUow(); }
29-
set { SetCurrentUow(value); }
30-
}
31-
32-
private static IUnitOfWork GetCurrentUow()
33-
{
34-
var uow = AsyncLocalUow.Value?.UnitOfWork;
35-
if (uow == null)
36-
{
37-
return null;
38-
}
39-
40-
if (uow.IsDisposed)
41-
{
42-
AsyncLocalUow.Value = null;
43-
return null;
44-
}
45-
46-
return uow;
47-
}
48-
49-
private static void SetCurrentUow(IUnitOfWork value)
50-
{
51-
lock (AsyncLocalUow)
52-
{
53-
if (value == null)
54-
{
55-
if (AsyncLocalUow.Value == null)
56-
{
57-
return;
58-
}
59-
60-
if (AsyncLocalUow.Value.UnitOfWork?.Outer == null)
61-
{
62-
AsyncLocalUow.Value.UnitOfWork = null;
63-
AsyncLocalUow.Value = null;
64-
return;
65-
}
66-
67-
AsyncLocalUow.Value.UnitOfWork = AsyncLocalUow.Value.UnitOfWork.Outer;
68-
}
69-
else
70-
{
71-
if (AsyncLocalUow.Value?.UnitOfWork == null)
72-
{
73-
if (AsyncLocalUow.Value != null)
74-
{
75-
AsyncLocalUow.Value.UnitOfWork = value;
76-
}
77-
78-
AsyncLocalUow.Value = new LocalUowWrapper(value);
79-
return;
80-
}
81-
82-
value.Outer = AsyncLocalUow.Value.UnitOfWork;
83-
AsyncLocalUow.Value.UnitOfWork = value;
84-
}
85-
}
86-
}
87-
88-
private class LocalUowWrapper
89-
{
90-
public LocalUowWrapper(IUnitOfWork unitOfWork)
91-
{
92-
UnitOfWork = unitOfWork;
93-
}
94-
95-
public IUnitOfWork UnitOfWork { get; set; }
96-
}
97-
}
9+
public class AsyncLocalCurrentUnitOfWorkProvider : ICurrentUnitOfWorkProvider
10+
{
11+
private static readonly AsyncLocal<LocalUowWrapper> asyncLocalUow = new AsyncLocal<LocalUowWrapper>();
12+
13+
public AsyncLocalCurrentUnitOfWorkProvider()
14+
{
15+
Logger = NullLogger.Instance;
16+
}
17+
18+
public ILogger Logger { get; set; }
19+
20+
/// <inheritdoc />
21+
[DoNotInject]
22+
public IUnitOfWork Current
23+
{
24+
get => GetCurrentUow();
25+
set => SetCurrentUow(value);
26+
}
27+
28+
private static IUnitOfWork GetCurrentUow()
29+
{
30+
IUnitOfWork uow = asyncLocalUow.Value?.UnitOfWork;
31+
if (uow == null)
32+
{
33+
return null;
34+
}
35+
36+
if (uow.IsDisposed)
37+
{
38+
asyncLocalUow.Value = null;
39+
return null;
40+
}
41+
42+
return uow;
43+
}
44+
45+
private static void SetCurrentUow(IUnitOfWork value)
46+
{
47+
lock (asyncLocalUow)
48+
{
49+
if (value == null)
50+
{
51+
if (asyncLocalUow.Value == null)
52+
{
53+
return;
54+
}
55+
56+
if (asyncLocalUow.Value.UnitOfWork?.Outer == null)
57+
{
58+
asyncLocalUow.Value.UnitOfWork = null;
59+
asyncLocalUow.Value = null;
60+
return;
61+
}
62+
63+
asyncLocalUow.Value.UnitOfWork = asyncLocalUow.Value.UnitOfWork.Outer;
64+
}
65+
else
66+
{
67+
if (asyncLocalUow.Value?.UnitOfWork == null)
68+
{
69+
if (asyncLocalUow.Value != null)
70+
{
71+
asyncLocalUow.Value.UnitOfWork = value;
72+
}
73+
74+
asyncLocalUow.Value = new LocalUowWrapper(value);
75+
return;
76+
}
77+
78+
value.Outer = asyncLocalUow.Value.UnitOfWork;
79+
asyncLocalUow.Value.UnitOfWork = value;
80+
}
81+
}
82+
}
83+
84+
private class LocalUowWrapper
85+
{
86+
public LocalUowWrapper(IUnitOfWork unitOfWork)
87+
{
88+
UnitOfWork = unitOfWork;
89+
}
90+
91+
public IUnitOfWork UnitOfWork { get; set; }
92+
}
93+
}
9894
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
using System.Collections.Concurrent;
2+
3+
using Autofac.Extras.IocManager;
4+
5+
using Stove.Log;
6+
using Stove.Threading;
7+
8+
namespace Stove.Domain.Uow
9+
{
10+
public class CallContextDrivenAsyncLocalCurrentUnitOfWorkProvider : ICurrentUnitOfWorkProvider, ITransientDependency
11+
{
12+
private const string ContextKey = "Stove.UnitOfWork.Current";
13+
private static readonly ConcurrentDictionary<string, IUnitOfWork> unitOfWorkDictionary = new ConcurrentDictionary<string, IUnitOfWork>();
14+
15+
public CallContextDrivenAsyncLocalCurrentUnitOfWorkProvider()
16+
{
17+
Logger = NullLogger.Instance;
18+
}
19+
20+
public ILogger Logger { get; set; }
21+
22+
[DoNotInject]
23+
public IUnitOfWork Current
24+
{
25+
get => GetCurrentUow(Logger);
26+
set => SetCurrentUow(value, Logger);
27+
}
28+
29+
private static IUnitOfWork GetCurrentUow(ILogger logger)
30+
{
31+
if (!(CallContext.GetData(ContextKey) is string unitOfWorkKey))
32+
{
33+
return null;
34+
}
35+
36+
if (!unitOfWorkDictionary.TryGetValue(unitOfWorkKey, out IUnitOfWork unitOfWork))
37+
{
38+
CallContext.SetData(ContextKey, null);
39+
return null;
40+
}
41+
42+
if (unitOfWork.IsDisposed)
43+
{
44+
logger.Warn("There is a unitOfWorkKey in CallContext but the UOW was disposed!");
45+
unitOfWorkDictionary.TryRemove(unitOfWorkKey, out unitOfWork);
46+
CallContext.SetData(ContextKey, null);
47+
return null;
48+
}
49+
50+
return unitOfWork;
51+
}
52+
53+
private static void SetCurrentUow(IUnitOfWork value, ILogger logger)
54+
{
55+
if (value == null)
56+
{
57+
ExitFromCurrentUowScope(logger);
58+
return;
59+
}
60+
61+
if (CallContext.GetData(ContextKey) is string unitOfWorkKey)
62+
{
63+
if (unitOfWorkDictionary.TryGetValue(unitOfWorkKey, out IUnitOfWork outer))
64+
{
65+
if (outer == value)
66+
{
67+
logger.Warn("Setting the same UOW to the CallContext, no need to set again!");
68+
return;
69+
}
70+
71+
value.Outer = outer;
72+
}
73+
}
74+
75+
unitOfWorkKey = value.Id;
76+
if (!unitOfWorkDictionary.TryAdd(unitOfWorkKey, value))
77+
{
78+
throw new StoveException("Can not set unit of work! UnitOfWorkDictionary.TryAdd returns false!");
79+
}
80+
81+
CallContext.SetData(ContextKey, unitOfWorkKey);
82+
}
83+
84+
private static void ExitFromCurrentUowScope(ILogger logger)
85+
{
86+
if (!(CallContext.GetData(ContextKey) is string unitOfWorkKey))
87+
{
88+
logger.Warn("There is no current UOW to exit!");
89+
return;
90+
}
91+
92+
if (!unitOfWorkDictionary.TryGetValue(unitOfWorkKey, out IUnitOfWork unitOfWork))
93+
{
94+
CallContext.SetData(ContextKey, null);
95+
return;
96+
}
97+
98+
unitOfWorkDictionary.TryRemove(unitOfWorkKey, out unitOfWork);
99+
if (unitOfWork.Outer == null)
100+
{
101+
CallContext.SetData(ContextKey, null);
102+
return;
103+
}
104+
105+
//Restore outer UOW
106+
string outerUnitOfWorkKey = unitOfWork.Outer.Id;
107+
if (!unitOfWorkDictionary.TryGetValue(outerUnitOfWorkKey, out unitOfWork))
108+
{
109+
//No outer UOW
110+
logger.Warn("Outer UOW key could not found in UnitOfWorkDictionary!");
111+
CallContext.SetData(ContextKey, null);
112+
return;
113+
}
114+
115+
CallContext.SetData(ContextKey, outerUnitOfWorkKey);
116+
}
117+
}
118+
}

0 commit comments

Comments
 (0)