NCache as an 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 having to get data from the disk again and again. The in-memory contents of the cache can then be periodically persisted to the disk, therefore drastically decreasing average time taken to get the 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:
Pre-Requisites
- Use .NET Core 3.1 SDK and runtimes for IdentityServer4.
- NCache Enterprise 5.0 SP1 or onwards should be running on your server(s).
- The cache name and IP address information has been changed according to your application.
- Cache must be running.
- To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
- 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 (Version 5.2) to your application:
Alachisoft.NCache.IdentityServer4
- Include the following namespaces in the StartupEFCore.cs file of your application.
IdentityServer4.NCache.Options
Step 2: In the cs 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
do not contain in the information regarding the cache cluster, then the ConnectionOptions
must be at least set with the information of at least one of the servers making up the NCache cluster. That information is provided 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 amount of time that 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
}
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 Servers 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.48,2.200.20.35",
"ConnectionStrings" : {
"db" : "server=;database=IdentityServer4.EntityFramework;UserId=userid;Password=password;"
}
}
Step 4: Run your applications IdentityServer
,MvcClient
,Api
,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. Make sure that the cache can be used as a configuration store and a persisted grant store cache is running and can be connected to the your IdentityServer
application.
Additional Resources
NCache provides sample application for IdentityServer4 at GitHub.
See Also
NCache as an in-memory IdentityServer4 Store
Cache Keys and Data Overview
Adding Data to Cache