This is a Redis based ICacheProvider for NHibernate written in C# using ServiceStack.Redis.
- You can install using NuGet:
PM> Install-Package NHibernate.Caches.Redis
- Or build/install from source:
msbuild .\build\build.proj
and then look inside thebin
directory.
Configure NHibernate to use the custom cache provider:
<property name="cache.use_second_level_cache">true</property>
<property name="cache.use_query_cache">true</property>
<property name="cache.provider_class">NHibernate.Caches.Redis.RedisCacheProvider,
NHibernate.Caches.Redis</property>
Set the IRedisClientsManager
(pooled, basic, etc) on the RedisCacheProvider
before creating your ISessionFactory
:
// Or use your IoC container to wire this up.
var clientManager = new PooledRedisClientManager("localhost:6379");
RedisCacheProvider.SetClientManager(clientManager);
using (var sessionFactory = ...)
{
// ...
}
clientManager.Dispose();
Inside of the app/web.config
, a custom configuration section can be added to
configure each cache region:
<configSections>
<section name="nhibernateRedisCache" type="NHibernate.Caches.Redis.RedisCacheProviderSection, NHibernate.Caches.Redis" />
</configSections>
<nhibernateRedisCache>
<caches>
<cache region="BlogPost" expiration="900" />
</caches>
</nhibernateRedisCache>
You may require that we gracefully continue to the database as if we "missed" the cache if an exception occurs. By default, this is what happens.
However, there is also the need of advanced exception handling scenarios. For example, imagine if you are using NHibernate in a web project and your Redis server is unavailable. You may not want NHibernate to continue to timeout for every NHibernate operation. Therefore, you do something similar to this:
public class RequestRecoveryRedisCache : RedisCache
{
private const string SkipNHibernateCacheKey = "__SkipNHibernateCache__";
public RequestRecoveryRedisCache(string regionName, IDictionary<string, string> properties, RedisCacheElement element, IRedisClientsManager clientManager)
: base(regionName, properties, element, clientManager)
{
}
public override object Get(object key)
{
if (HasFailedForThisHttpRequest()) return null;
return base.Get(key);
}
public override void Put(object key, object value)
{
if (HasFailedForThisHttpRequest()) return;
base.Put(key, value);
}
public override void Remove(object key)
{
if (HasFailedForThisHttpRequest()) return;
base.Remove(key);
}
public override void Clear()
{
if (HasFailedForThisHttpRequest()) return;
base.Clear();
}
public override void Destroy()
{
if (HasFailedForThisHttpRequest()) return;
base.Destroy();
}
public override void Lock(object key)
{
if (HasFailedForThisHttpRequest()) return;
base.Lock(key);
}
public override void Unlock(object key)
{
if (HasFailedForThisHttpRequest()) return;
base.Unlock(key);
}
protected override void OnException(RedisCacheExceptionEventArgs e)
{
HttpContext.Current.Items[SkipNHibernateCacheKey] = true;
}
private bool HasFailedForThisHttpRequest()
{
return HttpContext.Current.Items.Contains(SkipNHibernateCacheKey);
}
}
public class RequestRecoveryRedisCacheProvider : RedisCacheProvider
{
protected override RedisCache BuildCache(string regionName, IDictionary<string, string> properties, RedisCacheElement configElement, IRedisClientsManager clientManager)
{
return new RequestRecoveryRedisCache(regionName, properties, configElement, clientManager);
}
}
And then use RequestRecoveryRedisCacheProvider
in your app/web.config
settings.
1.3.0
- Add the
OnException
method for sub-classing the cache client and handling exceptions.
1.2.1
- Update ServiceStack.Redis to 3.9.55.
1.2.0
- Allow the provider to gracefully continue when Redis is unavailable.
- Fix infinite loop when data in Redis was cleared.
1.1.0
- Added configuration section for customizing the cache regions.
- Added sample project.
1.0.0
- Initial release.
Happy caching!