Redis Cache provider
The Redis Output Cache Provider is an out-of-process storage mechanism for output cache data. This data is specifically for full HTTP responses (page output caching). The provider plugs into the new output cache provider extensibility point that was introduced in ASP.NET 4. For ASP.NET Core applications, read Response caching in ASP.NET Core.
To use the Redis Output Cache Provider, first configure your cache, and then configure your ASP.NET application using the Redis Output Cache Provider NuGet package. This topic provides guidance on configuring your application to use the Redis Output Cache Provider. For more information about creating and configuring an Azure Cache for Redis instance, see Create a cache.
Store ASP.NET page output in the cache
To configure a client application in Visual Studio using the Azure Cache for Redis Session State NuGet package, click NuGet Package Manager, Package Manager Console from the Tools menu.
Run the following command from the Package Manager Console
window.
Install-Package Microsoft.Web.RedisOutputCacheProvider
The Redis Output Cache Provider NuGet package has a dependency on the StackExchange.Redis.StrongName package. If the StackExchange.Redis.StrongName package is not present in your project, it is installed. For more information about the Redis Output Cache Provider NuGet package, see the RedisOutputCacheProvider NuGet page.
<caching>
<outputCache defaultProvider="MyRedisOutputCache">
<providers>
<add name="MyRedisOutputCache" type="Microsoft.Web.Redis.RedisOutputCacheProvider"
host=""
accessKey=""
ssl="true" />
</providers>
</outputCache>
</caching>
https://docs.microsoft.com/en-us/azure/azure-cache-for-redis/cache-aspnet-output-cache-provider
public interface ICacheProvider | |
{ | |
T Get<T>(string key, Func<T> fetch) where T : class; | |
IEnumerable<T> GetAll<T>(IReadOnlyCollection<string> keys, Func<IEnumerable<T>> fetch, Func<T, string, string> keyGen, string keyPrefix) where T : class; | |
void Clear(string key); | |
} | |
//Encryt and decrypt | |
//Logging service | |
//Key for different env same shared redis cache | |
public class RedisCacheProvider : ICacheProvider | |
{ | |
private readonly Func<IDatabase> _connectionResolver; | |
private const double CacheTimeMaxDeviationFraction = 0.2; | |
private readonly ICryptoService _cyptoService; | |
private readonly ILoggerService _loggerService; | |
private readonly string _environment; | |
private readonly string _encryptionKey = ConfigurationManager.AppSettings[AppSettingKeys.Common.RedisEncryptionKey]; | |
private static readonly Random Random = new Random(Guid.NewGuid().GetHashCode()); | |
public RedisCacheProvider(bool enableCacheEncryption, int cacheExpiration, string environment, Func<IDatabase> connectionResolver, ICryptoService cyptoService, | |
ILoggerService loggerService) | |
{ | |
_connectionResolver = connectionResolver; | |
CacheExpiration = cacheExpiration; | |
EnableCacheEncryption = enableCacheEncryption; | |
_cyptoService = cyptoService; | |
_loggerService = loggerService; | |
_environment = environment; | |
} | |
private int CacheExpiration { get; set; } | |
private bool EnableCacheEncryption { get; set; } | |
public T Get<T>(string key, Func<T> fetch) where T : class | |
{ | |
return Get(key, fetch, CacheExpiration, EnableCacheEncryption); | |
} | |
public IEnumerable<T> GetAll<T>(IReadOnlyCollection<string> keys, Func<IEnumerable<T>> fetch, | |
Func<T, string, string> keyGen, string keyPrefix) where T : class | |
{ | |
return GetAll(keys, fetch, keyGen, CacheExpiration, EnableCacheEncryption, keyPrefix); | |
} | |
private IEnumerable<T> GetAll<T>(IReadOnlyCollection<string> keys, Func<IEnumerable<T>> fetch, | |
Func<T, string, string> keyGen, int minutesToExpiry, bool enableCacheEncryption, string keyPrefix) where T : class | |
{ | |
var redisKeys = keys.Select(key => (RedisKey)GetKey(key)).ToArray(); | |
try | |
{ | |
var redisValue = _connectionResolver().StringGet(redisKeys)? | |
.Where(r => r.HasValue) | |
.Select(r => JsonConvert.DeserializeObject<T>(enableCacheEncryption ? _cyptoService.Decrypt(r, _encryptionKey) : r.ToString())); | |
if (redisValue == null) return null; | |
var redisValueArr = redisValue as T[] ?? redisValue.ToArray(); | |
if (redisValueArr.Count() == keys.Count) | |
{ | |
_loggerService.Info($"Cache Hit {keyPrefix}: keys - {keys.Count}"); | |
return redisValueArr; | |
} | |
_loggerService.Info($"Cache Miss {keyPrefix}: Search keys - {keys.Count} Redis Keys -{redisValueArr.Count()}"); | |
} | |
catch (Exception ex) | |
{ | |
_loggerService.Error($"Error while getting cache from redis. Key: {keyPrefix}, Message: {ex.Message} : {ex}"); | |
return null; | |
} | |
var values = fetch(); | |
if (values == null) return null; | |
var valuesFeatched = values as T[] ?? values.ToArray(); | |
foreach (var value in valuesFeatched) | |
{ | |
var featchedValue = (enableCacheEncryption) ? _cyptoService.Encrypt(JsonConvert.SerializeObject(value), _encryptionKey) : JsonConvert.SerializeObject(value); | |
_connectionResolver().StringSet(GetKey(keyGen(value, keyPrefix)), featchedValue, GetCacheAbsoluteExpiration(minutesToExpiry)); | |
} | |
_loggerService.Info($"Cache Added {keyPrefix}: Search keys - {keys.Count} Featched Keys -{valuesFeatched.Count()}"); | |
return valuesFeatched; | |
} | |
} | |
public void Clear(string key) | |
{ | |
throw new NotImplementedException(); | |
} | |
private T Get<T>(string key, Func<T> fetch, int minutesToExpiry, bool enableCacheEncryption) where T : class | |
{ | |
var redisValue = _connectionResolver().StringGet(GetKey(key)); | |
if (redisValue.HasValue) | |
{ | |
redisValue = enableCacheEncryption ? _cyptoService.Decrypt(redisValue, _encryptionKey) : redisValue.ToString(); | |
return JsonConvert.DeserializeObject<T>(redisValue); | |
} | |
var value = fetch(); | |
if (value == null) return null; | |
_connectionResolver().StringSet(GetKey(key), enableCacheEncryption ? _cyptoService.Encrypt(JsonConvert.SerializeObject(value), _encryptionKey) : JsonConvert.SerializeObject(value), GetCacheAbsoluteExpiration(minutesToExpiry)); | |
return value; | |
} | |
private static TimeSpan? GetCacheAbsoluteExpiration(int requestedMinutes) | |
{ | |
var maxDeviation = requestedMinutes * CacheTimeMaxDeviationFraction; | |
var deviation = (Random.NextDouble() - 0.5) * 2 * maxDeviation; | |
return TimeSpan.FromMinutes(requestedMinutes + deviation); | |
} | |
private string GetKey(string key) | |
{ | |
return string.IsNullOrWhiteSpace(_environment) ? $"{key}" : $"{_environment}:{key}"; | |
} | |
} | |
public static class RedisReferenceDataConnnection | |
{ | |
/// <summary> | |
/// To use a different App Setting you will need to write your own connection resolver and register it | |
/// via AutoFac (an example can be seen where RedisCache is registered in ServiceQuotesModule). | |
/// </summary> | |
private static readonly string ConnectionString = ConfigurationManager.ConnectionStrings["redis"].ConnectionString; | |
/// <summary> | |
/// Static property initialization and lazy loading to simulate connection pooling. | |
/// This has the constraint of forcing us into a static App Settings key ie 'redisCache'. | |
/// </summary> | |
private static readonly Lazy<ConnectionMultiplexer> Connection = | |
new Lazy<ConnectionMultiplexer>( | |
() => ConnectionMultiplexer.Connect(ConnectionString)); | |
public static IDatabase GetConnection(int databaseId) | |
{ | |
return Connection.Value.GetDatabase(databaseId); | |
} | |
} | |
public class AutofacServiceProviderBuilder | |
: BaseServiceProviderBuilder | |
{ | |
protected override IServiceProvider BuildServiceProvider(IServiceCollection serviceCollection) | |
{ | |
var builder = new ContainerBuilder(); | |
/*------------------------------------------------------------------------------------------ | |
* Register Sitecore services in Autofac. | |
* It goes through all existing services (registered so far by Sitecore) and | |
* registers them in Autofac, which makes them available in your DI container. If | |
* Sitecore registers more services later on, they will be registered in Autofac through | |
* the IServiceProvider adaptor we returned from BuildServiceProvider(). | |
*------------------------------------------------------------------------------------------ | |
*/ | |
builder.Populate(serviceCollection); | |
// Register our custom services via a module. | |
builder.RegisterModule<ServicesModule>(); | |
// Register all MVC controllers in the current assembly. | |
builder.RegisterControllers(Assembly.GetExecutingAssembly()); | |
RegisterServices(builder); | |
//builder.RegisterFilterProvider(); | |
IContainer container = builder.Build(); | |
Platform.ServiceLocator.SetLocator(container); | |
return container.Resolve<IServiceProvider>(); | |
} | |
private static void RegisterServices(ContainerBuilder builder) | |
{ | |
var cryptoService = new CryptoService(); | |
builder.RegisterInstance<ICryptoService>(cryptoService); | |
builder.Register(ctx => | |
{ | |
var cacheExpirationintvalue = 0; | |
var enableCacheEncryption = false; | |
cacheExpirationintvalue = (cacheExpirationintvalue == 0) ? 2000 : cacheExpirationintvalue; | |
var databaseId = int.Parse(System.Configuration.ConfigurationManager.AppSettings["refDataId"]); | |
var environment = System.Configuration.ConfigurationManager.AppSettings["Env"]; | |
return new RedisCacheProvider(enableCacheEncryption, cacheExpirationintvalue, environment, | |
() => RedisReferenceDataConnnection.GetConnection(databaseId), new CryptoService(), | |
new LoggerService("abc")); | |
}).As<ICacheProvider>(); | |
; | |
} |
No comments :
Post a Comment