我有一个单例提供程序,其主要功能是从Web服务检索对象,并根据webservice缓存头响应进行缓存。这个对象将被访问很多。我的问题是,当webservice中的数据发生变化时,是否会自动反映对单例的任何后续调用?
public class ConfigurationProvider
{
#region Private Member Variables
private static readonly Lazy<ConfigurationProvider> _instance = new Lazy<ConfigurationProvider>(() => new ConfigurationProvider());
private static readonly HttpCache _cache = new HttpCache();
#endregion
#region Constructors
private ConfigurationProvider()
{
}
#endregion
#region Public Properties
public static ConfigurationProvider Instance
{
get { return _instance.Value; }
}
public ShowJsonResponse Configuration
{
get
{
// Try and get the configurations from webservice and add to cache
var cacheExpiry = 0;
return _cache.GetAndSet(WebApiConstant.ProxyCacheKeys.ShowJsonKey, ref cacheExpiry, () => GetConfiguration(ref cacheExpiry));
}
}
#endregion
#region Private Methods
private ShowJsonResponse GetConfiguration(ref int cacheExpiry)
{
var httpClient = new HttpClient();
try
{
var response = httpClient.GetAsync(WebApiConstant.Configuration.WebserviceUrl).Result;
if (response.IsSuccessStatusCode)
{
var showResponse = response.Content.ReadAsAsync<ShowJsonResponse>().Result;
if (response.Headers.CacheControl.Public && response.Headers.CacheControl.MaxAge.HasValue)
{
cacheExpiry = response.Headers.CacheControl.MaxAge.Value.Seconds;
}
// TODO: Remove when finished testing
// Default to 60 seconds for testing
cacheExpiry = 20;
return showResponse;
}
}
catch (HttpRequestException ex)
{
}
cacheExpiry = 0;
return null;
}
#endregion
}
HttpCache类只是HttpRuntime Cache的包装器。 GetAndSet方法只是尝试检索缓存对象,如果找不到则设置它。
public override T GetAndSet<T>(string key, ref int duration, Func<T> method)
{
var data = _cache == null ? default(T) : (T) _cache[key];
if (data == null)
{
data = method();
if (duration > 0 && data != null)
{
lock (sync)
{
_cache.Insert(key, data, null, DateTime.Now.AddSeconds(duration), Cache.NoSlidingExpiration);
}
}
}
return data;
}
用法示例:
ConfigurationProvider.Instance.Configuration.Blah
在这种情况下使用单例模式是否有任何明显的好处,或者定期实例化该类是否正常?
答案 0 :(得分:0)
我认为单例模式在您的情况下更适合,并且您也不需要对象实例。你在HttpCache包装器中处理并发吗?重要的是,为了避免并发线程在两个或多个同时访问缓存对象时或在WS请求返回之前发出多个WS请求。
我建议您使用双锁/检查模式:
public override T GetAndSet<T>(string key, ref int duration, Func<T> method) {
var data = _cache == null ? default(T) : (T) _cache[key];
if (data == null) { //check
lock (sync) { //lock
//this avoids that a waiting thread reloads the configuration again
data = _cache == null ? default(T) : (T) _cache[key];
if (data == null) { //check again
data = method();
if (duration > 0 && data != null) {
_cache.Insert(key, data, null, DateTime.Now.AddSeconds(duration), Cache.NoSlidingExpiration);
}
}
}
}
return data;
}