ASP.NET: Why is "_requestValueCollection" empty on PostBack? - asp.net

Why is "_requestValueCollection" empty on PostBack?
I have a really strange problem with post backs. In some cases on post backs (this.Request.RequestType == "POST") have null "_requestValueCollection" member. And for ASP.NET that means this.IsPostBack == false.
So I have modified the Page_Load in the following way:
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack && this.Request.RequestType != "POST")
{
//REGULAR INIT STUFF
}
else
{
//REGULAR SITE POSTBACK STUFF
}
}
What is possible danger of this approach? So far everything is doing OK (and is pretty rich and complicated page).

It isn't clear from your example what you are attempting to do with this code, so this is mostly a short in the dark.
You probably don't need the second part of the if statement. Checking IsPostBack alone should be sufficient.
_requestValueCollection is not a property, it is a field and probably isn't a good place to get at the data submitted by the client. I suggest instead that you consider using the Form property (this.Request.Form) or the Headers property (this.Request.Headers) depending on what you are looking for. Keep in mind that most of the time you can just get form values from the asp.net controls on the form directly.
You may also want to look at the Request.HttpMethod property if you need to determine the exact http method used to invoke the page.
Edit: Adding info about _requestValueCollection
The mechanics behind the _requestValueCollection being loaded are quite complex, but I took a look at the MS source and from what I can determine the page calls on every control on the page that implements the IPostBackDataHandler interface. For each of these it will call the LoadPostData method which adds the data for that control to the collection.
The main things that I can think of off the top of my head that might cause the collection to be null would be:
no server controls on the page implement IPostBackDataHandler
there is no server form, or the contents of the form weren't sent by the client
Alternately, the page may be using query strings to convey the data to the server, and the query string doesn't contain anything
As I said, this is a bit fuzzy. The Page class is very complex internally and so there could be other ways data gets put into that collection too, but this was all I could find on a casual examination.

Related

Should i make a call to DB or save value in viewstate

On asp.net page, I am using tabs and one of the tab has got user control on it.
On the first tab, data is being displayed from table A and the second tab (which has user control on it) is getting data from table B.
On the user control (second Tab), I need to show the column value of table A. It is just one string value.
I am wondering if there is any best way of displaying the value of a table A column without making a call to database?
The way code has been designed, I can’t access the user control’s textbox from the first tab.
I can only think of using view state or session but don’t know if I should use them instead of making call to DB.
I want value to live for the current page's lifecycle.
If you can save it in viewstate then go for it. But there are plenty of storage options in addition to just viewstate:
querystring (good for Ids, not great for strings)
cookie (pretty straight forward)
local storage (HTML 5 only)
cache (you could still appear to make the call but just have the results cached. you then have to deal with cache expiration as well)
session (as you mentioned, this is basically a per-person cache usage, but is not a bad option)
hidden field (basically what viewstate is)
Even with all of those options, the viewstate is going to be a pretty good one, but it just requires that you post back the viewstate every time you need that value.
How about using js to copy the data contents from tab1? Are you loading the usercontrols in tabs using ajax?
If you have a complex form and need to split into smaller chunks I would use a multiview control with as many views as you need to complete your task. If you design each view with its own controls, validation groups and logics .net will do the rest, you won't have to manually deal with states or saving middle steps
<asp:MultiView ID="MultiView1" runat="server">
<asp:View ID="View1" runat="server">
<asp:TextBox ID="txt1" runat="server" />
<asp:Button ID="Button1" runat="server" Text="Next" OnClick="NextStep_Click" />
</asp:View>
<asp:View ID="View2" runat="server">
<asp:TextBox ID="txt2" runat="server" />
<asp:Button ID="Button2" runat="server" Text="End" OnClick="EndProcess_Click" />
</asp:View>  
</asp:MultiView>
<asp:TextBox ID="txt3" runat="server" />
In code behind
protected void NextStep_Click(object sender, EventArgs e)
{
MultiView1.SetActiveView(View2);
txt2.Text = txt1.Text;
}
protected void EndProcess_Click(object sender, EventArgs e)
{
txt3.Text = txt1.Text + " " + txt2.Text;
}
you can go back and forth the times you want and won't have to worry with the values the users entered. Obviously, you have to put buttons to go back and just set the active view you want.

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.

How to hide asp.net querystring displayed in address bar as default.aspx?id=2&name=sanjay [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Removing a querystring from url in asp.net
How to hide asp.net querystring displayed in address bar as default.aspx?id=2&name=sanjay
If you want to hide the data passed in parameters in the query string.
Use a form and POST the information. This might require additional code in source pages, but should not require logic changes in the target pages (merely change Request.QueryString to Request.Form). While POST is not impossible to muck with, it's certainly less appealing than playing with QueryString parameters.
Use session variables to carry information from page to page. This is likely a more substantial effort compared to (1), because you will need to take session variable checking into account (e.g. the user might now have a difficult time navigating around using their Back and Forward buttons, if you are constantly checking state). You will also need to deal with the case where session cookies are not enabled (this solution will not work for these people).
Use "encoded" or non-sensical information in the QueryString in place of the real data. This will require the effort of creating an encoding and decoding scheme on either end of all page submissions. Sure, users can still experiment and reverse engineer your scheme, however they will be less likely to quickly come up with meaningful changes to the existing QueryString.
Use framesets. I really don't recommend this approach, though it is quite common. If you're trying to hide the information as opposed to making it more difficult to modify, users can still right-click the individual frames and click properties, in order to retrieve all of the information passed via QueryString.
Use Server.Transfer to move control to a second page, which will still have access to the QueryString parameters passed to the first page (the URL of which was visible only briefly)
You really need to POST the data -- directly to default.aspx, if possible. If the caller is a different page, this gets a little wonky with web forms, especially if you're relying on sitemap functionality. In any case, you could post the data using "cross page posting" or you could use "server.transfer". Using session state with a redirect is somewhat inefficient (an extra round trip for the client), but often expedient. So for example, the calling page may look like:
Web Form (caller):
<asp:LinkButton ID="LinkButton1" runat="server" OnClick="LinkButton1_Click">Click Me!</asp:LinkButton>
Code-behind (caller):
protected void LinkButton1_Click(object sender, EventArgs e)
{
Session["id"] = 2; // pull the data from the control or use OnCommand?
Session["name"] = "Sanjay";
Response.Redirect("~/Default.aspx");
}
And the receiving page, default.aspx would look like:
Web Form:
Name: <%=_name %>
<br />
Id: <%= _id %>
Code-Behind:
protected int? _id
{
get { return Session["id"] as int?; }
set { Session["id"] = value; }
}
protected string _name
{
get { return Session["name"] as string; }
set { Session["name"] = value; }
}
Good luck!

ASP.NET Caching - Programatically Invalidating Server Cache...confusion on example

I'm reading how to programmatically invalidate cached pages on the server in ASP.NET, and the book ("MCTS Self-Paced Traing Kit (Exam 70-515)") says:
To directly control whether a cached
version of a page is used or whether
the page is dynamically generated,
response to the ValidateCacheOutput
event and set a valid value for the
HttpValidationStatus attribute.
The code segments look like the following:
public static void ValidateCacheOutput(HttpContext context, Object data,
ref HttpValidationStatus status)
{
if (context.Request.QueryString["Status"] != null)
{
string pageStatus = context.Request.QueryString["Status"];
if (pageStatus == "invalid")
status = HttpValidationStatus.Invalid;
else if (pageStatus == "ignore")
status = HttpValidationStatus.IgnoreThisRequest;
else
status = HttpValidationStatus.Valid;
}
else
status = HttpValidationStatus.Valid;
}
protected void Page_Load(object sender, EventArgs e)
{
Response.Cache.AddValidationCallback(
new HttpCacheValidateHandler(ValidateCacheOutput),
null);
}
Could someone please explain to me what this code is doing? Also, the main question I have is that I thought Cached pages were simply returned from the server, but the code below indicates that the page life-cycle is being invoked (Page_Load event); I'm confused because the page life-cycle isn't invoked if a cached page is returned, so how would the code in the Page_Load event even fire?
Note: Here's the same example that the book has
I also came across this question. It is too bad that almost every blog post and article I find about this subject dutifully replicates the MSDN example without really explaining how it works.
I don't have a definite answer but I think this works because the page life cycle is invoked at least once. Namely when the page is requested for the first time and thus isn't cached yet.
During that first request the Page_Load is called and the HttpCacheValidateHandler is registered with the Cache object. During all subsequent request for that page, the Cache object is able to call your ValidateCacheOutput() method. And because this method is static the page life-cycle doesn't have to be invoked.
I hope that someone who knows more about this can comment on it but in my opinion this also implies the following:
In the given example the HttpCacheValidateHandler doesn't need to be a static method of the page because it doesn't use any properties of the Page object. It can be a static method on any other object you like.
The ValidateCacheOutput() method will probably be called for every page request, not just for the page which is (ab)used to call Response.Cache.AddValidationCallback(). Maybe i'm missing something obvious but I don't see how the Cache "knows" which HttpCacheValidateHandler belongs to which page.
You are right in that typically cached pages are just returned frm the server but this changes when you use AddValidationCallback. In this case, ASP.NET will call this method to determine whether to returned a cached copy or not. This method should therefore be very light or you will negate the effect of caching.
The code you have listed just checks the querystring for a Status variable and uses the value of this to determine whether to either (1) pull the page from the cache, (2) clear the cached page, re-render it and cache it or (3) just ignore the cache and re-render the page.
See http://msdn.microsoft.com/en-us/library/system.web.httpvalidationstatus.aspx for the status options.

Why not implement 'IsRefresh', 'IsBackPost' just like is 'IsPostBack'?

I could see, myself and many people are having trouble with this two items in ASP.NET... Refresh Button, Back Button... (I see many people went to the exent of asking how to disable these two buttons in the browser..)
Now what are the problems in Implementing two more boolean variables in Page (IsRefresh, IsPostBack)... If those problems can be circumvened and implemented, it would be a great asset to developers...
When you are answering, if you could also include the steps you are taking in your web app in order to avoid reposting (at times in DB) in such scenarios that would be helpful.
Thanks
The problem with implement the two additional boolean properties is, that there really is no (reliable) way to distinguish Back / Refresh triggered requests. When hitting on of these buttons, the browser will either:
display the page from the cache if allowed, or
execute the exact same request again (possibly asking the user to confirm first)
You are experiencing case #2. When the second request occurs, the server will recieve the exact same request data as it did with the original request. Thus, ASP.NET (and most other frameworks) will handle the request just like the original was handled. There are several ways to work around this problem:
Change your caching policy to allow the browser to redisplay the results of previous requests (might solve the Back problem, but not Refresh).
Add a hidden field (or data in the ViewState) containing a unique value on the page from where postbacks are expected. Then add some data structure to keep a list of "used" values, along with logic to test for duplicates before doing anything critical.
Use the Post/Redirect/Get pattern to ensure that the POST request never ends up in the browser history.
Solution #3 is dead easy, and works in almost every case. Basically, rather then returning the results/confirmation as a reply to the "critical" postback, do a redirect to a new URL:
protected void btnCritical_Click(object sender, EventArgs e)
{
DoSomethingThatShouldNotBeDoneTwice();
Response.Redirect("confirmation.aspx");
}
aspnet_isapi recognizes a postback from the form content, specifically the ViewState field. It has no intrinsic way to distinguish a postback from a refresh.
i have seen a few strategies for working with this in the past. One is to assign each request a guid and use that as a unique key or index in the table you are writing to.
You can create a base page that all of your pages inherit from.
public partial class PageBase : System.Web.UI.Page
{
private Guid _requestId;
protected Guid RequestId
{
get
{
return _requestId;
}
}
protected virtual void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
_requestId = Guid.NewGuid();
ViewState.Add("requestId", _requestId);
}
else
{
_requestId = (Guid)ViewState["requestId"];
}
}
}
public partial class _Default : PageBase
{
protected override void Page_Load(object sender, EventArgs e)
{
base.Page_Load(sender, e);
// now do stuff
}
}
It's not quite that clear cut. The only way the server can identify a "PostBack" is based on the headers passed to the page by your request. When you POST a form, "IsPostBack" is true, as you would expect. When you refresh a page or press Back the exact same request data is sent. There's no way for the application to detect that the user issued a non-standard request (Back or Refresh) without changing the behavior of the browser that sends the request.
As you know, most browsers will indicate to you that "Clicking Back will resend the form data...", but that is merely a warning issued by the browser to let you know that it is going to send the exact same request over again. The server does not know this and has no (native) way to interpret the information.
Double Postback Prevention Tips
One way to prevent data getting posted twice is to ensure that each PostBack contains some unique data that you can validate. The process is fairly simple.
On each page load you will want to create a unique identifier for that page's PostBack events. It doesn't matter what the unique id is, so long as it isn't the same on sequential page loads. Place that unique identifier in a hidden field on your page AND in the user's session (or a cookie). Then, on each PostBack validate that the cookie in the hidden field matches the value in the session. If the values match the PostBack is an original post to the page which can be processed accordingly. After performing the necessary operations you will then need to change the unique identifier in both locations again. This way, if the user should hit back and choose to "Resend Data", the hidden field will not match the session key and you can throw out the duplicate post data.

Resources