How to keep data through postbacks? - c#

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.

Related

MVC - Retain model result for use in ajax method without passing in via JSON?

Long time lurker first time posting, so hey!
TL:DR - how would I keep a value from the original page-loading-controller to the ajax method without passing it in as a json object as part of the ajax request? And I can't use Session[]!
Backstory - I'm working on a filter-search functionality which brings back a big list of objects on the initial page load, generated from a database call and populates Model.FullResults.
In order to filter the results, rather than keep doing more database calls each time a filter is clicked, I'm simply filtering the results via linq in an AJAX method, like so:
var fullResults = #Html.Raw(Json.Encode(Model.FullResults));
var obj = {
//filter tickboxes statuses etc are here
fullResults: fullResults
}
var jqxhr = $.ajax({
//urls etc removed for clarity
data: JSON.stringify(obj),
success: function (response) {
//stuff
}
}
});
Which is all working perfectly fine for small values of Model.FullResults. However, if Model.FullResults is pretty large (i.e. on my main search page), this is a large amount of data to pass across via ajax each time, and the only reason I'm even passing it across this way is just for the plain and simple fact of I don't know how else I can "keep" this data from the original controller action and still have it for use the ajax method.
Storing Model.FullResults in Session was a brief thought, but there's a high probability people will open multiple tabs that hit the same controller, thus making session outdated. Something like Viewdata would be ideal but I can't access that in the ajax method of course.
So how would I keep this value for use in the ajax method? Do I have to resort to doing another database call OR passing it into the ajax method? There must be a way of retaining it somehow?
Thanks in advance you helpful bunch! :)
You can go for memoryCache to save large amount of data. Similer problem was with me where I have to read data from csv file and pass through Web API. Every-time, reading data from text was not a good idea, So I saved data in memory cache and fetching the records from memoryCache to avoid reading from stream. A simple demo is shown on my github account.you can co relate it.
https://github.com/abhee235/SimpleRestfulAPI/tree/master/DataProvider
Note : The project is not optimized for performance point of view. It is just a demo.

c# static Data Dictionary lingering when source data changes - even across IIS users

I have an online store and the software is highly customized but not completely ours. We sell tours and some of them have reservations so I added a calendar to let them pick the date/time they want. Originally each cal_SelectionChanged() call was looking stuff up from the store database and that was, of course, horribly slow. I wanted to use a Data Dictionary to get the information once and use it whenever needed.
I have this class:
public partial class ConLib_Custom_BuyTourProductDialog : System.Web.UI.UserControl
and this declared inside that class.
static Dictionary<string, string> CustomFieldDict = new Dictionary<string, string>();
I also have a function to load all the bits from a database that I'll need on my page. My plan was to call this on Page_Load() and just access the info when needed.
protected void LoadCustomFieldDictionary()
{
string _sku = _Product.Sku.Trim().ToLower();
if (CustomFieldDict.ContainsKey("Sku"))
{
// is the dictionary entry for *this* sku?
if (CustomFieldDict["Sku"] == _sku)
{
return; // already have this one.
}
}
CustomFieldDict["Sku"] = _sku;
CustomFieldDict["EventId"] = TTAUtils.GetCustomFieldValue(_Product, "EventId");
CustomFieldDict["ResEventTypeId"] = TTAUtils.GetCustomFieldValue(_Product, "ResEventTypeId");
etc.
}
Then my boss loaded a page - ok, everything was fine - and changed one of the bits of data in the database to point to a different, wrong, ResEventTypeId. Reload the page and it has the new data. He changed it back to the original and it was "stuck" on the wrong information. I loaded a browser on my iPad and went there and it fed me the wrong info as well.
It seems that the server is caching that DataDictionary and even if we change the database all visitors, even in other sessions, get this cached wrong info.
Do you think this assessment is right?
What's the proper way to do this so that a visitor changing dates gets some kind of cached lookup speed and yet another browser gets a fresh set from the database?
How do I make it "forget" what it thinks it knows and accept the new info until I fix it? Reset IIS?
Thankfully this is on a dev server and not my live store!
Thanks for your help. I've learned a lot about C# and .NET but it's shade-tree-mechanic type stuff and I lack the formal training that is out there and would really help in situations like these. Any help is appreciated!
For anyone coming by at a later time:
What Jonesy said is very true - statics are scary. I found out from one site (link to a link from his link) that statics like this are sticky to the Application Pool level so any other browser would get the "wrong" information.
For my situation I decided to use ViewState to store the info since it was small and my current V.S. isn't very large already. Beware doing this for large amounts of data but in my case it was the best.

Data Persistence across ASP.NET postbacks

Context:
I've often been in situations where our ASP.NET pages would have to show data to the user on a GridView, let him change it as he pleases (Textbox on cells) and only save it to the database when he actually hits the "Save Button". This data is usually a virtual state of the information on the page, meaning that the user can change everything without really saving it until he hits the "Save Button".
In those cases, there's always list of data that needs to be persisted across ASP.NET Postbacks. This data could be an instance of a DataTable or just some List<Someclass>.
I often see people implementing this and persisting the data on Session. On that cases i also usually see problems when it comes to some user navigating with multiple tabs open, some times on the same page. Where the data of two different tabs would get merged and cause problems of information being scrambled.
Example of how Session is often used:
private List<SomeClass> DataList
{
get
{
return Session["SomeKey"] as List<SomeClass>;
}
set
{
Session["SomeKey"] = value;
}
}
People often tries to solve it by doing something like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DataList = null
}
else
{
FillGridView(DataList);
}
}
But what about when two tabs are already loaded and the user is changing the GridView values and for some weird reason he tries to save the data by hitting the Save button on the other page? I personally dislike this option.
Other ways to do this would be to put the data on ViewState. However, when it comes to persisting substantially big lists, it could impact the page heavily when it's stored on the page (HiddenField).
But, what's the best way to make that work? Once, i thought in using Session together with ViewState where the ViewState would hold an unique identifier which would index the Session saved data. That would prevent sharing the data between tabs on the browser:
private List<SomeClass> DataList
{
get
{
if (ViewState["SomeKey"] == null)
{
ViewState["SomeKey"] = Guid.NewGuid().ToString();
}
return Session[ViewState["SomeKey"].ToString()] as List<SomeClass>;
}
set {
if (ViewState["SomeKey"] == null)
{
ViewState["SomeKey"] = Guid.NewGuid().ToString();
}
Session[ViewState["SomeKey"].ToString()] = value;
}
}
On the other hand it would store a new list of data to the Session every time the user enters the page. Which would impact the server memory. Maybe they could be erased in some way.
Question:
What would be the best way of persisting that kind of data across Postbacks, considering the contexts of multiple tabs on the browser, with the less cost to the server and to the maintenance coding team?
Update:
As #nunespascal nicely posted, one option would be to store the ViewState in the Session using the SessionPageStatePersister. But unfortunately that's not an option on my case. And yet it is not very different from my last example, saving the data on the Session indexed by an UniqueId stored on the ViewState.
Would there be any other options?
There is a simple solution to that problem. Store the ViewState in the Session.
For that you need to use the SessionPageStatePersister
Refer: Page State Persister
All you need to do is override the PageStatePersister and make it use SessionPageStatePersister instead of the default HiddenFieldPageStatePersister
protected override PageStatePersister PageStatePersister
{
get
{
return new SessionPageStatePersister(this);
}
}
This even saves you the headache of maintaining a unique key. A hidden field will be used automatically to keep a unique key per instance of the page.
I've come across a similar situation. The idea is if you allow long sessions for each user to change the grid view, this means you'll also have a concurrency problem because eventually you will accept only one last set of modifications to your data.
So, my solution was, to allow changes on the database but make sure all the users see the same state via SignalR.
Now, the concurrency problem has disappeared but you still need to make the changes on the fly. You might not want to save the changes after all. I've solved this problem by applying the command design pattern. Now any set of changes can either be approved or discarded. Whenever you check the index you will see the last approved gridview. Go to update page and you see the live-updated gridview. Also, go to revisions to see old approved gridview -another advantages of command design pattern-.

Response.direct to a specific instance of a page

What i want:
pass values to public properties in a Page and call that specific instance, i cant use query variables coz that can be manipulated, also there are a lot of properties so keeping in session would be memory intensive, is there any way to assign the properties to the page and response.redirect to the page.
I had a look at the following post but dint get much of any idea.
Response.Redirect to Class that inherits from UI.Page?
Does anybody know any solution thanks
If you are not worried about SEO on the second/new page you could try Server.Transfer
http://msdn.microsoft.com/en-us/library/ie/ms525800(v=vs.90).aspx
Yes you can use query by encrypt it. Do not make you life so difficult with complex thinks, just encrypt it, and decrypt it with error checking and that's all.
here is a sample code for encrypting query strings:
http://www.codeproject.com/Articles/33350/Encrypting-Query-Strings
you can also make a cross-page postback that check for the valid of the data, see this example:
Cross-page postbacks and back again retaining data from source page

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;

Categories

Resources