-
Notifications
You must be signed in to change notification settings - Fork 102
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] Add ability to set cache key prefix separately from cache name #300
Comments
Hi @casperOne
It's already like that, the 2 are not forced to be linked. If, when building the cache, you use By NOT doing it, there will be no automatic cache key prefix, and you'll need to build the cache key yourself, however you want. Try it and let me know if you have any problem. Hope this helps. |
Also:
You can use Hope this helps. |
@jodydonetti Thanks for the response, but I think I'm not communicating my scenario accurately enough. Say I have a web app, entry point is an assembly: Application.Web.EntryPoint There's also a logic assembly. In an ideal world, this assembly is agnostic to hosting, it could be a web container, a windows service, desktop, etc. Additionally, many of the interfaces have a single implementation, and we place the registration code near the interface and implementation so that everything around that specific functionality is colocated as much as possible. Let's say this assembly is called: Application.Core In that assembly, we will have a structure like this:
The top-level ServiceCollectionExtensions.cs looks like this: public static IServiceCollection AddCore(
this IServiceCollection serviceCollection
)
{
// For ease-of-use.
var sc = serviceCollection;
// Call sub folders for registration.
sc = sc.AddFibonaciSequence();
// Return the service collection.
return sc;
} Say Let's also say that currently, UAT and TEST environments share the same redis instance we want to use for backplaning. In order to do that, my public static IServiceCollection AddFibonaciSequence(
this IServiceCollection serviceCollection
)
{
// For ease-of-use.
var sc = serviceCollection;
// Add the cache.
sc
// Calling this overload becomes somewhat irrelevant
// given the next line
.AddFusionCache(CacheName)
// The environment, which is a hosting concern, has bled in
.WithCacheKeyPrefix($"{environment}:{CacheName}:")
// All of these are delegated to the host's definition
// as how serialization, distributed caching and backplane
// are not specific to the core logic's concern.
.WithRegisteredSerializer()
.WithRegisteredDistributedCache()
.WithRegisteredBackplane()
// This is tied specifically to *this* cache, which is a
// concern of *this* component.
.WithDefaultEntryOptions(o => {
// Reference data *rarely* changes
// One day is fine and there will
// be a backplane on top of that.
o.Duration = TimeSpan.FromDays(1);
});
// Return the service collection.
return sc;
} The comments paint the picture, basically, we are bleeding hosting concerns (the environment) into the core logic. Fusion Cache already opens the door to this separation through the Ideally, in the hosting DLL, we set up the specific distributed cache, backplane, etc. as well as how to handle concerns around prefixing cache keys due to environment. In the core DLL, there may be additional concerns around key generation, but those concerns are for the purpose of discriminating between different business/logic concerns, not hosting concerns. Right now, I have to thread environment to every single cache (and I plan on having a bunch) which makes for a very leaky abstraction, IMO, as public static IServiceCollection AddCore(
this IServiceCollection serviceCollection
, string environment
)
{
// For ease-of-use.
var sc = serviceCollection;
// Call sub folders for registration.
sc = sc.AddFibonaciSequence(environment);
// New caches, nested deeply? Have to thread enviromment
// to all of them.
// Return the service collection.
return sc;
} I could have probably said "this is the same as property drilling in React" as well to explain all this 🤣 |
Hi @casperOne , sorry for the delay. I think I had already understood your scenario, you've been clear enough and maybe it was me who was not able to clearly articulate my thoughts 🙂 I think the main issue may revolve around the name of the Let me explain. When you think about it, the fact that each cache needs a prefix is a concern of the cache itself, so it is correct that the param is there, meaning that it cannot be hidden away. The cache is registered via the The host app on the other hand is responsible to register the services (via the In a way is the same when in a common web app you register some core aspnet service that requires some configuration, usually via options (see The Maybe using the options pattern it can even become clearer. Let me know what you think. |
Hello, to chip in on this we're currently configuring our CacheKeyPrefix in our tests to ensure that our tests do not interfere with eachother without having to use a separate redis instance for each test. // Program.cs
builder.Services.AddFusionCache()
.WithDistributedCache(_ => new RedisCache(...))
.WithBackplane(_ => ...); public class MyTest : IClassFixture<WebApplicationFactory<Program>>
{
private readonly WebApplicationFactory<Program> _factory;
public MyTest(WebApplicationFactory<Program> factory)
{
_factory.WithWebHostBuilder(builder =>
builder.ConfigureTestServices(services =>
{
services.Configure(
FusionCacheOptions.DefaultCacheName,
opts =>
{
opts.CacheKeyPrefix = $"MyTest:{Guid.NewGuid()}:";
});
})
);
}
[Fact]
public async Task SomeTest()
{
using var client = _factory.CreateClient();
// Test stuff here
}
} I assume you could do something similar to this in your code to achieve this? services.ConfigureAll<FusionCacheOptions>(opts => opts.CacheKeyPrefix = $"{environment}:{opts.CacheName}:"); I assume this is what @jodydonetti is alluding to in his comment about using the options pattern. |
Problem
In my apps (and I would think others), I may be using a shared server for distributed caching across multiple environments.
I may also be using named caches.
In order to generate keys that don't conflict, I would need to have a compound key prefix, something like:
However, when performing dependency injection, there are some things that are the concern of the host, and some that are the concern of the core logic.
In this case, the environment is a concern of the host, while the cache name is a concern of the logic.
If I am using dependency injection, I prefer to keep registration of services related to my core logic in an assembly separate from the host assembly, while keeping host registration concerns in the hosting assembly.
Currently, I have no way of setting both a cache name and a cache key prefix in separate areas of the code.
Solution
Separate out cache name and cache key prefix, such that when keys are generated, it does the composition at key generation time.
Currently, if the cache name is set, it simply sets the cache key prefix. These should be separate until key generation time.
Alternatives
I will stream environment details through to my DI in my core logic assembly.
The text was updated successfully, but these errors were encountered: