Introduction
I'm working on migrating a single-tenant, single-db ASP.NET Core Web API project that uses Azure AD with a DistributedSqlServerCache to support a multi-tenant, multi-db approach.
Our application will support Azure AD logins from multiple tenants, each tenant having their own database for better isolation.
This is documented well for Entity Framework Core, with code samples as well, but there isn't any clear information about having a multi-tenant, multi-db approach for the token cache. The official Multi tenant Azure AD documentation does mention the token caches, but it doesn't talk about a multi-db approach.
The problem
When you set up a token cache, you have to specify a connectionstring:
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = connectionString;
options.TableName = "DistributedCache";
options.SchemaName = "cache";
});
This code will be executed once, so I can't change the connectionstring to the tenant of the user who is executing the current request.
Does anyone know of a way to point the application to a different cache, depending on the current request/current user? As long as I would have access to the current IServiceProvider, I could grab the current HttpContext and find the Tenant and base my connectionstring on that, for example.
Given the comments about the core code creating a singleton of SqlServerCache, I've taken a new approach where we register it ourselves.
Now for every request we are setting up the cache. I have tested and this works but I'm not sure about performance implications of registering the service and building the ServiceProvider on every request. It's up to you how to implement the connection string decision, but this will enable you to make it.
First, create a delegate of type IDistributedCache:
Then in Startup add this delegate as a Transient service and set up the action to set the options and add the SqlServerCache as Transient:
Create a Cache provider class with an IDistributedCache which is resolved by our CacheResolver:
Register the provider:
Then simply inject ICustomCacheProvider where you need it.
Note that the discard in the callback is the serviceProvider parameter. Don't use this to get the SqlServerCache if you happened to register this outside the callback, for some reason it doesn't pick up the cacheConfigOptions set up in the callback.