如何在ServiceStack中处理InMemory缓存结果

时间:2013-11-29 09:55:29

标签: servicestack

我在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);
    } 
    [...]
}

1 个答案:

答案 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();
    }