-
Notifications
You must be signed in to change notification settings - Fork 219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature Request] Replace the memory cache and distributed cache implementation with .NET9's Hybrid Cache #3153
Labels
Comments
bgavrilMS
added
enhancement
New feature or request
feature request
untriaged
needs attention
token cache serialization - distributed cache
token cache serialization - in memory cache
and removed
untriaged
needs attention
labels
Nov 19, 2024
Would recommend adding a new class Developer experience today: public void ConfigureServices(IServiceCollection services)
{
services.AddDistributedMemoryCache(); // or any other distributed cache service
services.Configure<MsalDistributedTokenCacheAdapterOptions>(options =>
{
options.DisableL1Cache = false; // Configure as per your requirements
options.L1ExpirationTimeRatio = 0.5;
options.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30); // Example setting
});
services.AddSingleton<IMsalTokenCacheProvider, MsalDistributedTokenCacheAdapter>();
// Other service configurations
} Proposal: public void ConfigureServices(IServiceCollection services)
{
services.AddHybridCache(); // Add HybridCache service
services.Configure<HybridCacheOptions>(options =>
{
options.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30); // Example setting
options.SizeLimit = 500 * 1024 * 1024; // 500MB
});
services.AddSingleton<IMsalTokenCacheProvider, MsalHybridTokenCacheProvider>();
// Other service configurations
} Example: public class MsalHybridTokenCacheProvider : MsalAbstractTokenCacheProvider
{
private readonly IHybridCache _hybridCache;
private readonly HybridCacheOptions _cacheOptions;
public MsalHybridTokenCacheProvider(
IHybridCache hybridCache,
IOptions<HybridCacheOptions> cacheOptions)
{
_ = Throws.IfNull(cacheOptions);
_hybridCache = hybridCache;
_cacheOptions = cacheOptions.Value;
}
protected override Task RemoveKeyAsync(string cacheKey)
{
_hybridCache.Remove(cacheKey);
return Task.CompletedTask;
}
protected override Task<byte[]?> ReadCacheBytesAsync(string cacheKey)
{
byte[]? tokenCacheBytes = (byte[]?)_hybridCache.Get(cacheKey);
return Task.FromResult(tokenCacheBytes);
}
protected override Task WriteCacheBytesAsync(string cacheKey, byte[] bytes, CacheSerializerHints cacheSerializerHints)
{
HybridCacheEntryOptions hybridCacheEntryOptions = new HybridCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = DetermineCacheEntryExpiry(cacheSerializerHints),
Size = bytes?.Length
};
_hybridCache.Set(cacheKey, bytes, hybridCacheEntryOptions);
return Task.CompletedTask;
}
internal TimeSpan DetermineCacheEntryExpiry(CacheSerializerHints cacheSerializerHints)
{
TimeSpan? cacheExpiry = null;
if (cacheSerializerHints != null && cacheSerializerHints.SuggestedCacheExpiry != null)
{
cacheExpiry = cacheSerializerHints.SuggestedCacheExpiry.Value.UtcDateTime - DateTime.UtcNow;
if (cacheExpiry < TimeSpan.Zero)
{
cacheExpiry = TimeSpan.FromMilliseconds(1);
}
}
return cacheExpiry is null || _cacheOptions.AbsoluteExpirationRelativeToNow < cacheExpiry
? _cacheOptions.AbsoluteExpirationRelativeToNow
: cacheExpiry.Value;
}
} Possible test coverage: using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
using Moq;
using Xunit;
namespace Microsoft.Identity.Web.Test.TokenCacheProviders.Hybrid
{
public class MsalHybridTokenCacheProviderTests
{
private readonly Mock<IHybridCache> _hybridCacheMock;
private readonly MsalHybridTokenCacheProvider _tokenCacheProvider;
public MsalHybridTokenCacheProviderTests()
{
_hybridCacheMock = new Mock<IHybridCache>();
var options = Options.Create(new HybridCacheOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30),
SizeLimit = 500 * 1024 * 1024
});
_tokenCacheProvider = new MsalHybridTokenCacheProvider(_hybridCacheMock.Object, options);
}
[Fact]
public async Task RemoveKeyAsync_RemovesKeyFromCache()
{
// Arrange
var cacheKey = "test_key";
// Act
await _tokenCacheProvider.RemoveKeyAsync(cacheKey);
// Assert
_hybridCacheMock.Verify(cache => cache.Remove(cacheKey), Times.Once);
}
[Fact]
public async Task ReadCacheBytesAsync_ReturnsCachedBytes()
{
// Arrange
var cacheKey = "test_key";
var expectedBytes = new byte[] { 1, 2, 3 };
_hybridCacheMock.Setup(cache => cache.Get(cacheKey)).Returns(expectedBytes);
// Act
var result = await _tokenCacheProvider.ReadCacheBytesAsync(cacheKey);
// Assert
Assert.Equal(expectedBytes, result);
}
[Fact]
public async Task WriteCacheBytesAsync_WritesBytesToCache()
{
// Arrange
var cacheKey = "test_key";
var bytes = new byte[] { 1, 2, 3 };
var hints = new CacheSerializerHints();
// Act
await _tokenCacheProvider.WriteCacheBytesAsync(cacheKey, bytes, hints);
// Assert
_hybridCacheMock.Verify(cache => cache.Set(
cacheKey,
bytes,
It.Is<HybridCacheEntryOptions>(options =>
options.AbsoluteExpirationRelativeToNow == TimeSpan.FromMinutes(30) &&
options.Size == bytes.Length)),
Times.Once);
}
}
} |
related issue #3160 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
[Is your feature request related to a problem? Please describe.
.NET team provides a new library called HybridCache, which by default uses MemoryCache, but can optionally also be configured with a DistributedCache
https://learn.microsoft.com/en-us/aspnet/core/performance/caching/hybrid?view=aspnetcore-9.0
This library works on netstandard2.0 and net722
Describe the solution you'd like
Update the MemoryTokenCache and DistributedTokenCache implementation to use a HybridCache.
The text was updated successfully, but these errors were encountered: