/// <summary>
        /// Raised AFTER MSAL added the new token in its in-memory copy of the cache.
        /// This notification is called every time MSAL accesses the cache, not just when a write takes place:
        /// If MSAL's current operation resulted in a cache change, the property TokenCacheNotificationArgs.HasStateChanged will be set to true.
        /// If that is the case, we call the TokenCache.SerializeMsalV3() to get a binary blob representing the latest cache content – and persist it.
        /// </summary>
        /// <param name="args">Contains parameters used by the MSAL call accessing the cache.</param>
        private async Task OnAfterAccessAsync(TokenCacheNotificationArgs args)
        {
            // The access operation resulted in a cache update.
            if (args.HasStateChanged)
            {
                CacheSerializerHints cacheSerializerHints = CreateHintsFromArgs(args);

                if (args.HasTokens)
                {
                    await WriteCacheBytesAsync(args.SuggestedCacheKey, ProtectBytes(args.TokenCache.SerializeMsalV3()), cacheSerializerHints).ConfigureAwait(false);
                }
                else
                {
                    // No token in the cache. we can remove the cache entry
                    await RemoveKeyAsync(args.SuggestedCacheKey, cacheSerializerHints).ConfigureAwait(false);
                }
            }
        }
 /// <summary>
 /// Method to be overridden by concrete cache serializers to remove an entry from the cache.
 /// </summary>
 /// <param name="cacheKey">Cache key.</param>
 /// <param name="cacheSerializerHints">Hints for the cache serialization implementation optimization.</param>
 /// <returns>A <see cref="Task"/> that represents a completed remove key operation.</returns>
 protected virtual Task RemoveKeyAsync(string cacheKey, CacheSerializerHints cacheSerializerHints)
 {
     return(RemoveKeyAsync(cacheKey)); // default implementation avoids a breaking change.
 }
 /// <summary>
 /// Method to be overridden by concrete cache serializers to write the cache bytes.
 /// </summary>
 /// <param name="cacheKey">Cache key.</param>
 /// <param name="bytes">Bytes to write.</param>
 /// <param name="cacheSerializerHints">Hints for the cache serialization implementation optimization.</param>
 /// <returns>A <see cref="Task"/> that represents a completed write operation.</returns>
 protected virtual Task WriteCacheBytesAsync(string cacheKey, byte[] bytes, CacheSerializerHints cacheSerializerHints)
 {
     return(WriteCacheBytesAsync(cacheKey, bytes)); // default implementation avoids a breaking change.
 }