Open Tazer opened 7 years ago
Pretty good question. I had to play with the default ASP.NET Core DI a little bit to figure that out.
First of all, you probably should not use transient instances and use singleton instead for CacheManager.
Then, in your code, t.GetType()
gives you the type of IServiceProvider
, that is what t
is. So that totally wouldn't work. In that overload, you do not get to the Type requested. And there is no overload to do so.
Instead what you can do, and what actually works pretty well:
BaseCacheManager<>
also as open generic var config = ...build cache configuartion...
/* add it to the services */
services.AddSingleton(config);
/* add the cache manager interface and impl type as open generics */
services.AddSingleton(typeof(ICacheManager<>), typeof(BaseCacheManager<>));
Later, in your controller for example, you can constructor inject a CacheManager instance
public ValuesController(ICacheManager<string> cache, ICacheManager<int> intCache)
{
this.cache = cache;
this.intCache = intCache;
}
Works fine! Let me know if you have any issues and, in general, this kind of questions are probably more suited for stackoverflow ;)
Is there an implementation of SystemRuntimeCaching that is compatible with dotnet core?
@frumkinwy No, System.Runtime.Caching doesn't exist anymore in dotnet core and you have to use something else if you want cross platform support.
You can use System.Runtime.Caching as long as you are targeting the full .NET Framework of course (new or old project system).
@MichaCo What about using Microsoft.Extensions.Caching.Memory
for memory caching in dotnet core?
(Nevermind, just found out there's CacheManager.Microsoft.Extensions.Caching.Memory
- isn't that cross platform or is it Windows specific?)
@raRaRa CacheManager.Microsoft.Extensions.Caching.Memory is cross platform (netstandard1.3), yup
@MichaCo , please, put the code from your sample to the documentation. I just spent several hours before reading this, trying to figure out how to use CacheFactory with open-generic registration in MicrosoftExtensions and/or Castle Windsor DI containers. I even tried to create a fork of the repo, moving typed parameter from class to method level :D
Can anyone please post sample code with .net core configuration ?
I did something like this
var cacheConfig = CacheManager.Core.ConfigurationBuilder.BuildConfiguration(settings =>
{
settings.WithSerializer(typeof(CacheManager.Serialization.Json.JsonCacheSerializer)).WithMicrosoftMemoryCacheHandle("in-memory").And.WithRedisConfiguration("redis", redisIpAddress)
.WithMaxRetries(1000)
.WithRetryTimeout(100)
.WithRedisBackplane("redis")
.WithRedisCacheHandle("redis", true);
});
services.AddSingleton<ICacheManager<SerieViewModel>>(t => CacheFactory.FromConfiguration<SerieViewModel>(cacheConfig));
services.AddSingleton<ICacheManager<TokenResponse>>(t => CacheFactory.FromConfiguration<TokenResponse>(cacheConfig));
services.AddSingleton<ICacheManager<string>>(t => CacheFactory.FromConfiguration<string>(cacheConfig));
It worked .. but very long time ago I touched the code :)
Thanks @Tazer for adding some examples ;)
Actually, if you install the CacheManager.Microsoft.Extensions.Configuration package, there are several extensions on IServiceCollection
which should help with that
You can inject one common configuration and then a open generic cache manager
services.AddCacheManagerConfiguration(...);
services.AddCacheManager();
and/or inject type specific cache manager instances with specific configurations
services.AddCacheManager<string>(c => c.WithDictionaryHandle());
You can use both methods together.
Hi Micha,
Thanks for the code snippet , it worked well.
Now we are using JSON file to define the cache manager config instead of doing it from code. I have few doubts:
If I have my own logger, should I use unknownLoggerFactory in json to specify that, any example for this please?
If I use json serializer, knownType= Json and I have some settings then how to specify them in json? var jsonSerializerSettings = new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects, ReferenceLoopHandling = ReferenceLoopHandling.Serialize };
// Serialization is only used by CacheManager for any distributed cache(out of proc), in-mem cache stores objects directly
builder.WithSerializer(typeof(JsonCacheSerializer), jsonSerializerSettings, jsonSerializerSettings);
Regards, Vani.
No, there is no support for configuring logging nor serialization via MS JSON configuration.
You can use a hybrid approach, load most configuration from JSON and then further configure logging and serialization. There is even an example in the docs
Hi Micha,
We want to use Redis cache through cache manager. I added cache.config find attached, I am getting error for Redis handle, I can perfectly use it for Dictionary handle
System.InvalidOperationException: No configuration added for configuration name cacheManager.Redis
I feel I am missing on some connection string to Redis. Could you give me some cache.json where Redis is being used. I downloaded your sample code which has cache.json sample, But that is not being loaded in sample code. I have created attached cache.json looking at the sample json only, please help me with this.
System.ArgumentNullException: Value cannot be null. Parameter name: key
at CacheManager.Core.BaseCacheManager1..ctor(String name, ICacheManagerConfiguration configuration) at CacheManager.Core.BaseCacheManager
1..ctor(ICacheManagerConfiguration configuration)
at CacheManager.Core.CacheFactory.FromConfiguration[TCacheValue](String cacheName, ICacheManagerConfiguration configuration)
at FIS.Risk.Core.Examples.ServiceFactory..ctor(IDependencyContainer container, IConfiguration config, ILogging log, ICacheManagerConfigurationFactory cacheManagerConfigurationFactory) in C:\Projects\fis-risk-core\src\Examples\ExampleHostCore\ServiceFactory.cs:line 63
at lambda_method(Closure , LifetimeContext , CompositionOperation )
at System.Composition.Hosting.Core.LifetimeContext.GetOrCreate(Int32 sharingId, CompositionOperation operation, CompositeActivator creator)
at System.Composition.Hosting.Providers.ImportMany.ImportManyExportDescriptorProvider.<>cDisplayClass3_21.<GetImportManyDescriptor>b__4(ExportDescriptor e) at System.Linq.Enumerable.SelectArrayIterator
2.ToArray()
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at lambda_method(Closure , LifetimeContext , CompositionOperation )
at System.Composition.TypedParts.ActivationFeatures.DisposalFeature.<>cDisplayClass0_0.2 registrationAccessor) in C:\Projects\fis-risk-core\src\Implementations\Autofac\RegistrationSource.cs:line 38 at Autofac.Core.Registration.ComponentRegistry.GetInitializedServiceInfo(Service service) at Autofac.Core.Registration.ComponentRegistry.TryGetRegistration(Service service, IComponentRegistration& registration) at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable
1 parameters, Object& instance)
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
at FIS.Risk.Core.Composition.Autofac.AutofacDependencyContainer.Resolve(Type type) in C:\Projects\fis-risk-core\src\Implementations\Autofac\AutofacDependencyContainer.cs:line 38
at FIS.Risk.Core.Composition.DependencyContainerExtensions.Resolve[T](IDependencyContainer container) in C:\Projects\fis-risk-core\src\Core\Composition\IDependencyContainer.cs:line 81
at FIS.Risk.Core.Examples.Program.<>c.1 buildContainer, Func
2 resolveRoot, Action`1 run) in C:\Projects\fis-risk-core\src\Hosting\StartupManager.cs:line 81
Regards, Vani.
From: MichaC [mailto:notifications@github.com] Sent: 17 October 2018 13:25 To: MichaCo/CacheManager CacheManager@noreply.github.com Cc: Kulkarni, Vani Vani.Kulkarni@fisglobal.com; Comment comment@noreply.github.com Subject: Re: [MichaCo/CacheManager] ASP.NET Core DI Register CacheManager (#94)
No, there is no support for configuring logging nor serialization via MS JSON configuration.
You can use a hybrid approach, load most configuration from JSON and then further configure logging and serialization. There is even an example in the docshttps://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fcachemanager.michaco.net%2Fdocumentation%2FCacheManagerConfiguration%23loading-configuration-from-json-file&data=02%7C01%7Cvani.kulkarni%40fisglobal.com%7C8b87aa5febd54c5c572d08d63405e579%7Ce3ff91d834c84b15a0b418910a6ac575%7C0%7C0%7C636753597310886167&sdata=8rQrjfjAYG239a5nAT%2BzAz068vdL8fXfjWkCgQfibYQ%3D&reserved=0
— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FMichaCo%2FCacheManager%2Fissues%2F94%23issuecomment-430527800&data=02%7C01%7Cvani.kulkarni%40fisglobal.com%7C8b87aa5febd54c5c572d08d63405e579%7Ce3ff91d834c84b15a0b418910a6ac575%7C0%7C0%7C636753597310886167&sdata=1PnbTxbgDaJMxiFAMTy5mBupNPZQL0Jr20J5jLZsSd4%3D&reserved=0, or mute the threadhttps://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fnotifications%2Funsubscribe-auth%2FAluDJ3-qS1FK5bbJIq9KJMoNcac0KKr6ks5uluJqgaJpZM4J-2ia&data=02%7C01%7Cvani.kulkarni%40fisglobal.com%7C8b87aa5febd54c5c572d08d63405e579%7Ce3ff91d834c84b15a0b418910a6ac575%7C0%7C0%7C636753597310886167&sdata=KAVYQ4uZt%2FnhcsBZbPM2c%2BWWy7KmYS%2BeU%2FMiDFslInM%3D&reserved=0.
The information contained in this message is proprietary and/or confidential. If you are not the intended recipient, please: (i) delete the message and all copies; (ii) do not disclose, distribute or use the message in any manner; and (iii) notify the sender immediately. In addition, please be aware that any message addressed to our domain is subject to archiving and review by persons other than the intended recipient. Thank you.
Hi Micha,
I don’t want to use Redis as backplane. We are not using multi layered caching.
I could find app.config files in sample using Redis. I want simple cache.config that uses Redis cache. Could you please share one or point me there ?
Regards, Vani.
From: Kulkarni, Vani Sent: 22 October 2018 11:05 To: 'MichaCo/CacheManager' reply@reply.github.com; MichaCo/CacheManager CacheManager@noreply.github.com Cc: Comment comment@noreply.github.com Subject: RE: [MichaCo/CacheManager] ASP.NET Core DI Register CacheManager (#94)
Hi Micha,
We want to use Redis cache through cache manager. I added cache.config find attached, I am getting error for Redis handle, I can perfectly use it for Dictionary handle
System.InvalidOperationException: No configuration added for configuration name cacheManager.Redis
I feel I am missing on some connection string to Redis. Could you give me some cache.json where Redis is being used. I downloaded your sample code which has cache.json sample, But that is not being loaded in sample code. I have created attached cache.json looking at the sample json only, please help me with this.
System.ArgumentNullException: Value cannot be null. Parameter name: key
at CacheManager.Core.BaseCacheManager1..ctor(String name, ICacheManagerConfiguration configuration) at CacheManager.Core.BaseCacheManager
1..ctor(ICacheManagerConfiguration configuration)
at CacheManager.Core.CacheFactory.FromConfiguration[TCacheValue](String cacheName, ICacheManagerConfiguration configuration)
at FIS.Risk.Core.Examples.ServiceFactory..ctor(IDependencyContainer container, IConfiguration config, ILogging log, ICacheManagerConfigurationFactory cacheManagerConfigurationFactory) in C:\Projects\fis-risk-core\src\Examples\ExampleHostCore\ServiceFactory.cs:line 63
at lambda_method(Closure , LifetimeContext , CompositionOperation )
at System.Composition.Hosting.Core.LifetimeContext.GetOrCreate(Int32 sharingId, CompositionOperation operation, CompositeActivator creator)
at System.Composition.Hosting.Providers.ImportMany.ImportManyExportDescriptorProvider.<>cDisplayClass3_21.<GetImportManyDescriptor>b__4(ExportDescriptor e) at System.Linq.Enumerable.SelectArrayIterator
2.ToArray()
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at lambda_method(Closure , LifetimeContext , CompositionOperation )
at System.Composition.TypedParts.ActivationFeatures.DisposalFeature.<>cDisplayClass0_0.2 registrationAccessor) in C:\Projects\fis-risk-core\src\Implementations\Autofac\RegistrationSource.cs:line 38 at Autofac.Core.Registration.ComponentRegistry.GetInitializedServiceInfo(Service service) at Autofac.Core.Registration.ComponentRegistry.TryGetRegistration(Service service, IComponentRegistration& registration) at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable
1 parameters, Object& instance)
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
at FIS.Risk.Core.Composition.Autofac.AutofacDependencyContainer.Resolve(Type type) in C:\Projects\fis-risk-core\src\Implementations\Autofac\AutofacDependencyContainer.cs:line 38
at FIS.Risk.Core.Composition.DependencyContainerExtensions.Resolve[T](IDependencyContainer container) in C:\Projects\fis-risk-core\src\Core\Composition\IDependencyContainer.cs:line 81
at FIS.Risk.Core.Examples.Program.<>c.1 buildContainer, Func
2 resolveRoot, Action`1 run) in C:\Projects\fis-risk-core\src\Hosting\StartupManager.cs:line 81
Regards, Vani.
From: MichaC [mailto:notifications@github.com] Sent: 17 October 2018 13:25 To: MichaCo/CacheManager CacheManager@noreply.github.com<mailto:CacheManager@noreply.github.com> Cc: Kulkarni, Vani Vani.Kulkarni@fisglobal.com<mailto:Vani.Kulkarni@fisglobal.com>; Comment comment@noreply.github.com<mailto:comment@noreply.github.com> Subject: Re: [MichaCo/CacheManager] ASP.NET Core DI Register CacheManager (#94)
No, there is no support for configuring logging nor serialization via MS JSON configuration.
You can use a hybrid approach, load most configuration from JSON and then further configure logging and serialization. There is even an example in the docshttps://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fcachemanager.michaco.net%2Fdocumentation%2FCacheManagerConfiguration%23loading-configuration-from-json-file&data=02%7C01%7Cvani.kulkarni%40fisglobal.com%7C8b87aa5febd54c5c572d08d63405e579%7Ce3ff91d834c84b15a0b418910a6ac575%7C0%7C0%7C636753597310886167&sdata=8rQrjfjAYG239a5nAT%2BzAz068vdL8fXfjWkCgQfibYQ%3D&reserved=0
— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2FMichaCo%2FCacheManager%2Fissues%2F94%23issuecomment-430527800&data=02%7C01%7Cvani.kulkarni%40fisglobal.com%7C8b87aa5febd54c5c572d08d63405e579%7Ce3ff91d834c84b15a0b418910a6ac575%7C0%7C0%7C636753597310886167&sdata=1PnbTxbgDaJMxiFAMTy5mBupNPZQL0Jr20J5jLZsSd4%3D&reserved=0, or mute the threadhttps://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fnotifications%2Funsubscribe-auth%2FAluDJ3-qS1FK5bbJIq9KJMoNcac0KKr6ks5uluJqgaJpZM4J-2ia&data=02%7C01%7Cvani.kulkarni%40fisglobal.com%7C8b87aa5febd54c5c572d08d63405e579%7Ce3ff91d834c84b15a0b418910a6ac575%7C0%7C0%7C636753597310886167&sdata=KAVYQ4uZt%2FnhcsBZbPM2c%2BWWy7KmYS%2BeU%2FMiDFslInM%3D&reserved=0.
The information contained in this message is proprietary and/or confidential. If you are not the intended recipient, please: (i) delete the message and all copies; (ii) do not disclose, distribute or use the message in any manner; and (iii) notify the sender immediately. In addition, please be aware that any message addressed to our domain is subject to archiving and review by persons other than the intended recipient. Thank you.
@vanikulkarniAtFIS I'd appreciate if you could clean up the comments. Pretty hard to read.
Didn't really get what you are looking for, a json configuration example for Redis? Something like this? http://cachemanager.michaco.net/documentation/CacheManagerConfiguration#json-schema
Hi @MichaCo ,
Could you recommend any kind of generic
public ValuesController(ICacheManager
Moreover, I would like to have the ability to use in a single controller one CacheManager configured to work with dictionary/in-memory cache and another CacheManager configured to work with a Redis cache.
As a result, I would like to get something like:
public ValuesController(IDictionaryCacheManager dictionaryCache, IRedisCacheManager redisCache) { this.dictionaryCache= dictionaryCache; this.redisCache= redisCache; }
Looks like services.AddSingleton(typeof(ICacheManager<>), typeof(BaseCacheManager<>)); does not work for me. What would you recommend?
@vvadyak
Yes, the generic injection (ICacheManager<>), typeof(BaseCacheManager<>))
only works for one configuration. That's basically the most convenient way to configure many caches if you want to keep those caches separated from each other (not sharing keys across cached types.)
The extension on IServiceCollection
coming with CacheManager to set that up is
services.AddCacheManager();
That requires a configuration to be injected, so you also have to in setup one via services.AddCacheManagerConfiguration
which can use the standard configurations extensions to load cache manager configuration from file, or you can manually define a config...
Then, you can inject more specific configurations per type if some of your caches have a different config.
For example, to configure a slightly different cache for int
you can call
services.AddCacheManager<int>(Configuration, configure: builder => builder...);
This will basically overrule the open generic injection.
That being said, as you already figured out, there is no build in way to configure a cache for the same type, e.g. object
with different kinds of caches / different configurations.
The DI framework doesn't really allow us to inject named singleton instances. One way to do that though is by injecting distinct types to identify the different kinds of caches. You could wrap the ICacheManager interface with something you then can inject to get a certain cache back.
Let's say I want an in-memory and a distributed cache for the same type string
.
I'd define an interface per type of cache which extends ICacheManager
public interface IDistributedCacheManager<TType> : ICacheManager<TType>
{
}
public interface ILocalCacheManager<TType> : ICacheManager<TType>
{
}
Then, I need an implementation which I can inject for those interfaces, that's pretty simple, I can just extend BaseCacheManager
private class CacheManagerWrapper<TType> : BaseCacheManager<TType>, IDistributedCacheManager<TType>, ILocalCacheManager<TType>
{
public CacheManagerWrapper(ICacheManagerConfiguration configuration) : base(configuration)
{
}
}
And with that, I can inject different instances of CacheManager for different purposes:
services.AddSingleton<IDistributedCacheManager<string>>(p =>
{
//// Get already injected configuration and modify it further
// var config = p.GetRequiredService<ICacheManagerConfiguration>();
// config.Builder
// ....
// Or load some configuration from the configuration system (or you'd just create a new configuration from scratch...)
var config = Configuration.GetCacheConfiguration("distributed");
return new CacheManagerWrapper<string>(config);
});
services.AddSingleton<ILocalCacheManager<string>>(p =>
{
var config = Configuration.GetCacheConfiguration("inMemory");
return new CacheManagerWrapper<string>(config);
});
The wrapper can be totally hidden and isn't visible to any usage.
To use those different kinds of caches, you'd inject your custom interfaces in a controller or manager, instead of ICacheManager<T>
!
I was thinking of adding something like that to the library, but I'm not sure that really makes any sense. Its just like 5 lines of code anyways to implement it and I don't really know what kind of use cases other users might have, meaning, it doesn't make sense to add random named interfaces to the library for any kind of use case...
Hope that helps
In your case, with many different types, I guess it makes most sense to use object
for T
in ICacheManager<T>
. Otherwise, you have to inject so many different types to your controllers and such and that gets very ugly very quickly.
That being said, you have to be sure that this will work for your app. If you use one cache instance for all your types, you cannot have the same cache key for 2 different objects...
I'm still trying to figure out a better way to inject one type, a factory, which then gen be used to .Get
a cache instance via name and/or type.
The problem is that this use case isn't really supported by the DI framework. The Extensions.Options package did something custom to support named options for example but it gets pretty complicated...
Hello,
I have tried to find some good examples of registering CacheManager in ASP.NET Core with DI. Is there any examples of this , cause I couldn't really get it working with the "Built-In" DI. So wanted to ask if I'm missing something or do a need to use StrucutureMap, To be able to register CacheManager Generic?
This is the non-working code I wrote:
That throws an error
Open generic service type '{typeof(IEnumerable<>)}' requires registering an open generic implementation type.