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);
}
}
是否可以缓存使用 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);
}
}