我在ServiceStack API中有一个服务来处理图像结果,通过实现IStreamWriter WriteTo(流)。效果很好。
为了优化处理,我添加了对InMemory Cache的支持,使用TimeSpan使结果到期。我的担忧与IDispose有关。在缓存实现之前,我使用IDispose在返回后处理结果对象及其图像,但是使用内存缓存它不能实现IDispose,否则数据将在从缓存中重新获取之前被擦除。
问题是如何或在何处实施缓存结果的处理?缓存是否会在到期时处置项目?如果是这样,如何实现Dispose仅用于来自缓存管理器的调用,而不是来自http处理程序。
public class ImageResult : IDisposable, IStreamWriter, IHasOptions
{
private readonly Image image;
public void WriteTo(Stream responseStream)
{
image.Save(responseStream, imgFormat);
}
public void Dispose()
{
// if we dispose here, will be disposed after the first result is returned
// want the image to be disposed on cache expiration
//if (this.image != null)
// this.image.Dispose();
}
}
public class ImageService : AssetService
{
public object Get(ImageRequest request)
{
var cacheKey = ServiceStack.Common.UrnId.Create<ImageRequest>(request.id);
if (Cache.Get<ImageResult>(cacheKey) == null)
{
Cache.Set<ImageResult>(cacheKey, GetImage(request), TimeSpan.FromMinutes(1));
}
return Cache.Get<ImageResult>(cacheKey);
}
[...]
}
答案 0 :(得分:1)
通过快速查看ServiceStack的InMemoryCache
,您可以看到没有事件或回调挂钩进入缓存条目到期。考虑使用System.Runtime.Caching.MemoryCache
,它可以提供类似的缓存功能,此外,您还可以使用更改监视器在到期和/或删除时进行回调。
另一种选择:使用SS的缓存源代码创建自己的缓存源代码,为您提供回调。
回到原地后,您可以从那里拨打Dispose()
- 但正如您所说,您不希望ImageResult
是一次性的,而是允许访问其Image
1}}属性并从过期回调中自行处理。您可以在.net的图像周围包装一个类以允许进行单元测试(避免在测试中使用真实的图像对象)。
编辑:实际上..见下面(*),这会造成一团糟。
另一方面,我会对你的Get()方法稍作修改。最后一次调用Cache.Get()是多余的。即使您正在使用内存缓存,您仍然希望最大限度地减少对它的访问,因为它可能比看起来更慢(需要使用锁来同步来自多个内存的访问)线程)。
var imageResult = Cache.Get<ImageResult>(cacheKey);
if (imageResult == null)
{
imageResult = GetImage(request);
Cache.Set<ImageResult>(cacheKey, imageResult, TimeSpan.FromMinutes(1));
}
return imageResult;
(*)刚刚意识到你可能有一个请求从缓存中获取ImageResult
,然后一个实例稍后,在它向目标(响应)流写入任何内容之前,它会过期并被释放。讨厌。相反,让.net为您处理:不要使ImageResult
实现IDisposable
,而是创建一个析构函数,在其中处理内部Image
对象。这将与内存缓存中的SS一起使用:
~ImageResult()
{
image.Dispose();
}