Cache user control - asp.net

The problem of ouputcaching is avoiding accessing the object, it is cached and it will not be processed at ALL and it is a HTML. for example, what if I want to post back to initialize countries drop down list with specific selection, I don't want to go back and rebuild the whole control and rebind to a collection of countries to just intialize the contol to a certain country.
Output caching will not solve the problem because it caches the HTML, not the object, the object will be null, I can't manipulate it.
Is there away to cache the server object rather than caching its output html?
If u don't think this is possible please reply back, so I know that it is impossible if alot of people say so.
Thanks

It's quite possible - just use the HttpRuntime cache:
HttpRuntime.Cache.Add("myKey", myCountryList);
And then fetch the object back out:
CountryList myCountryList = HttpRuntime.Cache["myKey"] as CountryList;
if(myCountryList == null)
{
//the object isn't in cache
}
This is the most simple usage - the cache is fairly robust and supports some more complex behaviors like invalidation, callbacks, etc. which is all covered in the link above.

Related

Modifying item in viewstate - is it safe to do?

I'm still a relative noob, however I was surprised at the results of a small test I did.
I want to store a list of string in viewstate. To date when I want to modify the list I retrieved it from viewstate, performed a List.Add and saved it back to viewstate.
However, I then decided to do a simple test, here it is below:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<string> s = new List<string>();
s.Add("abc");
s.Add("def");
ViewState.Add("test", s);
s.Add("one");
s.Add("two");
}
var t = (List<string>)ViewState["test"];
foreach (var str in t)
{
Response.Write(str + "<br>");
}
}
As you can see, I create a list, add it to viewstate, then modify the list. To my suprise the list is modified in viewstate , even after postback.
The question is, is it safe to do this, and if so is it considered bad practice.
Thanks in advance.
ViewState is only serialized to the client page at the time of postback.
Previous to that, it is held in memory and safe for editing.
I often use ViewState as a backer to a property:
public Class1 MyClass1
{
get { return (Class1)ViewState["MyClass1"]; }
set { ViewState["MyClass1"] = value; }
}
In general, I would not consider it bad practice to do so, except for the following:
Storing sensitive data - Since data is serialized to the client, it is susceptible to being changed.
Large amounts of data - Since the data is persisted to the client, it will increase the page load times significantly for large amounts.
The reason you're seeing this is due to the Asp.Net WebForms page life cycle. At the point you're modifying the view state, Asp.Net has not yet rendered the page output as HTML. Since you're adding a reference to a dictionary, and changes you make prior to rending will show up. There are other points in the life cycle where such changes might not show up, although I've not investigated to see if that's the case or not.
I would not consider this good practice however. ViewState is serialized as a hidden form field in your web page, and thus any data in it is part of your page. This can at best just increase the size of the response sent to the client (sometimes significantly, if you store a lot of data there). Since it's a hidden form field, the request back to the server is also larger.
It can also open up security holes. You cannot trust necessarly trust view state, although there are ways you can secure it, but I would say its better not to send any data at all you don't absolutely need to render the page.
As an alternative, you may consider storing state that is specific to the user in Session, although you do need to take some extra effort if you're application will be behind a load balancer in a web farm. Storing the data in session will keep it isolated from other users and won't require exposing the data at all to the client.
Kind of subjective, but I don't see anything wrong with this by practice. This is something that happens all the time within different form controls on the page. The controls will edit viewstate information pertaining to themselves and persist that over postback. The reason the list changes in the viewstate when you modify it after adding it to the viewstate is that it doesn't get immediately serialized. The list is passed by reference to the viewstate collection where it sits until the page serializes the viewstate shortly before completing the request.

Storing data in AppState and Session

In my AppStart.cshtml I fetch some data from the database, do calculations, serialize/deserialize json strings and such, etc, and I store the result in a couple AppState-variables by doing something like the following:(C#)
AppState["myVar1"]="aString";
AppState["myVar2"]=anArray;
These variables are accessed frequently and are a bit heavy to define so I thought something like this would make sense rather than creating the data from scratch every time it's needed. Even if the optimization isn't needed it still makes sense to me since it also increases readability and definitely maintainability by not having the same code in a bunch of places where that data is needed.
Likewise, I do similar actions on a per-user basis by putting data in Session whenver a user logs in, e.g.
Session["userVar1"]="myString";
Session["userVar2"]=myAray;
However, I've just read that we should never rely on that the data stored in these still exist when we want to read them because they're stored in the server-memory which might have been cleared.
Is this true?
So when we want to access one of these we should first check whether it's null or not? And if we're lucky it's not null and we can use it straight away, otherwise we set it again.
Is this how data stored in AppState and Session are supposed to be used? And if so, what would be a good way of re-setting them if they're null? I suppose doing something like creating a function which sets them if they're null?
In your case it sounds like it's fine if the data is occasionally cleared by the server (re-starting the app process from IIS, for example) because what you've described is just a caching scenario. Cache data is inherently transient. If it's there, use it. If it's not there, re-fetch it (and populate the cache again with the result).
What I would suggest is abstracting your cache mechanism (app state and session state) from the structure of the cache itself. And within this structure you can check if the data is cached and, if not, re-cache it. Consider an object like this:
public class CacheManager
{
public static string MyString
{
get
{
if (string.IsNullOrWhiteSpace(AppState["myVar1"]))
{
// Fetch the value to be cached and set it in AppState["myVar1"]
}
return AppState["myVar1"];
}
}
}
Now anywhere in your application you can get the value by calling:
CacheManager.MyString
The rest of the application doesn't know or care if it's from app state, or session state, or a database, or a file, or any other transient location for cached data. That's entirely handled by the cache manager object. So if you ever want to change where certain values are located, you change them in that one place. Or if, for testing purposes, you want to remove the cache entirely and always get the data live, you'd just swap out the cache manager implementation with one that always returns re-fetched data. The rest of the application is blissfully unaware of the implementation.

Pass list of ids between forms

I have an ASP.NET c# project.
I have to pass a list of values (id numbers such as "23,4455,21,2,765,...) from one form to another. Since QueryString is not possible because the list could be long, which is the best way to do it?
Thanks in advance.
Thanks for all your answers, you are helping a lot !!!
I decided to do this:
On the first form:
List lRecipients = new List();
.....
Session["Recipients"] = lRecipients;
On the final form:
List lRecipients = (List)Session["Recipients"];
Session.Remove("Recipients");
You could use Session collection.
In the first page, use:
List<int> listOfInts = new List<int>();
...
Session["someKey"] = listOfInts
And in the second page, retrieve it like this:
List<int> listOfInts = Session["someKey"] as List<int>;
If your using asp.net webforms you can put it into a session variable to pass stuff from page to page. You've got to be concise of the potential performance issues of putting lots of stuff into session mind.
Session["ListOfStff"] = "15,25,44.etc";
There are any number of ways to pass this data. Which you choose will depend on your environment.
Session state is useful, but is constrained by the number of concurrent users on the system and the amount of available memory on the server. Consider this when deciding whether or not to use Session state. If you do choose session state for this operation, be sure to remove the data when you're done processing the request.
You could use a hidden input field, with runat="server" applied to it. This will make its data available server-side, and it will only last for the duration of the request. The pros of this technique are that it's accessible to both the server code and the client-side JavaScript. However, it also means that the size of your request is increased, and it may take more work to get the data where you want it (and back out).
Depending on how much data's involved, you could implement a web service to serialize the data to a temporary storage medium (say, a database table), and get back a "request handle." Then, you could pass the request handle on the query string to the next form and it could use the "handle" to fetch the data from your medium.
There are all kinds of different ways to deal with this scenario, but the best choice will depend on your environment, time to develop, and costs.
For Asp.NET MVC you can use ViewData.
ViewData["ID"] = "";

How to save value across postbacks for a composite control without using viewstate

I have a composite control that has a couple of private fields that reference values in the cache and these private fields are called during the constructor method. Since a string key is used to identify the value in the cache, I must have a way of storing that string key in such a way that it is available at the time the control is instantiated, and I have to be able to reference it on postbacks without it changing.
In addition, this key is generated the first time the control is loaded, but it should not be changed again after that first time.
How can I accomplish this?
I have already tried saving it to viewstate, but that doesn't work because viewstate is not yet available at the time the control is instantiated.
I have tried using a private field and then checking against Page.IsPostback in the constructor and if it isn't postback, I assign a value to the private field, but on subsequent postbacks it looses it's value, and I can't reassign it in the Page.IsPostBack again because it is an autogenerated GUID.
This has got to be something folks have had to do before....
There isn't a lot of state info available during control construction at all, so this could be difficult. Is there some reason you can't move your code which accesses the Cache'ed info into the control's Init event?
I assume you can't use Session because the information stored is related to that specific request/postback. If it's not specific to that request, using Session could be a possibility - but I think you may encounter other problems trying to deal with control state so early in the lifetime.
After seeing your comment to the other answer; you should be able to move your code that checks for the cached datasource into the control's Init or even Load event, so the state will be available.
Also, incidentally; are you sure you really need to cache this data? That could end up taking up a lot of server memory.
Have you tried Session?
You can store anything you like in the session object for one particular user, maintaining the value / object between postbacks.
If you want to store on a global basis and not per ser basis, try Application
Although this isn't the best solution (rearranging your logic to fit the lifecycle model generally is), have you tried accessing the Request directly? I once really wanted to get the selected value off a DropDownList very early in the lifecycle so I could adjust some elements in the building, and I did it like this:
myDropDownList.SelectedValue = Page.Request.Form[myDropDownList.UniqueID];
So instead of waiting for the viewstate to load the server-side proxie's values, I just got it myself from the client-side control value that was passed in on the post. I probably would do things differently if I redesigned that page, but it seems to have worked out alright for now and it solved the problem I was having.

What is the best alternative for QueryString

We heard a lot about the vulnerabilities of using QueryStrings and the possible attacks.
Aside from that, yesterday, an error irritated me so much that i just decide to stop using QueryStrings, i was passing something like:
Dim url As String = "pageName.aspx?type=3&st=34&am=87&m=9"
I tried to
Response.Write(url)
in the redirecting page, it printed the "type" as 3, then i tried it in the target page, it printed 3,0....i know this can be easily dealt with, but why? i mean why should i pass 3 and have to check for 3.0 in the next page's load to take my action accordingly???
So what should we use? what is the safest way to pass variables, parameters...etc to the next page?
You could use Cross-Page Postbacks.
Check also this article:
How to: Pass Values Between ASP.NET Web Pages
There are many options you can use, most of them requires you to build a strategy to pass variables between pages.
In most projects I use this strategy, I create a formVariables class to hold currently active items. it has properties which you will need to pass by querystring. and I store this class at session. and in my base page I read it from session. so in every page I get values over this object. the only negative thing about this method is to clean up items when you finished your work on it..
hope this helps.
I would sugest you avoid using Session to pass variables between pages as this breaks the stateless model of the web.
if you have just stored some values in session that relate to a certain page then the user uses their browsers back button to go back to the same page whcih should have a different state then you are not going to know about it.
It leads to the possibility of reading session values that are not relevant to the page the user is currently viewing - Which is potentially very confusing for the end user.
You will also run into issues with session expiration if you rely on it too much.
I personally try to avoid using session where possible in preference of hidden form values + query strings that can be read on postback + navigation.
The best / most secure way to pass info between pages is to use the session.
// On page 1:
this.Session["type"] = 3;
// On Page 2:
int type = (int)this.Session["type"];
You can store any kind of object in the session and it is stored on the server side, so the user can't manipulate it like a query string, viewstate, or hidden field
You said:
it printed 3,0....i know this can be easily dealt with, but why? i mean why should i pass 3 and have to check for 3.0
There's a difference between "3,0" (three comma oh) and "3.0" (three point oh). You also said that you were "passing something like".
In a query string, if you pass multiple values in the same key, they will be seperated with commas.
As all values are passed as strings there's no way that an int "3" is going to magically become decimal "3.0" unless you parse it as such when you request it.
I'd go back and double check what you are passing into your URL, if it ends up as something like:
pageName.aspx?type=3&st=34&am=87&m=9&type=0
Then when you read back
Request.QueryString["type"]
You'll get "3,0" back as the comma seperated list of values in that key.
First, in asp .net you can use several strategys to pass values between pages. You have viewstate too, however the viewstate store the value and the use is in different scenarios , you can use it too. Sessions instead, and of course by post in a form.
If your problem is the security, I recommended you to create 2 users for accesing the data. One user with read only access, this for accessing the pages ( Sql Inyection prevent ) and validate the data throw the querystring. And One with write access for your private zone.
Sorry, for my unreadeable English.
I like to use query string as I like users to be able to bookmark things like common searches and the like. E.g. if a page can work stand-alone then I like to it to be able to work stand-alone.
Using session/cross-page postbacks is cool if you needed to come from another page for the page you're on to make sense, but otherwise I generally find querystrings to be the better solution.
Just remember that query strings are unvalidated input and treat them with the caution you would treat any unvalidated input.
If you do proper security checks on each page load then the querystring is fine and most flexible IMHO.
They provide the most flexibility as the entry poitn to a page is not dependant on the sender as in some other options. You can call a page from any point within your own app or externally if needed via querystrings. They can also be bookmarked and manually modified for testing or direct manipulation.
Again the key is adding proper security and validation to the querystring, and not processing it blindly. Keep in mind that the seucirty goes beyond having edit or read access, depending on the data and user, they may not have access to the data with thos paranters at all, in cases where data is owned and private to specific users.
We have tried various methods, in an attempt to hide the querystring but in the end have gone back to it, as it is easier to do, debug, and manage.

Resources