1

我有一个单例提供程序,其主要功能是从 Web 服务中检索对象,并根据 Web 服务缓存标头响应进行缓存。这个对象将被访问很多。我的问题是当 web 服务中的数据发生变化时,对单例的任何后续调用都会自动反映吗?

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

在这种情况下使用单例模式是否有任何明显的好处,或者定期实例化类可以吗?

4

1 回答 1

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;
}
于 2013-08-12T03:03:43.640 回答