是否需要使用来自webservice的数据刷新单例?

时间:2013-08-12 02:43:00

标签: c# asp.net-mvc-4 singleton

我有一个单例提供程序,其主要功能是从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

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

1 个答案:

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