I am using webmethod which fetches data from database & storing it in a static variable so that next time it will not hit the database becoz the data is being accessed frequently. Creating static variable doesn't seem to be a proper solution what is an alernative to this scenario.
e.g
public static List<SupplierGridData> lstFullSupplierData;
public static List<SupplierGridData> GetProductData()
{
if (lstFullSupplierData == null)
{
//first time get data from database
lstFullSupplierData = new List<SupplierGridData>();
lstFullSupplierData = new POProcess().GetInquiryDetails();
}
else
{
//use lstFullSupplierData which holds data
}
}
What you want is caching:
http://msdn.microsoft.com/en-us/library/xsbfdd8c.aspx
More specifically, caching data:
http://msdn.microsoft.com/en-us/library/6hbbsfk6.aspx
There is also Session State:
http://msdn.microsoft.com/en-us/library/ms972429.aspx
This comes in the per-application and per-user guise. And you can also change the backing store of session state.
The easiest solution to this could be hitting the db once if(!this.IsPostBack) then burying that stuff in the viewstate of the page if it's not too much stuff (assuming you don't need to carry across other pages). Otherwise session or cache will do as other people are suggesting.
You need to store your data in session in order to not hit the database again.
http://msdn.microsoft.com/en-us/library/ms178581.aspx
Related
I'm working on asp.net mvc3 application. I guess it's described somewhere but a fast search didn't help much and also I get very diverse opinions on using Session variables but still I have a little time to make a decision.
The problem is that I have a razor view where in image gallery images are shown and user that has permissions can delete one or many images. However I can't delete each image at the time the user click the button, instead I have to collect the id's of the images that have been "deleted" from the user (I remove the span tag which holds the image) but the actual deleting is perform by service and I have to pass the service all the data at once.
All this is inside Html.BeginForm so the data is collected on submit and before that I need a way to store those values somehow. Using sessions seems the easiest way by now. I tried something like this :
public void DeletePicture(long documentImageID)
{
if (documentImageID != null)
{
Session["imagesIdForDeleting"] = documentImageID;
}
}
But with a simple debug I can not figure out first - how at all I can access the documentImageID value from the Session["imagesIdForDeleting"]. I don't know if it's just matter of syntax or I'm trying to make the things less complicated than they are in real. Also - I'm not sure if making something like this I'm actually saving all the values or I rewrite the previous value and always have only one value stored in the session variable. Anyways, Any help how to implement this right would be appreciated.
You can store list in Session.
e.g.
public void DeletePicture(long documentImageID)
{
if(Session["imagesIdForDeleting"] == null)
{
Session["imagesIdForDeleting"] = new List<long>();
}
if (documentImageID != null)
{
var list = (List<long >)Session["imagesIdForDeleting"];
list.Add(documentImageID);
}
}
I'm not sure if making something like this I'm actually saving all the
values or I rewrite the previous value and always have only one value
stored in the session variable.
Yes you are right about overwriting the stored value.
Use a typed list to store the images and put it in session.
public void DeletePicture(long documentImageID)
{
if (documentImageID != null)
{
if(Session["imagesIdForDeleting"]) == null
{
Session["imagesIdForDeleting"] = new List<long>();
}
((List<long>)Session["imagesIdForDeleting"]).Add( documentImageID);
}
}
I have an ASP.NET MVC 3 app that is basically just a set of web services. These web services are exposed by a set of Controller actions. Each controller action queries my database. Because my data rarely changes, and, stale data is not a concern, I thought i would implement some cacheing to improve performance. My goals are:
Never cache a response to a user.
Cache the database records for up to 24 hours. If 24 hours has passed, hit the database again.
Does that make sense? I know how to prevent the response from caching. I just use the following:
HttpContext.Response.Cache.SetCacheability(cacheability)
However, I'm not sure how to cache my database records in memory for up to 24 hours. Does anyone have any suggestions on how to do this? I'm not even sure where to look.
Thank you
You can use the System.Runtime.Caching namespace (or the ASP.NET cache, but this is older and can only be used within web applications).
Here's a sample function which you can use to wrap around your current data retrieval mechanism. You can alter the parameters in MemoryCache.Add to control how much it's cached, but you requested 24h above.
using System.Runtime.Caching; // At top of file
public IEnumerable<MyDataObject> GetData()
{
IEnumerable<MyDataObject> data = MemoryCache.Default.Get(MYCACHEKEY) as IEnumerable<MyDataObject>;
if (data == null)
{
data = // actually get your data from the database here
MemoryCache.Default.Add(MYCACHEKEY, data, DateTimeOffset.Now.AddHours(24));
}
return data;
}
As mentioned by #Bond, you may also wish to look at using an SQL Cache Dependency if the data you're caching is likely to change within the 24 hours. If it's pretty static though, this will do what you asked.
The MVC framework is persistence-agnostic. There are no built-in means to store data, so there are no built-in means to cache stored data.
The OutputCache attribute can be used to cache a server response. But you explicitly stated that that's not something you want to do.
However, you may still be able to use the built-in OutputCache if you want to stay within the MVC framework. Consider exposing the data you want to cache as a JSON result
[OutputCache(Duration = 86400)]
public JsonResult GetMyData() {
var results = QueryResults();
return Json(results);
}
The JSON string at /ControllerName/GetMyData will be cached for 24 hours, so the actual query will only be ran once per day. That means you'd have to implement an AJAX call on your final page, or make another HTTP call from your server. Neither of those are ideal.
I would look for another solution to your problem outside of the MVC framework. Consider memcached, which was created for exactly this purpose.
What you are talking about is not exactly MVC responsibility. ASP.Net allow you to cahce only the things it produces (and this they are responces, obviosly).
If you want to cache data it can be better to cachet it the same place it was produced - somewhere in BL or Data Layer.
You can do something like that:
public class DataCacher
{
private static String data;
private static DateTime updateTime;
private DataCacher() { }
public static String Data
{
get
{
if (data == null || updateTime > DateTime.Now)
{
data = "Insert method that requests your data form DB here: GetData()";
updateTime = DateTime.Now.AddDays(1);
}
return data;
}
}
}
String data presents your actual data here. After adding this class replace your GetData() methods with DataCacher.Data.
Hope it helps or at least leads you to some further thinking.
If you're using MSSQL you may want to look at SQL Cache Dependency.
I'm not sure if you can configure cache expiration to 24 hours but with the cache dependency you may not need to - it will invalidate the cache as soon as there is an update on the database(i.e. should be more efficient than the time expiration strategy).
Here is a good article which discusses several performance related practices for ASP.NET MVC 3 and caching is mentioned.
I have looked at this question first: retain value after page refresh. But it seems like it doesn't work with collections because the ViewState only store one value. I need to use the collection because I do not know how many instances of object the user will create. Therefore, the ViewState is not an option. I also tried using static variables but it stores the values for longer than I need it (I found the explanation for this here: http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/3664cd62-46c7-4098-88a7-c09647673096).
I would massively appreciate your help.
Often using Session state is better for lare objects, but you can store any serializable objects in the ViewState too ( http://msdn.microsoft.com/en-us/library/ms972976.aspx ).
Note: please avoid using storing data in static properties in ASP.Net as the values are shared across all requests. Note on note - HttpContext.Current is not really static objects (per-request object).
You could store the List<> instance in the client session on the server side. Then on each request you will have access to the list in the session.
However, you should still be able to use viewstate, as long as the items in your List<> are serializable.
You should consider the amount of data being exchanged between the browser and web server when using viewstate. If your items are not unreasonably large and you will not have too many of them in the list then viewstate might not be unreasonable.
The code might look something like this.
private ArrayList GlobalList
{
get
{
return ViewState["GlobalList"];
}
set
{
ViewState["GlobalList"] = value;
}
}
you can use class level variable which hold the value after post if you want to use List make it class level variable then it wont loose the value.
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?
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.