diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs
index efb6dc991..c852c7843 100644
--- a/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs
+++ b/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapter.cs
@@ -82,6 +82,12 @@ protected override async Task RemoveKeyAsync(string cacheKey)
catch (Exception ex)
{
_logger.LogError($"[IdWebCache] Connection issue encountered with Distributed cache. Currently using In Memory cache only. Error message: {ex.Message} ");
+
+ if (_distributedCacheOptions.OnL2CacheFailure != null && _distributedCacheOptions.OnL2CacheFailure(ex))
+ {
+ _logger.LogDebug($"[IdWebCache] DistributedCache: Retry to remove cacheKey {cacheKey}. ");
+ await _distributedCache.RemoveAsync(cacheKey).ConfigureAwait(false);
+ }
}
}
diff --git a/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapterOptions.cs b/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapterOptions.cs
index b15933f1c..42e202d47 100644
--- a/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapterOptions.cs
+++ b/src/Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalDistributedTokenCacheAdapterOptions.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
+using System;
using Microsoft.Extensions.Caching.Distributed;
namespace Microsoft.Identity.Web.TokenCacheProviders.Distributed
@@ -18,6 +19,17 @@ public class MsalDistributedTokenCacheAdapterOptions : DistributedCacheEntryOpti
///
public long L1CacheSizeLimit { get; set; } = 500;
+ ///
+ /// Callback offered to the app to be notified when the L2 cache fails.
+ /// This way the app is given the possibility to act on the L2 cache,
+ /// for instance, in the case of Redis, to reconnect. This is left to the application as it's
+ /// the only one that knows about the real implementation of the L2 cache.
+ /// The handler should return true if the cache should try again the operation, and
+ /// false otherwise. When true is passed and the retry fails, an exception
+ /// will be thrown.
+ ///
+ public Func? OnL2CacheFailure { get; set; }
+
///
/// Value more than 0, less than 1, to set the In Memory (L1) cache
/// expiration time values relative to the Distributed (L2) cache.
diff --git a/tests/WebAppCallsWebApiCallsGraph/Client/Startup.cs b/tests/WebAppCallsWebApiCallsGraph/Client/Startup.cs
index a6952921f..3a90a194e 100644
--- a/tests/WebAppCallsWebApiCallsGraph/Client/Startup.cs
+++ b/tests/WebAppCallsWebApiCallsGraph/Client/Startup.cs
@@ -14,6 +14,7 @@
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web.UI;
+using Microsoft.Identity.Web.TokenCacheProviders.Distributed;
namespace WebApp_OpenIDConnect_DotNet
{
@@ -48,6 +49,18 @@ public void ConfigureServices(IServiceCollection services)
options.Configuration = Configuration.GetConnectionString("Redis");
options.InstanceName = "RedisDemos_"; //should be unique to the app
});
+ services.Configure(options =>
+ {
+ options.OnL2CacheFailure = (ex) =>
+ {
+ if (ex is StackExchange.Redis.RedisConnectionException)
+ {
+ // action: try to reconnect or something
+ return true; //try to do the cache operation again
+ }
+ return false;
+ };
+ });
#endif
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)