How do I cache a dataset to stop round trips to db? - c#

I am creating a search results page in C# in an ASP.NET 1.1 page. In my data layer I have a DataSet that stores the result of a plain old ADO.NET stored procedure call. The DataSet has two DataTables and I'm using a DataVIew to filter and sort the columns.
I only want to fill the dataset once, and then work on the DataTables and derived DataView until the page is unloaded.
How best should I cache the DataSet in my DAL so that it is filled only PageLoad? Do i put it in a Cache object, a static member variable, a property...I don't have any fancy entity models or ORM, this is .NET 1.1. Thanks in advance.

Will your DAL be used by any other applications? If not then you can imbed the caching of the DataSet in the Cache or Session depending on what features are need of the storage.
Session will be specific to the user and get cleaned up when the user's session expires which means the data might be around a lot longer than required. More info on Session
Cache is nice because it will auto expire (use sliding expiry if the search data will not change often) and you can store the search criteria with it so that other users can leverage the search as well which will save you calls to the DB by multiple users possibly. Multiple user's being able to access this data is a big advantage over using Session. More info on Cache
If you plan to use your DAL in other apap, you might want the application to do the caching itself.
You just need a wrapper like:
// Consider this psuedo code for using Cache
public DataSet GetMySearchData(string search)
{
// if it is in my cache already (notice search criteria is the cache key)
string cacheKey = "Search " + search;
if (Cache[cacheKey] != null)
{
return (DataSet)(Cache[cacheKey]);
}
else
{
DataSet result = yourDAL.DoSearch(search);
Cache[cacheKey].Insert(result); // There are more params needed here...
return result;
}
}

there are ORMs that work with .net 1.1, but if you don't want to use them, I would recommend either populating something in the Cache so that you can expire it if needed and re-get the data. You could also put it into the session (if the data is user specific) or application (if it is not) objects.

If this is per user data don't cache a large amount of data putting it into session or similar, you are seriously hindering the ability of your site to scale. Consider how the amount of info in memory grows as you add more users, and then what happens when you need to use more than a single site server.
Instead modify the procedure so you can only retrieve the page of data that you need to show.
If this is data that is used for all users, definitely cache it. You can use the asp.net Cache for that.

Related

How to define Variable similer to Session variable in ASP.NET

I want to define a variable or object like session, to stored data about each user, and i want to access this object in many pages,
could u please tell me if there is a way.
thanks
You have onlyy a few choices, really. URL parameters, hidden form inputs, cookies, session (be careful in a load-balanced scenario) or just store/retrieve stuff from a database. RaveDB is bloomin' brilliant for this because it's so fast and document-based.
You can store data in a cookie and then in your codebehind parse the specific cookie into something like a System.Collections.Generic.Dictionary
But you should use sessions.
Edit
IF if's a KeyValuePair<String,TValue> you can set Session[kvp.Key] = kvp.Value;, if not Session["KVP"] = kvp;
If u really don't want to use session use Database mind that this is a slow method...
i've had a few situations where I wanted to minimize/eliminate session storage (due to users being on a horrible wifi connection). to handle this situation I used an encrypted query string with only their ID in the string. in the base page I would decrypt the string and pull information I needed from the database. This information would be populated into objects that I defined and since the objects were in the base page I could access the information from any pages that inherited it.

Session instead of viewsate

I have found many questions here about storing values in viewstate, but haven't found a good answer.
I have a situation when i retrieve large amount of data from database. Then i filter and manipulate the data according to my needs (so it is a preety heavy process). Then I put the result inside a list of custom class. For example lets say this class will be Person
List<Person> persons = new List<Person>();
private void FillPersons()
{
//Call to webservice
persons = ws.GetPersonsList();
//Do all kind of custom filtering
//Manipulate the data
}
Now the whole FillPersons() method is a heavy process that returns pretty small amount of data. And unfortunately it can't be moved to SQL and the heaviness is in the process, but that is not the point.
The point is that i need to reuse this data on the page between post backs.
Right now in order to spare the additional call to FillPersons() I mark Person class as serializeable and store the list in the viewstate, that works fine except the fact that the page becomes 1mb size because of the viewstate. According to what i have read, it is not so acceptable approach i.e. it is not secure and it blows the source code making the page heavy etc. (second is what most concerns me)
So it leaves me with a session. However session is persisted not only between postbacks, but much after it, even when user leaves the page. Or worst- the session will end before user decide to postback. So finding the best time span for session lifetime is mission impossible.
My question is what is the best practice to reuse "datasets" between postbacks?
What you guys do in such cases?
Thanks.
PS: hidden fields etc. is not an option.
You can store this kind of data in the Cache. It is application wide, so depending on what you add use the key accordingly.
var key = UserID + "_personList";
Cache.Add(key, personList, null,
DateTime.Now.AddSeconds(60),
Cache.NoSlidingExpiration,
CacheItemPriority.High,
null);
Note that you can never assume that the data is in the cache (it might have been flushed) so always check if it returns null and than refill it.
Viewstate is not a good way of storing large objects. As you mentioned your page size will get bigger and every postback will take lots of time.
I would suggest using cache. By using cache your list wont be saved there till end of session and you can set how much time it should be stored there. For caching you may use HttpCache or some distibuted caching system like AppFabric or MemCached . This nuget package will help using these cache systems.
this link will help how to configure AppFabric.
I should edit with some code to make it more helpful.
https://bitbucket.org/glav/cacheadapter/wiki/Home
var cacheProvider = AppServices.Cache; // will pick cachadapter using web.config ( can be Http, Memory, AppFabric or MemCached)
var data1 = cacheProvider.Get<SomeData>("cache-key", DateTime.Now.AddSeconds(3), () =>
{
// This is the anonymous function which gets called if the data is not in the cache.
// This method is executed and whatever is returned, is added to the cache with the
// passed in expiry time.
Console.WriteLine("... => Adding data to the cache... 1st call");
var someData = new SomeData() { SomeText = "cache example1", SomeNumber = 1 };
return someData;
});
Other than a cache (good idea by Magnus), the only other way I can think of is to keep the results of your heavy operation stored in the database server.
You mention that it takes a lot of time to retrieve the data. Once done, store it in a purposely established table with some type of access key. Give that key to the browser and use it for pulling what pieces you need back out.
Of course, without knowing the full architecture it's really hard to give a solution. So, in order of preference:
Store it back in the database with a unique key for this user.
Store it in a remote cache
Store it in a local cache
Under no circumstance would I store it in the page (viewstate), cookie (sounds too big anyway), or in session.
Have you considered using ASP.NET caching?
You should choose a key that will suite your exact needs and you will have your data stored in the server memory. But keep in mind cache is application specific and is valid for all users.
If the data you process is not often changed, the processing algorithm doesn't depend on user specific settings and it is not critical to always have the latest data maybe this is the best option I can think of.
Store your filtered collection on disk in a file. Give the file the same name as a key you can store in viewstate. Use that key to retrieve the file on postbacks. In order to keep the file system from filling up, have two folders. Alternate the days for which folder you save the files to. That way you can wipe out the contents of the folder that is not being used that day. This method has extremely good performance, and can scale with a web farm if your folder locations are identified by a network path.
I think personlist is a shared object. Does everyone use the same list? You can store on Application.
Application["PersonList"] =persons;
persons = (List<"Person">)Application["PersonList"]
Or you can Store on Static class.
public static class PersonList { public static List<"Person"> Get {get;set;} }
You should write this code to Application_Start on Global.asax file
PersonList.Get = ws.GetPersonsList();
And you can get List by using this code
persons = PersonList.Get;

How to keep data through postbacks?

I am working on a ASP.NET/C# Website.
I am reading data from a database, saving it in a Dictionary
Dictionary<string, decimal> Results
and then binding it to a ASP.NET chart
PieChart.Series["Series"].Points.DataBind(Results, "Key", "Value", string.Empty);
I want to change the Label of a Point when I click a button.
protected void Button_Click(object sender, EventArgs e)
{
PieChart.Series["Series"].Points[0].Label = "abc"
}
But the problem when I click the button, a PostBack happens and the data saved in The "Results" Dictionnary is lost as well as the Chart.
Is there a way to , not lose the data when a postback happens without having to read from the database all over again?
Thank you for any help.
Yes Make use of ViewState to preserve data between postback.
public Dictionary<string, decimal> Results
{
get { return ViewState["Results"]; }
set { ViewState["Results"] = value; }
}
Note:
Check for the Null value of viewstate otherwise it will throw an Exception or Error
Some responders have suggested storing the data in ViewState. While this is custom in ASP.NET you need to make sure that you absolutely understand the implications if you want to go down that route, as it can really hurt performance. To this end I would recommend reading TRULY understanding ViewState.
Usually, storing datasets retrieved from the database in ViewState really hurts performance. Without knowing the details of your situation I would hazard a guess that you are better off just loading the data from the database on every request. Essentially, you have the option of a) serializing the data and sending the data to the client (who could be on a slow connection) or b) retrieving the data from the database, which is optimized for data retrieval and clever caching.
You can put the data in ViewState or Session to then be able to pull it out "on the other side".
A better solution than using the ViewState and passing this data back and forth from the client may be to create a client id that each is passed back and forth and keep a cache of this data on the server side, keyed by this id. That way you do not need to send this data from client to server each time, only the other way around.
This still sounds wrong to me, but it is a better solution than some of the other answers that would involve so much overhead due to the data back-and-forth.
In fact since you're only changing display information and, from your question, I don't believe you're actually processing this data in any way, it seems to me that this is really a job for some sort of javascript alongside of your ASP.NET page. I have never done this, but some basic googling did turn up some articles about this.
Instead of using ViewState, why dont you move your code for assigning value to the dictionary to a function and then call that function from page_load on every postback. This way you will not lose data from your chart.
I often use asp:HiddenField to store small amounts of non-secure data on the client side.
In the Page_Load() function you can set the hidden field value, and then you can read it back in functions that get called later.
Do not use this for secure data as the client user can do a View Source to see the data in the page if they wish.

Server side paging with MVCContrib grid

I have to use stored procedures to fetch and page data. This particular stored procedure has all sorts of parameters, including paging information. Obviously, paging needs to be done server side, one page of data needs to be fetched each time a user selects a new page.
I'm trying to get this work with MVCContrib, but it seems to me that the grid and its pager support only local paging and filtering. Number of available pages is determined by the number of already present items in the collection, or so it seems to me.
Is there a way to make MVCContrib work with server side paging?
There is a class called CustomPagination in MVCContrib. The constructor takes following arguments
(Enumerable<T> dataSource, int pageNumber, int pageSize, int totalItems)
Then you pass that to the Grid and Pager.
You'll need to implement the IPagination interface yourself, add a page parameter to your action method then pass this into your stored procedure to get the appropriate collection of items. Then populate each of the IPagination properties from this and your knowledge of how your stored procedure works.
If you want more concrete examples of this, a sample of your stored procedure (or cut down version of it) may be helpful.
"Number of available pages is determined by the number of already
present items in the collection, or so it seems to me."
Perhaps you're looking at samples that are using a flavour of LINQ. This does not necessarily mean that the entire collection is in memory. Also, even if they are in memory, I would still call this server side paging - To me, client side paging in a web application means javascript.
PS: this may help you get started, though by the sounds of it you will need to ignore the Entity Framework bits of it:
http://weblogs.asp.net/rajbk/archive/2010/05/08/asp-net-mvc-paging-sorting-filtering-using-the-mvccontrib-grid-and-pager.aspx
Where they use the "AsPagination()" extension you'll need to call your stored procedure and populate your own implementation of IPagination.

ASP.NET Server Side Viewstate

I have read some approaches to storing viewstate on the server:
Here is one
Here is another
But they are sort of complicated. I am looking for a way to persist an object without having to serialize it. I could use session state, but if a user opens more than one window, there could be overwrites of the object.
Is there a simple solution to this?
In this situation I would put store the object in the session using a unique key and tie the key to the page. All this can be abstracted into properties on the page class.
public string PersistanceKey
{
get {
if(ViewState["PersistanceKey"] == null)
ViewState["PersistanceKey"] = "Object" + Guid.NewGuid().ToString();
return (string)ViewState["PersistanceKey"];
}
}
public PersistanceObject Persistance
{
get {
if(Session[this.PersistanceKey] == null)
Session[this.PersistanceKey] = new PersistanceObject();
return (PersistanceObject)Session[this.PersistanceKey];
}
The different session keys would allow different objects on a per-page basis. Alternately, instead of using the Session object, you could consider using the application cache (the Cache object) to automatically remove stale entries out of memory, but this has its own caveats.
It should be noted that Joel's warnings on his answer about memory usage are entirely accurate. This might not be the best idea for low-memory, high-usage, or large-persistance-object scenarios.
I am looking for a way to persist an object without having to serialize it.
Be careful with that. This will have a dramatic impact on the memory use of your site, and memory use is often the biggest impediment to scalability.
Assign a number to each window the user might open. Append that number to the session key. You should also store the number somewhere in page (querystring or a hidden input) to be able to retrieve the appropriate session variable.

Categories

Resources