1
- // Copyright 2004-2020 Castle Project - http://www.castleproject.org/
1
+ // Copyright 2004-2020 Castle Project - http://www.castleproject.org/
2
2
//
3
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
4
// you may not use this file except in compliance with the License.
14
14
15
15
namespace Castle . Windsor . Extensions . DependencyInjection . Scope
16
16
{
17
- internal class ExtensionContainerScope : ExtensionContainerScopeBase
17
+ using System ;
18
+ using System . Threading ;
19
+
20
+ using Castle . Core ;
21
+ using Castle . MicroKernel ;
22
+ using Castle . MicroKernel . Lifestyle . Scoped ;
23
+
24
+ internal class ExtensionContainerScope : ILifetimeScope , IDisposable
18
25
{
19
- private readonly ExtensionContainerScopeBase parent ;
26
+ public static ExtensionContainerScope Current => current . Value ;
27
+ public static string TransientMarker = "Transient" ;
28
+ protected static readonly AsyncLocal < ExtensionContainerScope > current = new AsyncLocal < ExtensionContainerScope > ( ) ;
29
+ private readonly ExtensionContainerScope parent ;
30
+ private readonly ExtensionContainerRootScope rootScope ;
31
+ private readonly IScopeCache scopeCache ;
20
32
21
- protected ExtensionContainerScope ( )
33
+ protected ExtensionContainerScope (
34
+ ExtensionContainerScope parent ,
35
+ ExtensionContainerRootScope rootScope )
22
36
{
23
- parent = ExtensionContainerScopeCache . Current ;
37
+ scopeCache = new ScopeCache ( ) ;
38
+ this . parent = parent ?? rootScope ;
39
+ this . rootScope = rootScope ;
24
40
}
25
41
26
- internal override ExtensionContainerScopeBase RootScope { get ; set ; }
27
-
42
+ public ExtensionContainerRootScope RootScope
43
+ => this as ExtensionContainerRootScope ?? rootScope ;
28
44
29
- internal static ExtensionContainerScopeBase BeginScope ( )
45
+ public static ExtensionContainerScope BeginScope ( ExtensionContainerScope parent , ExtensionContainerRootScope rootScope )
30
46
{
31
- var scope = new ExtensionContainerScope { RootScope = ExtensionContainerScopeCache . Current . RootScope } ;
32
- ExtensionContainerScopeCache . Current = scope ;
47
+ if ( rootScope == null )
48
+ throw new ArgumentNullException ( nameof ( rootScope ) ) ;
49
+
50
+ var scope = new ExtensionContainerScope ( parent , rootScope ) ;
51
+ current . Value = scope ;
33
52
return scope ;
34
53
}
35
54
36
- public override void Dispose ( )
55
+ public void Dispose ( )
56
+ {
57
+ var disposableCache = scopeCache as IDisposable ;
58
+ if ( disposableCache != null )
59
+ {
60
+ disposableCache . Dispose ( ) ;
61
+ }
62
+
63
+ current . Value = parent ;
64
+ }
65
+
66
+ public Burden GetCachedInstance ( ComponentModel model , ScopedInstanceActivationCallback createInstance )
37
67
{
38
- if ( ExtensionContainerScopeCache . current . Value == this )
68
+ lock ( scopeCache )
69
+ {
70
+ // Add transient's burden to scope so it gets released
71
+ if ( model . Configuration . Attributes . Get ( TransientMarker ) == bool . TrueString )
72
+ {
73
+ var transientBurden = createInstance ( ( _ ) => { } ) ;
74
+ scopeCache [ transientBurden ] = transientBurden ;
75
+ return transientBurden ;
76
+ }
77
+
78
+ var scopedBurden = scopeCache [ model ] ;
79
+ if ( scopedBurden != null )
80
+ {
81
+ return scopedBurden ;
82
+ }
83
+ scopedBurden = createInstance ( ( _ ) => { } ) ;
84
+ scopeCache [ model ] = scopedBurden ;
85
+ return scopedBurden ;
86
+ }
87
+ }
88
+
89
+ /// <summary>
90
+ /// Forces a specific <see name="ExtensionContainerScope" /> for 'using' block. In .NET scope is tied to an instance of <see name="System.IServiceProvider" /> not a thread or async context
91
+ /// </summary>
92
+ internal class ForcedScope : IDisposable
93
+ {
94
+ private readonly ExtensionContainerScope previousScope ;
95
+ public ForcedScope ( ExtensionContainerScope scope )
96
+ {
97
+ previousScope = ExtensionContainerScope . Current ;
98
+ ExtensionContainerScope . current . Value = scope ;
99
+ }
100
+ public void Dispose ( )
39
101
{
40
- ExtensionContainerScopeCache . current . Value = parent ;
102
+ ExtensionContainerScope . current . Value = previousScope ;
41
103
}
42
- base . Dispose ( ) ;
43
104
}
44
105
}
45
- }
106
+ }
0 commit comments