@@ -61,80 +61,126 @@ public static void AddSimpleCache(this IServiceCollection services, IConfigurati
6161 /// <param name="configuration">Configuration</param>
6262 public static void AddSimpleCache ( this IServiceCollection services , SimpleCacheConfiguration configuration )
6363 {
64- // assign configuration defaults
6564 SetConfigurationDefaults ( configuration ) ;
65+ var layerCacheOptions = AddLayerCacheOptions ( services , configuration ) ;
66+ AddSystemClock ( services ) ;
67+ AddMemoryCache ( services , configuration ) ;
68+ AddFileCache ( services , configuration ) ;
69+ AddDistributedCache ( services , configuration , layerCacheOptions ) ;
70+ services . AddSingleton < ISerializer > ( configuration . SerializerObject ) ;
71+ services . AddSingleton < IDiskSpace , DiskSpace > ( ) ;
72+ services . AddSingleton < ILayeredCache , LayeredCache > ( ) ;
73+ }
74+
75+ private static void SetConfigurationDefaults ( SimpleCacheConfiguration configuration )
76+ {
77+ if ( ! string . IsNullOrWhiteSpace ( configuration . SerializerType ) )
78+ {
79+ var serializerType = Type . GetType ( configuration . SerializerType ) ??
80+ throw new ArgumentException ( "Invalid serializer type " + configuration . SerializerType ) ;
81+ var serializer = Activator . CreateInstance ( serializerType ) ;
82+ if ( serializer is ISerializer serializerInterface )
83+ {
84+ configuration . SerializerObject = serializerInterface ;
85+ }
86+ else
87+ {
88+ throw new ArgumentException ( "Failed to detect serializer interface from type " + configuration . SerializerType ) ;
89+ }
90+ }
91+ configuration . SerializerObject ??= new JsonLZ4Serializer ( ) ;
92+ }
6693
94+ private static LayeredCacheOptions AddLayerCacheOptions ( IServiceCollection services , SimpleCacheConfiguration configuration )
95+ {
6796 // add layer cache options
6897 var layerCacheOptions = new LayeredCacheOptions
6998 {
7099 KeyPrefix = configuration . KeyPrefix
71100 } ;
72101 services . AddSingleton ( layerCacheOptions ) ;
102+ return layerCacheOptions ;
103+ }
73104
74- // add file cache options
75- var fileOptions = new FileCacheOptions
76- {
77- CacheDirectory = configuration . FileCacheDirectory ,
78- FreeSpaceThreshold = configuration . FileCacheFreeSpaceThreshold
79- } ;
80- services . AddSingleton ( fileOptions ) ;
81-
82- // add redis cache options
83- var redisOptions = new DistributedRedisCacheOptions
84- {
85- KeyPrefix = layerCacheOptions . KeyPrefix
86- } ;
87- services . AddSingleton ( redisOptions ) ;
88-
89- // a little hacky because of poor api design around AddStackExchangeRedisCache not exposing IServiceProvider
90- Resolver resolver = new ( ) ;
91- services . AddSingleton ( resolver ) ;
92- services . AddHostedService < SimpleCacheHelperService > ( ) ; // transfers IServiceProvider to resolver
93-
94- // setup stackexchange redis
95- var stackExchangeRedisOptions = ConfigurationOptions . Parse ( configuration . RedisConnectionString ) ;
96- stackExchangeRedisOptions . AbortOnConnectFail = false ; // can connect later if initial connection fails
97-
105+ private static void AddSystemClock ( IServiceCollection services )
106+ {
98107 // add our own system clock
99108 services . AddSingleton < ClockHandler > ( ) ;
100109 services . AddSingleton < IClockHandler > ( provider => provider . GetRequiredService < ClockHandler > ( ) ) ;
101110 services . Replace ( new ServiceDescriptor ( typeof ( ISystemClock ) , provider => provider . GetRequiredService < ClockHandler > ( ) , ServiceLifetime . Singleton ) ) ;
111+ }
102112
103- // add stack exchange redis
104- services . AddSingleton < IConnectionMultiplexer > ( provider =>
113+ private static void AddDistributedCache ( IServiceCollection services ,
114+ SimpleCacheConfiguration configuration ,
115+ LayeredCacheOptions layerCacheOptions )
116+ {
117+ if ( string . IsNullOrWhiteSpace ( configuration . RedisConnectionString ) )
105118 {
106- try
119+ // add null distributed cache
120+ services . AddSingleton < IDistributedCache > ( new NullDistributedCache ( ) ) ;
121+ }
122+ else
123+ {
124+ // add redis cache options
125+ var redisOptions = new DistributedRedisCacheOptions
126+ {
127+ KeyPrefix = layerCacheOptions . KeyPrefix
128+ } ;
129+ services . AddSingleton ( redisOptions ) ;
130+
131+ // a little hacky because of poor api design around AddStackExchangeRedisCache not exposing IServiceProvider
132+ Resolver resolver = new ( ) ;
133+ services . AddSingleton ( resolver ) ;
134+ services . AddHostedService < SimpleCacheHelperService > ( ) ; // transfers IServiceProvider to resolver
135+
136+ // setup stackexchange redis
137+ var stackExchangeRedisOptions = ConfigurationOptions . Parse ( configuration . RedisConnectionString ) ;
138+ stackExchangeRedisOptions . AbortOnConnectFail = false ; // can connect later if initial connection fails
139+ services . AddSingleton < IConnectionMultiplexer > ( provider =>
107140 {
108- stackExchangeRedisOptions . AllowAdmin = true ;
109- using var admin = ConnectionMultiplexer . Connect ( stackExchangeRedisOptions ) ;
110- var existing = admin . GetServer ( admin . GetEndPoints ( ) . Single ( ) ) . ConfigGet ( "notify-keyspace-events" ) ;
111- if ( existing is null ||
112- existing . Length == 0 ||
113- ! existing . Any ( kv =>
141+ try
142+ {
143+ stackExchangeRedisOptions . AllowAdmin = true ;
144+ using var admin = ConnectionMultiplexer . Connect ( stackExchangeRedisOptions ) ;
145+ var existing = admin . GetServer ( admin . GetEndPoints ( ) . Single ( ) ) . ConfigGet ( "notify-keyspace-events" ) ;
146+ if ( existing is null ||
147+ existing . Length == 0 ||
148+ ! existing . Any ( kv =>
149+ {
150+ // this seems to be a random order
151+ var v = kv . Value ?? string . Empty ;
152+ return v . Contains ( 'K' , StringComparison . OrdinalIgnoreCase ) &&
153+ v . Contains ( 'E' , StringComparison . OrdinalIgnoreCase ) &&
154+ v . Contains ( 'A' , StringComparison . OrdinalIgnoreCase ) ;
155+ } ) )
114156 {
115- var v = kv . Value ?? string . Empty ;
116- return v . Contains ( 'K' , StringComparison . OrdinalIgnoreCase ) &&
117- v . Contains ( 'E' , StringComparison . OrdinalIgnoreCase ) &&
118- v . Contains ( 'A' , StringComparison . OrdinalIgnoreCase ) ;
119- } ) )
157+ admin . GetServer ( admin . GetEndPoints ( ) . Single ( ) ) . ConfigSet ( "notify-keyspace-events" , "KEA" ) ;
158+ }
159+ }
160+ catch
120161 {
121- admin . GetServer ( admin . GetEndPoints ( ) . Single ( ) ) . ConfigSet ( "notify-keyspace-events" , "KEA" ) ;
162+ var logger = provider . GetRequiredService < ILogger < DistributedRedisCache > > ( ) ;
163+ const string keySpaceCommand = "CONFIG SET notify-keyspace-events KEA" ;
164+ logger . LogError ( $ "Connection multiplexer has failed to enable key space events, you must manually run this command on your redis servers: '{ keySpaceCommand } '") ;
122165 }
123- }
124- catch
166+ stackExchangeRedisOptions . AllowAdmin = false ;
167+ return ConnectionMultiplexer . Connect ( stackExchangeRedisOptions ) ;
168+ } ) ;
169+ services . AddStackExchangeRedisCache ( cfg =>
125170 {
126- var logger = provider . GetRequiredService < ILogger < DistributedRedisCache > > ( ) ;
127- const string keySpaceCommand = "CONFIG SET notify-keyspace-events KEA" ;
128- logger . LogError ( $ "Connection multiplexer has failed to enable key space events, you must manually run this command on your redis servers: '{ keySpaceCommand } '") ;
129- }
130- stackExchangeRedisOptions . AllowAdmin = false ;
131- return ConnectionMultiplexer . Connect ( stackExchangeRedisOptions ) ;
132- } ) ;
133- services . AddStackExchangeRedisCache ( cfg =>
134- {
135- cfg . ConnectionMultiplexerFactory = ( ) => Task . FromResult < IConnectionMultiplexer > ( resolver . Provider ! . GetRequiredService < IConnectionMultiplexer > ( ) ) ;
136- } ) ;
171+ cfg . ConnectionMultiplexerFactory = ( ) => Task . FromResult < IConnectionMultiplexer > ( resolver . Provider ! . GetRequiredService < IConnectionMultiplexer > ( ) ) ;
172+ } ) ;
173+
174+ // add redis cache
175+ services . AddSingleton < DistributedRedisCache > ( ) ;
176+ services . AddHostedService ( provider => provider . GetRequiredService < DistributedRedisCache > ( ) ) ;
177+ services . AddSingleton < IDistributedCache > ( provider => provider . GetRequiredService < DistributedRedisCache > ( ) ) ;
178+ services . AddSingleton < IDistributedLockFactory > ( provider => provider . GetRequiredService < DistributedRedisCache > ( ) ) ;
179+ }
180+ }
137181
182+ private static void AddMemoryCache ( IServiceCollection services , SimpleCacheConfiguration configuration )
183+ {
138184 // add memory cache
139185 // another deficiency in the .NET api here, we need the provider to pull out the correct system clock
140186 // in case it has been replaced
@@ -148,17 +194,21 @@ public static void AddSimpleCache(this IServiceCollection services, SimpleCacheC
148194 Clock = provider . GetRequiredService < ISystemClock > ( )
149195 } ) ) ) ;
150196 services . AddSingleton < IMemoryCache > ( provider => provider . GetRequiredService < MemoryCache > ( ) ) ;
197+ }
151198
152- // add serializer
153- services . AddSingleton < ISerializer > ( configuration . SerializerObject ) ;
154-
155- // add disk space checker
156- services . AddSingleton < IDiskSpace , DiskSpace > ( ) ;
157-
199+ private static void AddFileCache ( IServiceCollection services , SimpleCacheConfiguration configuration )
200+ {
158201 // add file cache
159202 bool useRealFileCache = ! string . IsNullOrWhiteSpace ( configuration . FileCacheDirectory ) ;
160203 if ( useRealFileCache )
161204 {
205+ // add file cache options
206+ var fileOptions = new FileCacheOptions
207+ {
208+ CacheDirectory = configuration . FileCacheDirectory ,
209+ FreeSpaceThreshold = configuration . FileCacheFreeSpaceThreshold
210+ } ;
211+ services . AddSingleton ( fileOptions ) ;
162212 services . AddSingleton < FileCache > ( ) ;
163213 services . AddHostedService ( provider => provider . GetRequiredService < FileCache > ( ) ) ;
164214 services . AddSingleton < IFileCache > ( provider => provider . GetRequiredService < FileCache > ( ) ) ;
@@ -167,34 +217,6 @@ public static void AddSimpleCache(this IServiceCollection services, SimpleCacheC
167217 {
168218 services . AddSingleton < IFileCache > ( new NullFileCache ( ) ) ;
169219 }
170-
171- // add redis cache
172- services . AddSingleton < DistributedRedisCache > ( ) ;
173- services . AddHostedService ( provider => provider . GetRequiredService < DistributedRedisCache > ( ) ) ;
174- services . AddSingleton < IDistributedCache > ( provider => provider . GetRequiredService < DistributedRedisCache > ( ) ) ;
175- services . AddSingleton < IDistributedLockFactory > ( provider => provider . GetRequiredService < DistributedRedisCache > ( ) ) ;
176-
177- // finally, add the layered cache interface
178- services . AddSingleton < ILayeredCache , LayeredCache > ( ) ;
179- }
180-
181- private static void SetConfigurationDefaults ( SimpleCacheConfiguration configuration )
182- {
183- if ( ! string . IsNullOrWhiteSpace ( configuration . SerializerType ) )
184- {
185- var serializerType = Type . GetType ( configuration . SerializerType ) ??
186- throw new ArgumentException ( "Invalid serializer type " + configuration . SerializerType ) ;
187- var serializer = Activator . CreateInstance ( serializerType ) ;
188- if ( serializer is ISerializer serializerInterface )
189- {
190- configuration . SerializerObject = serializerInterface ;
191- }
192- else
193- {
194- throw new ArgumentException ( "Failed to detect serializer interface from type " + configuration . SerializerType ) ;
195- }
196- }
197- configuration . SerializerObject ??= new JsonLZ4Serializer ( ) ;
198220 }
199221}
200222
0 commit comments