In-Memory IdentityServer4 Cache Implementation
NCache, on its own, can be used as a configuration and persistent grant store to further increase performance by removing the impediment of repeatedly getting data from the disk. The in-memory cache contents of the cache can periodically persist on the disk. Therefore, drastically decreasing the average time taken to get data.
NCache's core functionality is to cache data persisting in your data source for faster access and better performance. While you can use NCache as your data store, you can also use NCache between your data store and the application by caching the configuration and/or the operational data in NCache.
Now let's figure out from the diagram how NCache works as a cache with IdentityServer4:
Prerequisites
- Use .NET 4.8 SDK and runtime API for IdentityServer4.
- The cache name and IP address information should change according to your application.
- The cache must be running.
- To handle any unseen exceptions, refer to the Troubleshooting section.
In order to use NCache for the IdentityServer4 configuration and operational data, configurations need to be done as explained in detail below.
How to Configure NCache as IdentityServer4 Cache Implementation
Step 1:
- Install the following NuGet package to your application:
- Include the following namespaces in the StartupEFCore.cs file of your application.
IdentityServer4.NCache.Options
Step 2:
In the .cs file of your project, add the .UseStartup<StartupEFCore>
method. Then for NCache as both a configuration and operational store, add the following code where CacheId
is the name of your cache and Servers
are the IP addresses of your nodes in the StartupEFCore.cs file.
Warning
If the client.ncconf file in the project folder or your installation directory, i.e., %NCHOME%\config
does not contain the information regarding the cache cluster, then the ConnectionOptions
must contain the information of at least one server in the NCache cluster. That information is available within the ServerList
property of the NCacheConnectionOptions
class.
Note
- In case of any network-related issues preventing the use of NCache as a caching layer and for the application to proceed by accessing the data from the underlying database, circuit breaker pattern implementation has been incorporated by
ICache<T>
implementation. DurationOfBreakInSeconds
determines the time the circuit breaker will stay in the Open state before transitioning to the Half Open state. The default value is 30.
public void ConfigureServices(IServiceCollection services)
{
...
var builder = services.AddIdentityServer()
.AddTestUsers(TestUsers.Users)
// Add NCache as a configuration store
.AddNCacheCaching(options =>
{
options.CacheId = _configuration["CacheId"];
var serverList = _configuration["Servers"].Split(',')
.Select(x => x.Trim())
.ToList()
.Select(y =>
new NCacheServerInfo(y, 9800))
.ToList();
options.ConnectionOptions = new NCacheConnectionOptions
{
ServerList = serverList
};
options.DurationOfBreakInSeconds = 120;
})
// Add NCache as a persisted operational grant store
.AddClientStoreCache<ClientStore>()
.AddResourceStoreCache<ResourceStore>()
.AddNCacheCorsPolicyCache<CorsPolicyService>()
.AddNCachePersistedGrantStoreCache<PersistedGrantStore>(options =>
{
options.CacheId = _configuration["CacheId"];
var serverList = _configuration["Servers"].Split(',')
.Select(x => x.Trim())
.ToList()
.Select(y =>
new NCacheServerInfo(y, 9800))
.ToList();
options.ConnectionOptions = new NCacheConnectionOptions
{
ServerList = serverList
};
options.DurationOfBreakInSeconds = 120;
})
// NCache as an IProfileService default implementation
.AddNCacheProfileServiceCache<TestUserProfileService>(options =>
{
options.Expiration = TimeSpan.FromMinutes(10);
options.KeyPrefix = "NCache-";
options.KeySelector = (context) => context.Subject.Claims.First
(_=> _.Type == "sub").Value;
options.ShouldCache = (context) => true;
});
// Rest of the code
}
Note
To ensure the operation is fail-safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
Important
The application will generate the database and all relevant tables using EF Core migrations through your defined connection string. Do not create the database beforehand.
Step 3:
After that, in the appsettings.json file, modify the value of the CacheId
key to the name of the cache you are using. Furthermore, for the multiple server keys, use a comma-separated list of one or more IP addresses belonging to the NCache servers making up the NCache cluster. Also, provide the connection string of the SQL Server.
{
"CacheId" : "demoCache",
"Servers" : "20.200.20.40,20.200.20.39",
"ConnectionStrings" : {
"db" : "server=;database=IdentityServer4.EntityFramework;UserId=userid;Password=password;"
}
}
Step 4:
Run your applications IdentityServer
, MvcClient
, Api
, and JavaScriptClient
to see how NCache operates as a caching mechanism for the configuration store, the persisted grant store as well as the IProfileService default implementation. Ensure the cache is useable as a configuration store and a persisted grant store cache is running and can connect to your IdentityServer
application.
Additional Resources
NCache provides a sample application for IdentityServer4 on GitHub.
See Also
.NET: IdentityServer4 namespace.