diff --git a/Source/Csla.AspNetCore/Blazor/ApplicationContextManagerInMemory.cs b/Source/Csla.AspNetCore/Blazor/ApplicationContextManagerInMemory.cs
new file mode 100644
index 0000000000..a7643bbda5
--- /dev/null
+++ b/Source/Csla.AspNetCore/Blazor/ApplicationContextManagerInMemory.cs
@@ -0,0 +1,220 @@
+#if NET5_0_OR_GREATER
+//-----------------------------------------------------------------------
+//
+// Copyright (c) Marimer LLC. All rights reserved.
+// Website: https://cslanet.com
+//
+// Application context manager that uses HttpContextAccessor
+//-----------------------------------------------------------------------
+using Csla.Core;
+using Microsoft.AspNetCore.Components.Authorization;
+using System;
+using System.Security.Claims;
+using System.Security.Principal;
+using System.Threading.Tasks;
+
+namespace Csla.AspNetCore.Blazor
+{
+ ///
+ /// Application context manager that uses HttpContextAccessor when
+ /// resolving HttpContext to store context values.
+ ///
+ public class ApplicationContextManagerInMemory : IContextManager, IDisposable
+ {
+ private ContextDictionary LocalContext { get; set; }
+ private ContextDictionary ClientContext { get; set; }
+ private IPrincipal CurrentPrincipal { get; set; }
+ private readonly ClaimsPrincipal UnauthenticatedPrincipal = new();
+ private bool disposedValue;
+
+ ///
+ /// Gets the current HttpContext instance.
+ ///
+ protected AuthenticationStateProvider AuthenticationStateProvider { get; private set; }
+
+ ///
+ /// Gets or sets a reference to the current ApplicationContext.
+ ///
+ public ApplicationContext ApplicationContext { get; set; }
+
+ ///
+ /// Gets the active circuit state.
+ ///
+ protected ActiveCircuitState ActiveCircuitState { get; private set; }
+
+ ///
+ /// Creates an instance of the object, initializing it
+ /// with the required IServiceProvider.
+ ///
+ /// AuthenticationStateProvider service
+ ///
+ public ApplicationContextManagerInMemory(AuthenticationStateProvider authenticationStateProvider, ActiveCircuitState activeCircuitState)
+ {
+ AuthenticationStateProvider = authenticationStateProvider;
+ ActiveCircuitState = activeCircuitState;
+ CurrentPrincipal = UnauthenticatedPrincipal;
+ AuthenticationStateProvider.AuthenticationStateChanged += AuthenticationStateProvider_AuthenticationStateChanged;
+ InitializeUser();
+ }
+
+ private void InitializeUser()
+ {
+ Task task = default;
+ try
+ {
+ task = AuthenticationStateProvider.GetAuthenticationStateAsync();
+ }
+ catch (InvalidOperationException ex)
+ {
+ task = Task.FromResult(new AuthenticationState((ClaimsPrincipal)UnauthenticatedPrincipal));
+ string message = ex.Message;
+ if (message.Contains(nameof(AuthenticationStateProvider.GetAuthenticationStateAsync))
+ && message.Contains(nameof(IHostEnvironmentAuthenticationStateProvider.SetAuthenticationState)))
+ {
+ SetHostPrincipal(task);
+ }
+ else
+ {
+ throw;
+ }
+ }
+ AuthenticationStateProvider_AuthenticationStateChanged(task);
+ }
+
+ private void AuthenticationStateProvider_AuthenticationStateChanged(Task task)
+ {
+ if (task is null)
+ {
+ CurrentPrincipal = UnauthenticatedPrincipal;
+ }
+ else
+ {
+ task.ContinueWith((t) =>
+ {
+ if (task.IsCompletedSuccessfully && task.Result != null)
+ CurrentPrincipal = task.Result.User;
+ else
+ CurrentPrincipal = UnauthenticatedPrincipal;
+ });
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether this
+ /// context manager is valid for use in
+ /// the current environment.
+ ///
+ public bool IsValid
+ {
+ get { return ActiveCircuitState.CircuitExists; }
+ }
+
+ ///
+ /// Gets a value indicating whether the context manager
+ /// is stateful.
+ ///
+ public bool IsStatefulContext => true;
+
+ ///
+ /// Gets the current principal.
+ ///
+ public IPrincipal GetUser()
+ {
+ return CurrentPrincipal;
+ }
+
+ ///
+ /// Attempts to set the current principal on the registered
+ /// IHostEnvironmentAuthenticationStateProvider service.
+ ///
+ /// Principal object.
+ public virtual void SetUser(IPrincipal principal)
+ {
+ if (!ReferenceEquals(CurrentPrincipal, principal))
+ {
+ if (principal is ClaimsPrincipal claimsPrincipal)
+ {
+ CurrentPrincipal = principal;
+ SetHostPrincipal(Task.FromResult(new AuthenticationState(claimsPrincipal)));
+ }
+ else
+ {
+ throw new ArgumentException("typeof(principal) != ClaimsPrincipal");
+ }
+ }
+ }
+
+ private void SetHostPrincipal(Task task)
+ {
+ if (AuthenticationStateProvider is IHostEnvironmentAuthenticationStateProvider hostProvider)
+ hostProvider.SetAuthenticationState(task);
+ }
+
+ ///
+ /// Gets the local context.
+ ///
+ public ContextDictionary GetLocalContext()
+ {
+ if (LocalContext == null)
+ LocalContext = new ContextDictionary();
+ return LocalContext;
+ }
+
+ ///
+ /// Sets the local context.
+ ///
+ /// Local context.
+ public void SetLocalContext(ContextDictionary localContext)
+ {
+ LocalContext = localContext;
+ }
+
+ ///
+ /// Gets the client context.
+ ///
+ ///
+ public ContextDictionary GetClientContext(ApplicationContext.ExecutionLocations executionLocation)
+ {
+ if (ClientContext == null)
+ ClientContext = new ContextDictionary();
+ return ClientContext;
+ }
+
+ ///
+ /// Sets the client context.
+ ///
+ /// Client context.
+ ///
+ public void SetClientContext(ContextDictionary clientContext, ApplicationContext.ExecutionLocations executionLocation)
+ {
+ ClientContext = clientContext;
+ }
+
+ ///
+ /// Dispose this object's resources.
+ ///
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposedValue)
+ {
+ if (disposing)
+ {
+ AuthenticationStateProvider.AuthenticationStateChanged -= AuthenticationStateProvider_AuthenticationStateChanged;
+ }
+ disposedValue = true;
+ }
+ }
+
+ ///
+ /// Dispose this object's resources.
+ ///
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/Source/Csla.Blazor/ConfigurationExtensions.cs b/Source/Csla.Blazor/ConfigurationExtensions.cs
index 95dd03b6a8..80fcd7d5b4 100644
--- a/Source/Csla.Blazor/ConfigurationExtensions.cs
+++ b/Source/Csla.Blazor/ConfigurationExtensions.cs
@@ -45,9 +45,14 @@ public static CslaOptions AddServerSideBlazor(this CslaOptions config, Action i.ServiceType.Equals(contextManagerType)).ToList();
foreach ( var manager in managers )
@@ -82,6 +87,12 @@ public class BlazorServerConfigurationOptions
///
public bool UseCslaPermissionsPolicy { get; set; } = true;
+ ///
+ /// Gets or sets a value indicating whether to use the
+ /// pre-Blazor 8 in-memory context manager.
+ ///
+ public bool UseInMemoryApplicationContextManager { get; set; }
+
///
/// Gets or sets the type of the ISessionManager service.
///