我正在遵循一些做法 documented通过 steven并使用 Simple Injector .我有一个从 WCF 服务检索数据的查询,我想使用 ObjectCache
的实例缓存结果.
我定义了一个装饰器 CachingQueryHandlerDecorator<TQuery, TResult>
:
public sealed class CachingQueryHandlerDecorator<TQuery, TResult>
: IQueryHandler<TQuery, TResult>
where TQuery : IQuery<TResult>
{
private readonly IQueryHandler<TQuery, TResult> _handler;
private readonly ObjectCache _cache;
private readonly CacheItemPolicy _policy;
private readonly ILog _log;
public CachingQueryHandlerDecorator(IQueryHandler<TQuery, TResult> handler,
ObjectCache cache,
CacheItemPolicy policy,
ILog log)
{
_handler = handler;
_cache = cache;
_policy = policy;
_log = log;
}
public TResult Handle(TQuery query)
{
var key = query.GetType().ToString();
var result = (TResult) _cache[key];
if (result == null)
{
_log.Debug(m => m("No cache entry for {0}", key));
result = (TResult)_handler.Handle(query);
if (!_cache.Contains(key))
_cache.Add(key, result, _policy);
}
return result;
}
}
在SimpleInjectorInitializer.cs
内我定义缓存和策略,并为特定查询添加装饰器:
container.RegisterSingle<ILog>(LogManager.GetCurrentClassLogger());
container.RegisterSingle<ObjectCache>(() => new MemoryCache("MyCache"));
container.RegisterSingle<CacheItemPolicy>(() => new CacheItemPolicy { AbsoluteExpiration = DateTime.Now.AddMinutes(1) } );
.
.
.
container.RegisterDecorator(typeof(IQueryHandler<,>),
typeof(CachingQueryHandlerDecorator<,>),
ctx => ctx.ServiceType.GetGenericArguments()[0] == typeof(MyQuery));
我面临的问题是我希望能够指定不同的 CacheItemPolicy
用于不同的查询。我可以创建一个新的 ICachePolicy<TQuery>
接口(interface),然后为每个不同的查询类型定义具体的类,但我希望有一种方法可以避免这种情况,并直接在初始化文件中定义每个查询的策略。
最佳答案
I could create a new ICachePolicy interface and then define concrete classes for each different query type
我认为这实际上是一个非常好的想法。您可以注册一个默认的通用实现,该实现注入(inject)到每个没有注册特定实现的装饰器中:
container.RegisterOpenGeneric(typeof(ICachePolicy<>), typeof(DefaultCachePolicy<>),
Lifestyle.Singleton);
对于具有替代缓存策略的查询,您可以注册一个特定的实现:
container.RegisterSingle<ICachePolicy<MyQuery>>(new CachePolicy<MyQuery>
{
AbsoluteExpiration = DateTime.Now.AddHour(2)
});
另一种选择是使用描述缓存策略的属性来标记查询或其查询处理程序(这是我通常采用的方法):
[CachePolicy(AbsoluteExpirationInSeconds = 1 * 60 * 60)]
public class MyQuery : IQuery<string[]> { }
现在您不必注入(inject) ICachePolicy<T>
,但可以使用反射直接读取此元数据:
public sealed class CachingQueryHandlerDecorator<TQuery, TResult>
: IQueryHandler<TQuery, TResult>
where TQuery : IQuery<TResult>
{
private static readonly bool shouldCache;
private static readonly CachingPolicySettings policy;
private readonly IQueryHandler<TQuery, TResult> _handler;
private readonly ObjectCache _cache;
private readonly ILog _log;
static CachingQueryHandlerDecorator()
{
var attribute = typeof(TQuery).GetCustomAttribute<CachePolicyAttribute>();
if (attribute != null)
{
shouldCache = true;
policy = attribute.Policy;
}
}
public CachingQueryHandlerDecorator(
IQueryHandler<TQuery, TResult> handler,
ObjectCache cache,
ILog log)
{
_handler = handler;
_cache = cache;
_log = log;
}
public TResult Handle(TQuery query)
{
if (!shouldCache)
{
return this._handler.handle(query);
}
// do your caching stuff here.
}
关于c# - 如何使用 Simple Injector 注入(inject) CacheItemPolicy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19803555/