Reference to cache object - c#

I'm using .NET C# for a project.
I have a list of products which I want to cache as they're used company wide. If the products drop out of cache I already know how to lock the cache and rebuild it ok as per the patterns on various authority/blog sites.
In my pages/user controls etc, I might grab a reference to the cache, like this:
var myCacheInstance = cachedProducts
However, I might also want to do something like this:
myCacheInstance.Add(new product(...));
Which will also update the cache as it's the same object.
I have 2 queries.
If I have a reference to the cached object is it guaranteed to remain in cache for the lifetime of my variable?
In the scanario outlined above, how do I go about ensuring integrity? I'm only planning on adding in this instance, but suppose, I was updating and deleting objects as well?

1) If I have a reference to the cached object is it guaranteed to
remain in cache for the lifetime of my variable?
If I right interpret this question: responce is no.
cache.Add("key", new object()); // ADD KEY
var obj = cache["key"]; // GET REFERENCE TO CACHED OBJECT
cache.Remove("key"); // REMOVE OBJECT FROM CACHE
obj.DoSomething(..); //PERFECTLY VALID, STILL WORK ..
2) In the scanario outlined above, how do I go about ensuring
integrity? I'm only planning on adding in this instance, but suppose,
I was updating and deleting objects as well?
Can add bool property like, for example:
public bool IsValid
{
get; private set;
}
when object removed this property is set from the class to false. Just example, iff it really fits your need can tell us only you.

Do not pass around a reference to your cache!
Use an object for your cache and if a clients wants to have the cached items return a new list of your cached items, or a readonly collection.
If you want to add items to the cache, use a method on the cache object and in that method lock the cache and add the item. Same with remove.
question 1: If you pass around references you can not guarantee anything.
question 2: Use an object to cache all your items as I described above.
public class Cache
{
private List<Item> cachedItems = new List<Item>();
public void Add(Item item)
{
lock(cachedItems)
{
cachedItems.Add(item);
}
}
}

hello in order to ensure integrity, you must add key
Cache.Add("YourKey", yourValue)
here you can find helper for all operations
http://johnnycoder.com/blog/2008/12/10/c-cache-helper-class/
For duration or timeout you have this format, where you specify absoluteExpiration
public Object Add (string key, Object value, CacheDependency dependencies,
DateTime absoluteExpiration, TimeSpan slidingExpiration, CacheItemPriority
priority, CacheItemRemovedCallback onRemoveCallback)

Related

ASP.NET Cache - What's the difference between direct assignments and Add() or Insert()

I'm trying to understand the difference between these two items and what one (if any) is the "correct" way to do it.
I'd like to add an object to a cache. For example:
List<String> list = new List<String>();
list.Add("Monday");
list.Add("Tuesday");
list.Add("Wednesday");
list.Add("Thursday");
Now add the list to the cache. Do I do:
System.Web.HttpContext.Current.Cache.Insert("DaysOfTheWeek", list);
Or can I just do this?
System.Web.HttpContext.Current.Cache["DaysOfTheWeek"] = list;
I've done both, and they work fine. I'm wondering if this will blow up as this scales, or if it will have any consequences I'm not foreseeing.
This is in C#, ASP.NET 4.5
There is no difference. Using the indexer (the second example) just calls Insert anyway. You can see that in the reference source:
public object this[string key] {
get {
return Get(key);
}
set {
Insert(key, value);
}
}
Add is different from Insert in that Add will not overwrite a value in cache if the key already exists - Insert will replace an already cached value. This is mentioned in the documentation of Add:
Calls to this method will fail if an item with the same key parameter is already stored in the Cache. To overwrite an existing Cache item using the same key parameter, use the Insert method.

Proper way to update a dictionary that is constantly being updated/read?

I have a function that returns a Dictionary<uint, SomeClass> this function is called every second updating data to my list.
Right now, used like this to update my property:
MyData = Api.GetData();
And my property as:
public static Dictionary<uint, SomeClass> MyData { get; private set; }
Is that method fine to update my Dictionary or how should it be done?
I mean, the Dictionary is constantly being replaced as it is right now, right? So if I am using or updating any entry of that Dictionary say:
MyData[SomeValidKey].SomeProperty
My reference would become null or invalid? Or it would simple use a copy of it? Or this is something that would only have a chance to ever happen depending on how fast MyData is queried and the such?
What would be an optimal way to update my Dictionary, while allowing other parts of my application to freely access and use it?
The dictionary is mainly read only and/or call functions of a given item in the Dictionary that is part SomeClass.
UPDATE:
Since MyData = Api.GetData(); means the list is actually replaced? If so if an entry that previously existed no longer exist but any of my functions still had it in use, it would cause exceptions? If an item that was previously used is updated I would not have the updated data as my reference is dead?
So the way I am updating my Dictionary is clearly wrong?
If you're updating your Dictionary in a separate thread then you should use proper locking mechanism to ensure that you're reading the current value. Use lock for both read/write. Also there is a ConcurrentDictionary class in .NET 4 (or above) which is designed for concurrent operations.
But if you're using your dictionary in a single thread then you shouldn't worry about locking at all. Here is an example to demonstrate what happens when you change the reference to another someClass instance:
private class SomeClass
{
public string Name { get; set; }
}
...
Dictionary<uint, SomeClass> dic = new Dictionary<uint, SomeClass>
{
{ 1u, new SomeClass { Name = "1"}},
{ 2u, new SomeClass { Name = "2"}}
};
var sc1 = dic[1]; // sc1 refers to old instance of SomeClass
dic[1] = new SomeClass { Name = "new" }; // now we change the reference here
string oldName = sc1.Name; // oldName is still "1", because sc1 points to the old instance
Your question is different to your example. Your example states you are replacing your dictionary when you call your API. Your question corresponds to updating.
If you were to update your dictionary, then you can either assign the return of your Api call to a temporary dictionary, then transfer/add/delete values in MyData or pass MyData to your Api function and handle that functionality there. This would keep your references in tact if accessed from other parts of your application.
If this isn't possible, then you cannot guarantee that there aren't to be errors from other parts of your code when you replace your MyData object with your Api call. The easiest solution here would that you do not cache your MyData entry value but instead cache its key. Other parts of your application can then check if their cached key is valid and take appropriate action.

Create property object on demand or in constructor?

What is the best way of initializing objects for properties without setters in C#?
For example I have property of type UserData and I can initialize it:
In constructor
In getter
private UserData _user;
public UserData User
{
get
{
return _user?? (_user= new UserData ());
}
}
Initialize field:
private UserData _user = new UserData()
I found few similiar threads:
Create an object in the constructor or at top of the class
C# member variable initialization; best practice?
But it is consideration between 1st and 3rd option - no one thinks about 2nd option - do you know way? From some time it is my preffered option to get objects, but I wonder if there are some cons that I don't know.
Could you tell me what is the best option and what problem could make use of 2nd option?
It all depends on what you want to do with it, so there is definite answer for that.
One difference between 1+3 and 2 is predictability.
With 1+3, you know exactly where your object is created and at which point during instantiation of your class. That can be desirable in some circumstances.
With 2, you depend on external influences (who accesses the property at which time) to initialize the field.
With the delayed creation in approach 2 (only create the object if needed), you could save some time when creating an object of the containing class.
If the UserData's creation takes a lot of time, like, when you have to query a database for it, you might want to delay its creation until really necessary. The object that contains the UserData object is constructed faster since it doesn't need to wait for the UserData object to be created. If the property isn't always accessed, you might even get to completely avoid creating a UserData instance.
If you're simply using plain data, initializing the backing field at its definition (if possible) is preferred:
// when you create constructor N+1, no worries about forgetting to set the value
private UserData _userData = new UserData();
public UserData User
{
get { return _userData; }
}
If you need initialization to be deferred, your best option is using Lazy<T>:
private Lazy<UserData> _userData = new Lazy<UserData>(() => new UserData());
public UserData User
{
get { return _userData.Value; }
}
The constructor for Lazy<T> contains overloads which can address your thread safety needs:
None: access from multiple threads is "undefined behavior"
PublicationOnly: the first thread to complete initialization "wins"
ExecutionAndPublication: locks ensure only one thread initializes the value
One issue with #2 is if the property could be accessed by multiple threads you could potentially create two copies of the UserData object. An additional consideration with #2 is if UserData is expensive to create you will be paying the cost of creating that object when the property is accessed rather than when the containing object is created. That may or may not be desirable depending on your use case.

shared asp.net object as static or cache

What is the best method of storing a shared object in asp.net? It will get called multiple times per request on every request. Ive been using these two methods but Id like to know if there is a better way. I refresh this object once an hour.
public static List<ResourceObject> SharedResources = new List<ResourceObject>()
//OR
public static List<ResourceObject> SharedResources
{
get
{
List<ResourceObject> _sharedResources = HttpContext.Current.Cache["RedirectRoutes"] as List<ResourceObject>;
if (_sharedResources == null)
{
_sharedResources = LoadNewSharedResource();
HttpContext.Current.Cache["RedirectRoutes"] = _sharedResources;
}
return _redirectRoutes;
}
set
{
HttpContext.Current.Cache["RedirectRoutes"] = value;
}
}
If your object is changing frequently (i.e. hourly as you mentioned) then you'll be best to use the cache as it will be able to take care of flushing for you (assuming you pass the correct parameters when adding the value to the cache). If you use a static value it will not be cleared out every hour automatically so you'd need to implement the check yourself.
If this is, as it seems, an object that needs to persist across requests, then this is a perfectly good and reasonable way to achieve it. You may want to put the cached version in a local variable if it is being accessed multiple times within one call, to save retrieving it from the cache each time.
Is there a specific issue with caching it like that that you are concerned about?

Application_End() cannot access cache through HttpContext.Current.Cache[key]

I want to be able to maintain certain objects between application restarts.
To do that, I want to write specific cached items out to disk in Global.asax Application_End() function and re-load them back on Application_Start().
I currently have a cache helper class, which uses the following method to return the cached value:
return HttpContext.Current.Cache[key];
Problem: during Application_End(), HttpContext.Current is null since there is no web request (it's an automated cleanup procedure) - therefore, I cannot access .Cache[] to retrieve any of the items to save to disk.
Question: how can I access the cache items during Application_End()?
If you want to get access to cache object before it will be disposed, you need to use somethink like this to add object to cache:
Import namespace System.Web.Caching to your application where you are using adding objects to cache.
//Add callback method to delegate
var onRemove = new CacheItemRemovedCallback(RemovedCallback);
//Insert object to cache
HttpContext.Current.Cache.Insert("YourKey", YourValue, null, DateTime.Now.AddHours(12), Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, onRemove);
And when this object is going to be disposed will be called following method:
private void RemovedCallback(string key, object value, CacheItemRemovedReason reason)
{
//Use your logic here
//After this method cache object will be disposed
}
I strongly urge you to rethink your approach. You may want to describe specifics of what are you trying to do, so we might help you with that.
But if you are totally set on it, then you can simply save values on disk when you actually set them, i.e. your helper class would looks something like this:
public static class CacheHelper
{
public static void SetCache(string key, object value)
{
HttpContext.Current.Cache[key] = value;
if (key == "some special key")
WriteValueOnDisk(value);
}
}
You can access the cache through HttpRuntime.Cache when you don't have an HttpContext available. However, at Application_End, i believe the cache is already flushed.
The solution Dima Shmidt outlines would be the best approach to store your cached values. That is by adding your items to cache with a CacheItemRemovedCallback, and store the values to disk there.
As an alternative solution you could store the data in Application object (Application[key]) or simply create a static class and use it to keep your data within app - in this case the data would sill be available upon Application_End.

Categories