1
+ #if NET5_0_OR_GREATER
2
+ //-----------------------------------------------------------------------
3
+ // <copyright file="ApplicationContextManagerInMemory.cs" company="Marimer LLC">
4
+ // Copyright (c) Marimer LLC. All rights reserved.
5
+ // Website: https://cslanet.com
6
+ // </copyright>
7
+ // <summary>Application context manager that uses HttpContextAccessor</summary>
8
+ //-----------------------------------------------------------------------
9
+ using Csla . Core ;
10
+ using Microsoft . AspNetCore . Components . Authorization ;
11
+ using System ;
12
+ using System . Security . Claims ;
13
+ using System . Security . Principal ;
14
+ using System . Threading . Tasks ;
15
+
16
+ namespace Csla . AspNetCore . Blazor
17
+ {
18
+ /// <summary>
19
+ /// Application context manager that uses HttpContextAccessor when
20
+ /// resolving HttpContext to store context values.
21
+ /// </summary>
22
+ public class ApplicationContextManagerInMemory : IContextManager , IDisposable
23
+ {
24
+ private ContextDictionary LocalContext { get ; set ; }
25
+ private ContextDictionary ClientContext { get ; set ; }
26
+ private IPrincipal CurrentPrincipal { get ; set ; }
27
+ private readonly ClaimsPrincipal UnauthenticatedPrincipal = new ( ) ;
28
+ private bool disposedValue ;
29
+
30
+ /// <summary>
31
+ /// Gets the current HttpContext instance.
32
+ /// </summary>
33
+ protected AuthenticationStateProvider AuthenticationStateProvider { get ; private set ; }
34
+
35
+ /// <summary>
36
+ /// Gets or sets a reference to the current ApplicationContext.
37
+ /// </summary>
38
+ public ApplicationContext ApplicationContext { get ; set ; }
39
+
40
+ /// <summary>
41
+ /// Gets the active circuit state.
42
+ /// </summary>
43
+ protected ActiveCircuitState ActiveCircuitState { get ; private set ; }
44
+
45
+ /// <summary>
46
+ /// Creates an instance of the object, initializing it
47
+ /// with the required IServiceProvider.
48
+ /// </summary>
49
+ /// <param name="authenticationStateProvider">AuthenticationStateProvider service</param>
50
+ /// <param name="activeCircuitState"></param>
51
+ public ApplicationContextManagerInMemory ( AuthenticationStateProvider authenticationStateProvider , ActiveCircuitState activeCircuitState )
52
+ {
53
+ AuthenticationStateProvider = authenticationStateProvider ;
54
+ ActiveCircuitState = activeCircuitState ;
55
+ CurrentPrincipal = UnauthenticatedPrincipal ;
56
+ AuthenticationStateProvider . AuthenticationStateChanged += AuthenticationStateProvider_AuthenticationStateChanged ;
57
+ InitializeUser ( ) ;
58
+ }
59
+
60
+ private void InitializeUser ( )
61
+ {
62
+ Task < AuthenticationState > task = default ;
63
+ try
64
+ {
65
+ task = AuthenticationStateProvider . GetAuthenticationStateAsync ( ) ;
66
+ }
67
+ catch ( InvalidOperationException ex )
68
+ {
69
+ task = Task . FromResult ( new AuthenticationState ( ( ClaimsPrincipal ) UnauthenticatedPrincipal ) ) ;
70
+ string message = ex . Message ;
71
+ if ( message . Contains ( nameof ( AuthenticationStateProvider . GetAuthenticationStateAsync ) )
72
+ && message . Contains ( nameof ( IHostEnvironmentAuthenticationStateProvider . SetAuthenticationState ) ) )
73
+ {
74
+ SetHostPrincipal ( task ) ;
75
+ }
76
+ else
77
+ {
78
+ throw ;
79
+ }
80
+ }
81
+ AuthenticationStateProvider_AuthenticationStateChanged ( task ) ;
82
+ }
83
+
84
+ private void AuthenticationStateProvider_AuthenticationStateChanged ( Task < AuthenticationState > task )
85
+ {
86
+ if ( task is null )
87
+ {
88
+ CurrentPrincipal = UnauthenticatedPrincipal ;
89
+ }
90
+ else
91
+ {
92
+ task . ContinueWith ( ( t ) =>
93
+ {
94
+ if ( task . IsCompletedSuccessfully && task . Result != null )
95
+ CurrentPrincipal = task . Result . User ;
96
+ else
97
+ CurrentPrincipal = UnauthenticatedPrincipal ;
98
+ } ) ;
99
+ }
100
+ }
101
+
102
+ /// <summary>
103
+ /// Gets a value indicating whether this
104
+ /// context manager is valid for use in
105
+ /// the current environment.
106
+ /// </summary>
107
+ public bool IsValid
108
+ {
109
+ get { return ActiveCircuitState . CircuitExists ; }
110
+ }
111
+
112
+ /// <summary>
113
+ /// Gets a value indicating whether the context manager
114
+ /// is stateful.
115
+ /// </summary>
116
+ public bool IsStatefulContext => true ;
117
+
118
+ /// <summary>
119
+ /// Gets the current principal.
120
+ /// </summary>
121
+ public IPrincipal GetUser ( )
122
+ {
123
+ return CurrentPrincipal ;
124
+ }
125
+
126
+ /// <summary>
127
+ /// Attempts to set the current principal on the registered
128
+ /// IHostEnvironmentAuthenticationStateProvider service.
129
+ /// </summary>
130
+ /// <param name="principal">Principal object.</param>
131
+ public virtual void SetUser ( IPrincipal principal )
132
+ {
133
+ if ( ! ReferenceEquals ( CurrentPrincipal , principal ) )
134
+ {
135
+ if ( principal is ClaimsPrincipal claimsPrincipal )
136
+ {
137
+ CurrentPrincipal = principal ;
138
+ SetHostPrincipal ( Task . FromResult ( new AuthenticationState ( claimsPrincipal ) ) ) ;
139
+ }
140
+ else
141
+ {
142
+ throw new ArgumentException ( "typeof(principal) != ClaimsPrincipal" ) ;
143
+ }
144
+ }
145
+ }
146
+
147
+ private void SetHostPrincipal ( Task < AuthenticationState > task )
148
+ {
149
+ if ( AuthenticationStateProvider is IHostEnvironmentAuthenticationStateProvider hostProvider )
150
+ hostProvider . SetAuthenticationState ( task ) ;
151
+ }
152
+
153
+ /// <summary>
154
+ /// Gets the local context.
155
+ /// </summary>
156
+ public ContextDictionary GetLocalContext ( )
157
+ {
158
+ if ( LocalContext == null )
159
+ LocalContext = new ContextDictionary ( ) ;
160
+ return LocalContext ;
161
+ }
162
+
163
+ /// <summary>
164
+ /// Sets the local context.
165
+ /// </summary>
166
+ /// <param name="localContext">Local context.</param>
167
+ public void SetLocalContext ( ContextDictionary localContext )
168
+ {
169
+ LocalContext = localContext ;
170
+ }
171
+
172
+ /// <summary>
173
+ /// Gets the client context.
174
+ /// </summary>
175
+ /// <param name="executionLocation"></param>
176
+ public ContextDictionary GetClientContext ( ApplicationContext . ExecutionLocations executionLocation )
177
+ {
178
+ if ( ClientContext == null )
179
+ ClientContext = new ContextDictionary ( ) ;
180
+ return ClientContext ;
181
+ }
182
+
183
+ /// <summary>
184
+ /// Sets the client context.
185
+ /// </summary>
186
+ /// <param name="clientContext">Client context.</param>
187
+ /// <param name="executionLocation"></param>
188
+ public void SetClientContext ( ContextDictionary clientContext , ApplicationContext . ExecutionLocations executionLocation )
189
+ {
190
+ ClientContext = clientContext ;
191
+ }
192
+
193
+ /// <summary>
194
+ /// Dispose this object's resources.
195
+ /// </summary>
196
+ /// <param name="disposing"></param>
197
+ protected virtual void Dispose ( bool disposing )
198
+ {
199
+ if ( ! disposedValue )
200
+ {
201
+ if ( disposing )
202
+ {
203
+ AuthenticationStateProvider . AuthenticationStateChanged -= AuthenticationStateProvider_AuthenticationStateChanged ;
204
+ }
205
+ disposedValue = true ;
206
+ }
207
+ }
208
+
209
+ /// <summary>
210
+ /// Dispose this object's resources.
211
+ /// </summary>
212
+ public void Dispose ( )
213
+ {
214
+ // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
215
+ Dispose ( disposing : true ) ;
216
+ GC . SuppressFinalize ( this ) ;
217
+ }
218
+ }
219
+ }
220
+ #endif
0 commit comments