WCF:如何在客户端缓存来自 OData 的集合

WCF: How to cache collections from OData in client

是否可以缓存使用 WCF 从 OData 服务检索的集合。

情况如下: 我使用 odata 服务的元数据生成了 Visual Studio 2015 的 WCF 服务客户端。 VS 生成了一个继承自 System.Data.Services.Client.DataServiceContext 的 class。这个 class 有一些 System.Data.Services.Client.DataServiceQuery<T> 类型的属性。其中一些属性的数据很少更改。由于性能原因,我希望 WCF 客户端仅在第一次而不是每次在代码中使用它时加载这些属性。

是否有内置的可能性来缓存这些属性的数据?或者我可以告诉服务客户端不要每次都重新加载特定的proeprties。

假设服务客户端 class 是 ODataClient 并且其属性之一是 `Area,现在我通过以下方式获取值:

var client = new ODataClient("url_to_the_service");
client.IgnoreMissingProperties = true;

var propertyInfo = client.GetType().GetProperty("Area");
var area = propertyInfo.GetValue(client) as IEnumerable<object>;

之所以这么复杂,是因为客户端应该非常通用:可以在配置文件中配置要处理的属性。

* 编辑 *

我已经尝试在 System.Data.Services.Client.DataServiceContext class 或 System.Data.Services.Client.DataServiceQuery<T> class 中查找用于缓存的属性。但是我没找到。

据我所知,客户端没有 "out of the box" 缓存概念。有一些选项可以在服务器上缓存请求的输出,这也是您可能需要考虑的。谷歌搜索 "WCF Caching" 会给你一堆这方面的信息。

关于客户端缓存...@Evk 是正确的,它非常简单。这是使用 MemoryCache.

的示例
using System;
using System.Runtime.Caching;

namespace Services.Util
{
    public class CacheWrapper : ICacheWrapper
    {
        ObjectCache _cache = MemoryCache.Default;

        public void ClearCache()
        {
            MemoryCache.Default.Dispose();
            _cache = MemoryCache.Default;
        }

        public T GetFromCache<T>(string key, Func<T> missedCacheCall)
        {
            return GetFromCache<T>(key, missedCacheCall, TimeSpan.FromMinutes(5));
        }

        public T GetFromCache<T>(string key, Func<T> missedCacheCall, TimeSpan timeToLive)
        {
            var result = _cache.Get(key);
            if (result == null)
            {
                result = missedCacheCall();
                if (result != null)
                {
                    _cache.Set(key, result, new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.Add(timeToLive) });
                }
            }

            return (T)result;
        }

        public void InvalidateCache(string key)
        {
            _cache.Remove(key);
        }
    }
}

这是一个使用缓存的代码示例...

private class DataAccessTestStub
        {
            public const string DateTimeTicksCacheKey = "GetDateTimeTicks";

            ICacheWrapper _cache;

            public DataAccessTestStub(ICacheWrapper cache)
            {
                _cache = cache;
            }

            public string GetDateTimeTicks()
            {
                return _cache.GetFromCache(DateTimeTicksCacheKey, () =>
                {
                    var result = DateTime.Now.Ticks.ToString();
                    Thread.Sleep(100); // Create some delay
                    return result;
                });
            }

            public string GetDateTimeTicks(TimeSpan timeToLive)
            {
                return _cache.GetFromCache(DateTimeTicksCacheKey, () =>
                {
                    var result = DateTime.Now.Ticks.ToString();
                    Thread.Sleep(500); // Create some delay
                    return result;
                }, timeToLive);
            }

            public void ClearDateTimeTicks()
            {
                _cache.InvalidateCache(DateTimeTicksCacheKey);
            }

            public void ClearCache()
            {
                _cache.ClearCache();
            }
        }

还有一些测试,如果你喜欢...

 [TestClass]
public class CacheWrapperTest
{
    private DataAccessTestStub _dataAccessTestClass;

    [TestInitialize]
    public void Init()
    {
        _dataAccessTestClass = new DataAccessTestStub(new CacheWrapper());
    }

    [TestMethod]
    public void GetFromCache_ShouldExecuteCacheMissCall()
    {
        var original = _dataAccessTestClass.GetDateTimeTicks();
        Assert.IsNotNull(original);
    }

    [TestMethod]
    public void GetFromCache_ShouldReturnCachedVersion()
    {
        var copy1 = _dataAccessTestClass.GetDateTimeTicks();
        var copy2 = _dataAccessTestClass.GetDateTimeTicks();
        Assert.AreEqual(copy1, copy2);
    }

    [TestMethod]
    public void GetFromCache_ShouldRespectTimeToLive()
    {
        _dataAccessTestClass.ClearDateTimeTicks();
        var copy1 = _dataAccessTestClass.GetDateTimeTicks(TimeSpan.FromSeconds(2));
        var copy2 = _dataAccessTestClass.GetDateTimeTicks();
        Assert.AreEqual(copy1, copy2);

        Thread.Sleep(3000);
        var copy3 = _dataAccessTestClass.GetDateTimeTicks();
        Assert.AreNotEqual(copy1, copy3);
    }

    [TestMethod]
    public void InvalidateCache_ShouldClearCachedVersion()
    {
        var original = _dataAccessTestClass.GetDateTimeTicks();

        _dataAccessTestClass.ClearDateTimeTicks();

        var updatedVersion = _dataAccessTestClass.GetDateTimeTicks();
        Assert.AreNotEqual(original, updatedVersion);
    }

}