I have a class that returns a cache, usage currently:
var cache = new ProductCache().Get();
then cache is a List<> that can be enumerated.
question is really should i populate this cache when ProductCache() is instantiated in the constructor, or when it is retrieved?
Option 1:
public class ProductCache
{
private readonly string key = "Product";
private readonly object cacheLock = new object();
ObjectCache cache = MemoryCache.Default;
public ProductCache()
{
}
public List<string> Get()
{
// Try to return.
var data = cache.Get(key) as List<string>;
if (data != null)
return data;
lock (cacheLock)
{
// Check again.
data = cache.Get(key) as List<string>;
if (data != null)
return data;
// Populate, and return.
data = PopulateFromElsewhere();
cache.Set(key, data, DateTimeOffset.UtcNow.AddSeconds(20));
return data;
}
}
private List<string> PopulateFromElsewhere()
{
return new List<string> { "Ball", "Stick" };
}
}
Option 2:
public class ProductCache
{
private readonly string key = "Product";
private readonly object cacheLock = new object();
ObjectCache cache = MemoryCache.Default;
public ProductCache()
{
var data = cache.Get(key);
if (data != null)
return;
lock (cacheLock)
{
// Check again.
data = cache.Get(key);
if (data != null)
return;
// Populate, and return.
PopulateFromElsewhere();
}
}
public List<string> Get()
{
return cache.Get(key) as List<string>;
}
private void PopulateFromElsewhere()
{
var data = new List<string> { "Ball", "Stick" };
cache.Set(key, data, DateTimeOffset.UtcNow.AddSeconds(20));
}
}
is the second option thread safe (enough)? i think the first one is....
there are other caches too.. and they are all similar, so i was planning on putting all the actual locking / loading behaviour in an abstract class
var storeCache = new StoreCache().Get();
var otherCache = new OtherCache().Get();
I guess the other option is a static class, but then there would need to be duplication of the locking mechanisms as i can't make that abstract... that could be quite nice, and used like...
var cache = GlobalCache.Stores();
If you want to reuse your cache logic but want flexibility in your child classes you could use Template method pattern:
public abstract class BaseCache
{
private readonly object cacheLock = new object();
protected ObjectCache cache = MemoryCache.Default;
public List<string> Get()
{
// for example. It could be anywhere and return any type.
ChildLogic();
var data = cache.Get(key);
if (data != null)
return;
lock (cacheLock)
{
// Check again.
data = cache.Get(key);
if (data != null)
return;
// Populate, and return.
PopulateFromElsewhere();
}
}
protected abstract void ChildLogic();
protected abstract void PopulateFromElsewhere();
}
And then in your child classes you should implement ChildLogic() and PopulateFromElsewhere() any way you want.
Of course you are not required to have method ChildLogic() at all.
Related
I'd like to create a static Cached class for an ASP.NET MVC site for quick access to cached items like dropdown lists. It needs to have locking implemented so that when a key comes back empty it can be pulled from the repository while any other request threads wait on it to come back. As such, it needs per-method thread locking (versus a shared lock). My first thought was to use nameof as the lock for each method instead of creating a separate object to lock for each method. A simplified version would look something like...
public static class Cached
{
public static List<Country> GetCountriesList()
{
List<Country> cacheItem = null;
if (HttpContext.Current.Cache["CountriesList"] != null)
cacheItem = (List<Country>)HttpContext.Current.Cache["CountriesList"];
else
{
lock (nameof(GetCountriesList))
{
// Check once more in case it got stored while waiting on the lock
if (HttpContext.Current.Cache["CountriesList"] == null)
{
using (var repo = new Repository())
{
cacheItem = repo.SelectCountries();
HttpContext.Current.Cache.Insert("CountriesList", cacheItem, null, DateTime.Now.AddHours(2), TimeSpan.Zero);
}
}
else
cacheItem = (List<Country>)HttpContext.Current.Cache["CountriesList"];
}
}
return cacheItem;
}
public static List<State> GetStatesList()
{
List<State> cacheItem = null;
if (HttpContext.Current.Cache["StatesList"] != null)
cacheItem = (List<State>)HttpContext.Current.Cache["StatesList"];
else
{
lock (nameof(GetStatesList))
{
// Check once more in case it got stored while waiting on the lock
if (HttpContext.Current.Cache["StatesList"] == null)
{
using (var repo = new Repository())
{
cacheItem = repo.SelectStates();
HttpContext.Current.Cache.Insert("StatesList", cacheItem, null, DateTime.Now.AddHours(2), TimeSpan.Zero);
}
}
else
cacheItem = (List<State>)HttpContext.Current.Cache["StatesList"];
}
}
return cacheItem;
}
}
Is there anything glaringly wrong with an approach like this?
UPDATE:
Per the advice that it is a bad idea to lock on strings, I've changed it to a pattern that I found in SO's Opserver code that uses a ConcurrentDictionary to store a lock object per cache key. Is there anything wrong with the following:
public static class Cached
{
private static readonly ConcurrentDictionary<string, object> _cacheLocks = new ConcurrentDictionary<string, object>();
private const string KEY_COUNTRIES_LIST = "CountriesList";
public static List<Country> GetCountriesList()
{
List<Country> cacheItem = null;
var nullLoadLock = _cacheLocks.AddOrUpdate(KEY_COUNTRIES_LIST, k => new object(), (k, old) => old);
if (HttpContext.Current.Cache[KEY_COUNTRIES_LIST] != null)
cacheItem = (List<Country>)HttpContext.Current.Cache[KEY_COUNTRIES_LIST];
else
{
lock (nullLoadLock)
{
// Check once more in case it got stored while waiting on the lock
if (HttpContext.Current.Cache[KEY_COUNTRIES_LIST] == null)
{
using (var repo = new Repository())
{
cacheItem = repo.SelectCountries();
HttpContext.Current.Cache.Insert(KEY_COUNTRIES_LIST, cacheItem, null, DateTime.Now.AddHours(2), TimeSpan.Zero);
}
}
else
cacheItem = (List<Country>)HttpContext.Current.Cache[KEY_COUNTRIES_LIST];
}
}
return cacheItem;
}
private const string KEY_STATES_LIST = "StatesList";
public static List<State> GetStatesList()
{
List<State> cacheItem = null;
var nullLoadLock = _cacheLocks.AddOrUpdate(KEY_COUNTRIES_LIST, k => new object(), (k, old) => old);
if (HttpContext.Current.Cache[KEY_STATES_LIST] != null)
cacheItem = (List<State>)HttpContext.Current.Cache[KEY_STATES_LIST];
else
{
lock (nullLoadLock)
{
// Check once more in case it got stored while waiting on the lock
if (HttpContext.Current.Cache[KEY_STATES_LIST] == null)
{
using (var repo = new Repository())
{
cacheItem = repo.SelectStates();
HttpContext.Current.Cache.Insert(KEY_STATES_LIST, cacheItem, null, DateTime.Now.AddHours(2), TimeSpan.Zero);
}
}
else
cacheItem = (List<State>)HttpContext.Current.Cache[KEY_STATES_LIST];
}
}
return cacheItem;
}
}
Based on what you posted so far, I think you're over-thinking this. :) I don't see a need to populate yet another dictionary with your locking objects. Since you are using them in explicitly named methods, just declare them as fields as needed.
First, the advice to not lock on string values is sound, but based on the problem that two string values can appear identical while still being different objects. You could avoid that in your scenario by storing the appropriate string value in a const field:
public static class Cached
{
private const string _kcountries = "CountriesList";
private const string _kstates = "StatesList";
public static List<Country> GetCountriesList()
{
List<Country> cacheItem = (List<Country>)HttpContext.Current.Cache[_kcountries];
if (cacheItem == null)
{
lock (_kcountries)
{
// Check once more in case it got stored while waiting on the lock
cacheItem = (List<Country>)HttpContext.Current.Cache[_kcountries];
if (cacheItem == null)
{
using (var repo = new Repository())
{
cacheItem = repo.SelectCountries();
HttpContext.Current.Cache.Insert(_kcountries, cacheItem, null, DateTime.Now.AddHours(2), TimeSpan.Zero);
}
}
}
}
return cacheItem;
}
public static List<State> GetStatesList()
{
// Same as above, except using _kstates instead of _kcountries
}
}
Note that you shouldn't be using string literals throughout the code anyway. It's much better practice to define const fields to represent those values. So you kill two birds with one stone doing the above. :)
The only remaining problem is that you are still using a possibly-public value to lock, since the string literals are interned, and if the exact same string was used somewhere else, it would likely be the same interned value as well. This is of debatable concern; it's my preference to avoid doing so, to ensure no other code outside my control could take the same lock my code is trying to use, but there are those who feel such concerns are overblown. YMMV. :)
If you do care (as I do) about using the possibly-public value, then you can associate a unique object value instead of using the string reference:
public static class Cached
{
private const string _kcountriesKey = "CountriesList";
private const string _kstatesKey = "StatesList";
private static readonly object _kcountriesLock = new object();
private static readonly object _kstatesLock = new object();
public static List<Country> GetCountriesList()
{
List<Country> cacheItem = (List<Country>)HttpContext.Current.Cache[_kcountriesKey];
if (cacheItem == null)
{
lock (_kcountriesLock)
{
// Check once more in case it got stored while waiting on the lock
cacheItem = (List<Country>)HttpContext.Current.Cache[_kcountriesKey];
if (cacheItem == null)
{
using (var repo = new Repository())
{
cacheItem = repo.SelectCountries();
HttpContext.Current.Cache.Insert(_kcountriesKey, cacheItem, null, DateTime.Now.AddHours(2), TimeSpan.Zero);
}
}
}
}
return cacheItem;
}
// etc.
}
I.e. use the ...Key field for your cache (since it does require string values for keys) but the ...Lock field for locking (so that you are sure no code outside your control would have access to the object value used for the lock).
I'll note that you do have an opportunity to reduce the repetition in the code, by writing a single Get...() implementation that can be shared by your various types of data:
public static class Cached
{
private const string _kcountriesKey = "CountriesList";
private const string _kstatesKey = "StatesList";
private static readonly object _kcountriesLock = new object();
private static readonly object _kstatesLock = new object();
public static List<Country> GetCountriesList()
{
// Assuming SelectCountries() is in fact declared to return List<Country>
// then you should actually be able to omit the type parameter in the method
// call and let type inference figure it out. Same thing for the call to
// _GetCachedData<State>() in the GetStatesList() method.
return _GetCachedData<Country>(_kcountriesKey, _kcountriesLock, repo => repo.SelectCountries());
}
public static List<State> GetStatesList()
{
return _GetCachedData<State>(_kstatesKey, _kstatesLock, repo => repo.SelectStates());
}
private static List<T> _GetCachedData<T>(string key, object lockObject, Func<Repository, List<T>> selector)
{
List<T> cacheItem = (List<T>)HttpContext.Current.Cache[key];
if (cacheItem == null)
{
lock (lockObject)
{
// Check once more in case it got stored while waiting on the lock
cacheItem = (List<T>)HttpContext.Current.Cache[key];
if (cacheItem == null)
{
using (var repo = new Repository())
{
cacheItem = selector(repo);
HttpContext.Current.Cache.Insert(key, cacheItem, null, DateTime.Now.AddHours(2), TimeSpan.Zero);
}
}
}
}
return cacheItem;
}
// etc.
}
Finally, I'll note that since the underlying cache (i.e. System.Web.Caching.Cache) is thread-safe, you could just skip all of this altogether, and instead choose to blindly populate the cache if your item (the List<T> in question) isn't found. The only downside is that you in some cases could retrieve the same list more than once. The upside is that the code is a lot simpler.
I have the following cache implementation for my application:
public static class Keys
{
public const string CacheKey = "cachekey";
}
public interface ICache
{
string QueryCachedData(string param);
}
the data is loaded when the application starts in Global.asax
//Global.asax
protected void Application_Start(object sender, EventArgs e)
{
//instantiates the repository
HttpContext.Current.Application[Keys.CacheKey] = repository.getDataView();
}
the implementation recover the data from HttpContext.Current
public class Cache : ICache
{
private Cache() { }
private static Cache _instance = null;
public static Cache GetInstance()
{
if (_instance == null)
_instance = new Cache();
return _instance;
}
private System.Data.DataView GetCachedData()
{
if (HttpContext.Current.Application[Keys.CacheKey] == null)
{
//instantiates the repository
HttpContext.Current.Application[Keys.CacheKey] = repository.getDataView();
}
return HttpContext.Current.Application[Keys.CacheKey] as System.Data.DataView;
}
private readonly Object _lock = new Object();
public string QueryCachedData(string param)
{
lock (_lock)
{
var data = GetCachedData();
//Execute query
return result;
}
}
}
at some point i need consume some third party web service with the following class using the cache...
public class ThirdPartyWebserviceConsumer
{
ICache _cache;
int _provider;
public ThirdPartyWebserviceConsumer(int provider, ICache cache)
{
_cache = cache;
_provider = provider;
}
public result DoSomething()
{
var info = _cache.QueryCachedData(param);
}
}
...using multi-thread:
public List<Result> Foo(ICache cache, List<int> collectionOfProviders)
{
List<Result> results = new List<Result>();
List<Task> taskList = new List<Task>();
foreach (var provider in collectionOfProviders)
{
var task = new Task<Result>(() => new ThirdPartyWebserviceConsumer(provider, cache).DoSomething());
task.Start();
task.ContinueWith(task =>
{
results.Add(task.Result);
});
taskList.Add(task);
}
Task.WaitAll(taskList.ToArray());
return results;
}
My problem is that HttpContext.Current.Application is null in the thead context.
What options do I have? there are some form to access the HttpContext in thread? or maybe another type of cache that could be shared between the threads?
My problem is that HttpContext.Current.Application is null in the thead context. What options do I have?
HttpContext.Current is bound to the managed thread processing the current request.
If you need data from the current context for another thread, you need to copy that data out of the current context first and pass it to your separate thread.
I might have coded myself into a corner here, but I am hoping there is a simple way out of it.
My Logic Layer is a static singleton instance that has lots of properties for accessing the individual sub-Logic Layers. Most of this was put in place for unit testing to allow injection of custom repositories and works quite nicely for that. However the boiler plate code for each sub-instance is very repetitive and I would expect that there is a way to simplify it.
Below is a very simplified example to demonstrate how far I have manages to get and where I am stuck. The one way that works is with an indexer on the sub-logic class wrapper to get to the sub-logic, which reads very strangely. The other way is by using a random letter as a property on the sub-logic class wrapper to get to the sub-logic. This reads slightly better, but still has a ripple effect on all the existing code.
Can this be done the way I want to, or should I be looking at this completely differently.
Apologies for the length of the example. I tried to make it as simple as possible while still keeping the concept intact
class Program
{
static void Main(string[] args)
{
var logic = new Logic();
// old usage (desired)
var abcs_1 = logic.ABCs_1.List();
var defs_1 = logic.DEFs_1.List();
// new usage (would like to keep old way)
var abcs_2 = logic.ABCs_2[0].List(); // <-- ugly
var defs_2 = logic.DEFs_2.d.List(); // <-- less ugly, but still not pretty
//var abcs_2 = logic.ABCs_2.List(); // <-- wanted
//var defs_2 = logic.DEFs_2.List(); // <-- wanted
}
}
public class ABC { }
public class DEF { }
public class ABCsLogicLayer
{
public List<ABC> List() { return null; }
}
public class DEFsLogicLayer
{
public List<DEF> List() { return null; }
}
public class Logic
{
#region New Code. Want to move towards this
public LogicLocker<ABCsLogicLayer> ABCs_2 = new LogicLocker<ABCsLogicLayer>();
public LogicLocker<DEFsLogicLayer> DEFs_2 = new LogicLocker<DEFsLogicLayer>();
#endregion
#region Old Code. Want to move away from this.
#region BuilerPlate for ABCs_1
private ABCsLogicLayer m_ABCs = null;
private readonly object m_ABCsLock = new object();
public ABCsLogicLayer ABCs_1
{
get
{
lock (m_ABCsLock)
{
if (m_ABCs == null)
{
m_ABCs = new ABCsLogicLayer();
}
}
return m_ABCs;
}
set
{
lock (m_ABCsLock)
{
m_ABCs = value;
}
}
}
#endregion
#region BuilerPlate for DEFs_1
private DEFsLogicLayer m_DEFs = null;
private readonly object m_DEFsLock = new object();
public DEFsLogicLayer DEFs_1
{
get
{
lock (m_DEFsLock)
{
if (m_DEFs == null)
{
m_DEFs = new DEFsLogicLayer();
}
}
return m_DEFs;
}
set
{
lock (m_DEFsLock)
{
m_DEFs = value;
}
}
}
#endregion
#endregion
}
public class LogicLocker<T> where T : class, new()
{
private T LogicLayer = null;
private readonly object LogicLayerLock = new object();
public T this[int i]
{
get
{
lock (LogicLayerLock)
{
if (LogicLayer == null)
{
LogicLayer = new T();
}
}
return LogicLayer;
}
set
{
lock (LogicLayerLock)
{
LogicLayer = value;
}
}
}
public T d
{
get
{
lock (LogicLayerLock)
{
if (LogicLayer == null)
{
LogicLayer = new T();
}
}
return LogicLayer;
}
set
{
lock (LogicLayerLock)
{
LogicLayer = value;
}
}
}
}
You can use interface for solve your problem:
1) Define interface with List method:
public interface ILogicLayer<T>
{
List<T> List();
}
2) Your logic layer class should implement this interface:
public class ABCsLogicLayer:ILogicLayer<ABC>
3) LogicLocker should implement this interface as well
public class LogicLocker<T,U> : ILogicLayer<U> where T : ILogicLayer<U>, new()
Implementation of List method will be:
lock (LogicLayerLock)
{
if (LogicLayer == null)
{
LogicLayer = new T();
}
}
return LogicLayer.List();
4) You will instantiate your logic locker in the Logic class
public LogicLocker<ABCsLogicLayer, ABC> ABCs_2 = new LogicLocker<ABCsLogicLayer,ABC>();
public LogicLocker<DEFsLogicLayer, DEF> DEFs_2 = new LogicLocker<DEFsLogicLayer, DEF>();
or better make it more generics:
public LogicLocker<LogicLayer<ABC>> ABCs_2 = new LogicLocker<LogicLayer<ABC>>();
but it depends on what you want
I have a few static Dictionary object that holds some constants list for me so I wouldn't have to load them from database each time my website loads (for example: a list of countries, a list of categories).
So I have a static function that checks if the instance is null, and if it is query the database, instantiate the static variable, and populate it with data.
Since it is a website, there could be a case that more than one person tries to access that information at the same time while the object is null, and all those who do will call that process at the same time (which is really not necessary, causes unneeded queries against the DB, and could cause duplicated objects in the list).
I know there's a way to make this kind of loading thread-safe (just not really sure how) - could someone point me in the right direction? should I use a lock?
Thanks
UPDATE II:
This is what I wrote (is this a good thread-safe code?)
private static Lazy<List<ICountry>> _countries = new Lazy<List<ICountry>>(loadCountries);
private static List<ICountry> loadCountries()
{
List<ICountry> result = new List<ICountry>();
DataTable dtCountries = SqlHelper.ExecuteDataTable("stp_Data_Countries_Get");
foreach (DataRow dr in dtCountries.Rows)
{
result.Add(new Country
{
ID = Convert.ToInt32(dr["CountryId"]),
Name = dr["Name"].ToString()
});
}
return result;
}
public static List<ICountry> GetAllCountries()
{
return _countries.Value;
}
You can use Lazy to load a resource in a lazy and thread-safe manner:
Lazy<List<string>> countries =
new Lazy<List<string>>(()=> /* get your countries from db */);
Update:
public static class HelperTables
{
private static Lazy<List<ICountry>> _countries;
static HelperTables //Static constructor
{
//Instantiating the lazy object in the static constructor will prevent race conditions
_countries = new Lazy<List<ICountry>>(() =>
{
List<ICountry> result = new List<ICountry>();
DataTable dtCountries = SqlHelper.ExecuteDataTable("stp_Data_Countries_Get");
foreach (DataRow dr in dtCountries.Rows)
{
result.Add(new Country
{
ID = Convert.ToInt32(dr["CountryId"]),
Name = dr["Name"].ToString()
});
}
return result;
});
}
public static List<ICountry> GetAllCountries()
{
return _countries.Value;
}
}
If you're using .NET 4.0, you can use the builtin Lazy generic class.
private static Lazy<YourObject> data = new Lazy<YourObject>(YourInitializationFunction);
public static YourObject Data { get { return data.Value; } }
Note that you have to add a static constructor to the class where you define this, otherwise it's not completely thread-safe.
If you're not on .NET 4.0+, you can just write your own code. The basic pattern looks something like this:
private static YourObject data;
private static object syncObject = new object();
public static YourObject Data
{
get
{
if (data == null)
{
lock (syncObject)
{
if (data != null)
return data;
var obj = new YourObject();
return (YourObject)Interlocked.Exchange(ref data, obj);
}
}
return data;
}
}
I have a singleton provider, where the main function is to retrieve an object from a webservice, and cache depending on the webservice cache headers response. This object will be accessed quite a lot. My question is when the data in the webservice changes, will any subsequent call to the singleton automatically be reflected?
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
}
The HttpCache class is just a wrapper around HttpRuntime Cache. The GetAndSet method just tries to retrieve the cache object and sets it if not found.
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;
}
Usage example:
ConfigurationProvider.Instance.Configuration.Blah
Is there any perceived benefit to using the singleton pattern in this scenario, or instantiate the class regularly would be ok?
I think that the singleton pattern fits better in your case, and you won't need the object instance as well. Are you taking care of concurrency inside your HttpCache wrapper? It's important in order to avoid that concurrent threads could make multiple WS requests when two or more access the cache object at the same time or before the WS request returns.
I would suggest you to use the double lock/check pattern:
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;
}