Update: the clearest explanation I have found on the web as I have been struggling through this can be found here.
Maybe I just don't understand the model of runat server terribly well. It appears the following code is always executing the if block. If the code is running on the server side I guess I can understand that it has to be stateless.
I am a seasoned non-web programmer but it appears counter intuitive to me. Will I need to create some sort of session object or pass the current state along in the URL or what?
<script runat="server">
DateTime begin;
DateTime end;
int iSelectedStart = 0;
int iSelectedEnd = 0;
int iPutName = 0;
protected void Button1_Click(object sender, EventArgs e)
{
if (iPutName == 0)
{
iPutName = 1;
Label1.Text = TextBox1.Text + " you will be slecting your start and end dates.";
It looks like part of your code got cut off, but here's the basic thing with web programming -- it's stateless. Unless, that is, you do something (use ViewState, Session, etc.) to add some state into the mix.
In your case, it looks like you want to maintain some state through refreshes of the page. Put the values you want to preserve in ViewState to keep them across postbacks to the same page. If you want to hold values across pages on your site, use Session. If you want to maintain values across visits to the site, put them in a database and tie them to a login or cookie.
The important thing to remember here is that the web is stateless. Each request from a person's browser is completely separate from all previous requests. What's happening with your code is that the class is being instantiated from scratch each time the client requests a page. That includes clicking Button1.
If you want values to persist between requests, you have to store it in a location where it can be retrieved later. The Session object provides this for you.
Basically, you'll need to store the iPutName variable in the session somehow. Probably the nicest way is to encapsulate it in a property:
protected int iPutName
{
get {
if (Session["iPutName"] == null)
Session["iPutName"] == 0;
return Session["iPutName"];
}
set { Session["iPutName"] = value; }
}
Edit: The ViewState object will work as well (as long as ViewState is turned on on the page). This encodes the value in a hidden field in the HTML and decodes it when it comes back.
Edit (again): Apologies for repeated edits, but I should clear this up. What Jonathan and Emil have said is correct. You should probably be using ViewState for this rather than Session unless you want this value to remain accessible between pages. Note that this does require that ViewState is turned on and it will result in a larger payload being sent to the client.
I really recommend to look at the quick start tutorial.
http://quickstarts.asp.net/QuickStartv20/aspnet/Default.aspx
There are a lot of concepts in dot net to simulate state on the UI.
In your case I think what you really want to do is using viewstate. Sessions should be used with care and I think the concept you are looking for i localized to the page not to the entier user session.
You should also look at the concept codebehind/codefront as well.
Because ASP.NET is stateless what you're assuming is correct. The postback will cause the page to lose the variable for iPutName. Storing in session is one option, or storing in viewstate could be another option.
The main thing to understand here is how the ASP.NET page lifecycle works and what happens each time you post back to the server.
For the lifecycle, check out the following URL :
http://www.eggheadcafe.com/articles/20051227.asp
You can store your iPutName in the session by doing this :
Session["iPutName"] = iPutName;
Fetching the session variable is also easy, but you should be sure to do a NULL check, like this:
if (Session["iPutName"] != null) iPutName = Session["iPutName"];
Haven't tested any of this, but if you encounter typos... sorry ;)
The Url you posted in your update is definitely not "All You Want to Know" about ViewState.... not even close. I only scanned his article but he doesn't appear to address Page Life Cycle at all. If your going the View State route then read these 2 links:
Understanding ASP.NET View State by Scott Mitchell
Truly Understanding ViewState By Dave Reed
If you're new to ViewState then dump all that guff (1 half the article) about parsing ViewState mentioned in your linked article. It's simply not required for anything but highly specialized scenarios. It is definitely not a normal thing to be doing re:ViewState.
Related
I have the following controller:
[HttpPost]
public ActionResult SomeMethod(string foo, obj bar)
{
//Some Logic
}
Now suppose that from the view that Action is called from a Button or from Ajax (with some edits), and I don't want to receive a double request.
What is the best approach to handle it from server side?
Update
You'd first have to define the time interval that would meet the
criteria of a double request – Jonesopolis
Let's suppose that in this case a double request are when the difference of time between first and 2nd call is less than 1s
Frankly, you can't, at least not totally. There's certain things you can do server-side, but none are fool-proof. The general idea is that you need to identity the POST is some way. The most common approach is to set a hidden input with a GUID or similar. Then, when a request comes in you record that GUID somewhere. This could be in the session, in a database, etc. Then, before processing the request, you check whatever datastore you're using for that GUID. If it exists, it's a duplicate POST, and if not, you can go ahead.
However, the big stipulation here is that you have to record that somewhere, and do that takes some period of time. It might only be milliseconds, but that could be enough time for a duplicate request to come in, especially if the user is double-clicking a submit button, which is most often the cause of a double-submit.
A web server just reponds to requests as they come in, and importantly, it has multiple threads and perhaps even multiple processes serving requests simultaneously. HTTP is a stateless protocol, so the server doesn't care whether the client has made the same request before, because it effectively doesn't know the client has made the same request before. If two duplicate requests are being served virtually simultaneously on two different threads, then it's a race to see if one can set something identifying the other as a duplicate before the other one checks to see if it's a duplicate. In other words, most of the time, you're just going to be out of luck and both requests will go through no matter what you try to do server-side to stop duplicates.
The only reliable way to prevent double submits is to disable the submit button on submit using JavaScript. Then, the user can effectively only click once, even if they double-click. That still doesn't help you if the user disables JavaScript, of course, but that's becoming more and more rare.
Look. Becareful with this approach. You will add most complexity to control this in server side.
First, you need recognize when the multiple requests are comming from the same user.
I don't think that to control this in server side is the best way.
However, if you really want that... look: https://stackoverflow.com/a/218919/2892830
In this link was suggested maintain a list of token. But, in your case, just check if the same token was received more than one time.
You need at least to implement double click on event listener.
UseSubmitBehiviar="false"
OnClientClick="this.disable='true'; this.value="Please wait";"
Check ASP.NET Life cycle
Check Request/Redirect
Add test code to see who is responsible
if (IsPostBack)
{
_CtrlName = thisPage.Request.Params.Get("__EVENTTARGET");
if (_CtrlName != null && _CtrlName == myButton.ID)
{
//Do your thing
}
}
Check IsPostBack in page load and use it correct to prevent dublicate requests.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
}
}
I realize this may be a simple problem, but I am new to ASP.net (C#) and am having an issue with a method in which I pass a 'Ride' object that was obtained from an sql database through a LINQ-to-entities statement. I attempt to set another global variable to the value of the Ride.identity attribute (which is a long), but in the next method, when I attempt to use this value, the new value has not persisted. Any thoughts? If there is some post-back that I am missing that reinitializes this variable, is there a way to save it? Thanks.
private void displayRide(Ride ride, int carNum)
{
if (ride != null)
{
ride.AssignedCar = carNum;
ride.Status = "EnRoute";
id_ridePendingConfirm = ride.identity; //<----THE PROBLEM IS HERE!
myEntities.SaveChanges();
RideToAssignDV.DataSource = new List<Ride> {ride};
RideToAssignDV.DataBind();
}
else
{
//TODO: Redirect to error.aspx
RideToAssignDV.DataSource = null;
RideToAssignDV.DataBind();
}
}
Store the value in ViewState. For example:
ViewState["RideId"] = ride.identity;
When you go and use it in the line in your code, you would need to do this:
id_ridePendingConfirm = (long)ViewState["RideId"];
But be careful. Since ViewState[key] returns an object, you will need to make sure it isn't a null reference, or else you'll receive an InvalidCastException.
I normally tell my my peers with less experience to create a protected property that will store this value and persist it in ViewState, as follows:
protected const string RideIdViewStateKey = "CurrentRideId";
protected long CurrentRideId
{
get
{
object o = ViewState[RideIdViewStateKey];
return (null == o)? -1 : (long)o;
}
set
{
ViewState[RideIdViewStateKey] = value;
}
}
Then in your code, do this:
// Assignment before postback so that you can preserve the state:
CurrentRideId = ride.identity;
// After postback in the method you have above:
id_ridePendingConfirm = CurrentRideId;
Now, since I don't know what your code should do when no Ride identity is available, I decided for -1, but it depends on what your code actually needs.
I do not recommend Session state for your scenario because this apparently needs to persist between page postbacks, not for the entire duration of the user's session. Also be careful with how much information you store in ViewState because it can easily be abused.
For more information on ViewState and Session State see:
Undestanding View State (2004)
ViewState Property (.NET 4.0)
ASP.NET State Management Recommendations
ASP.NET Session State Overview
Variables and fields do not persist across postbacks.
You need to use session state.
See this question and my answer for multiple methods of storing data between executions of a page. In brief, you need to store the value somewhere between postbacks. ASP.NET (and .NET in general) provide a variety of tools for doing so, but nothing is done automatically between requests. The page is created, executed, and destroyed with every request.
First a brief background. I am using .NET output caching and substitution controls to keep a few bits updated on each page refresh. The static methods that the substitution controls use require access to the Session object. Unfortunately, the HttpContext session is null in those methods.
I'm not going to rewrite my app to use a different store than the Session. Session is perfect for everything I need except this one aspect.
Can I manually create or populate a session object or otherwise get at its data by some sort of black magic wizardry? The session cookie is still being set from the client to the server. The info has got to be there somewhere. How do I get at it?
I'm not convinced this is a "good" way to go...but you can very dodgily store a reference to the Session in a shared/static variable and access it then.
Public Class SessionHelper
Public Shared TheSession As HttpSessionState
End Class
In your Session Start event (haven't figured out the best place to put it yet as the session isn't available in Application start as far as I am aware)
Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
' Store a reference...only do this once etc etc
If SessionHelper.TheSession Is Nothing Then
SessionHelper.TheSession = HttpContext.Current.Session
End If
End Sub
Then in your code you can just reference the helper
Dim someVariable as String = SessionHelper.TheSession.Item("ItemName")
A few things I'm not sure about this method:
not sure if the session object is now not thread safe
it doesn't seem quite right
this example is extremely simple...
Edit
I verified this worked for me by adding something to the cache and seeing if the session was available in the Cache Remove Callback which Http.Context.Current is not available in.
Edit 2
Here's a screenshot of it correctly returning the value. So it must be working to some degree, but the fact that the SessionId is not set is kind of worrying...I know I've used this technique before to access the Cache object but the cache is the cache, where as the session does need something to identify each session...Here you go anyway:
Session information is stored in the server's memory. You can, however, configure ASP.NET to store the session information inside SQL Server.
HttpContext.Current.Session should give you access to the current Session. The only time when this would not work is when there is no current HttpContext. As long as you have a reference to System.Web, it should work.
I am implementing the Ecommerce projects, where I need to static SessionID, is there any way to maintain the SessionID in the Entire Application.Explanation of my question is here
session.sessionid in asp.net?
but How can I implement this approach.
Now I understand your point
you have to do something like this on the Global.asax file
protected void Session_Start(Object sender, EventArgs e)
{
Session["DummyData"] = "dummy";
}
Adding any value to the Session object at the very first moment after created, you avoids to get different SessionIDs because the Session object wasn't accessed yet.
EDIT
Anyway checking your last comment I don't see that this is something that is affecting your development in some way. Probably you're over thinking on this. If you just need to avoid users to buy more than X products, you don't care about this problem. When the first product is added to the session, the same SessionID will be used in successive requests, until it expires.
Reading the other post you mention, it sounds like either Session was not being used, and so a new Session ID was generated on each request. To fix this, just store something (anything) in the session on the first request to make sure it sticks.
Session["something"] = "anything";
Or, it could be that the user did not allow cookies, which would also cause a new session on each request. So, your users need to allow cookies.
Or you could use cookie-less session.
The other post explains it pretty well, I think.
My question is a little bit tricky. at least I think. Maybe not, anyway. I want to know if there's any way to know if the user is leaving the page. Whatever if he clicks "Previous button", closing the window or ckicking on a link on my website. If my memory's still good, I think it's possible with JavaScript.
But in my case, I want to do some stuff (cleaning objects) in my codebehind.
There really is no way to do it. No event is fired when the browser goes back.
You can do it with Javascript, but it is difficult at best.
See the question here.
This script will also work. It was found here
<script>
window.onbeforeunload = function (evt) {
var message = ‘Are you sure you want to leave?’;
if (typeof evt == ‘undefined’) {
evt = window.event;
}
if (evt) {
evt.returnValue = message;
}
return message;
}
</script>
You can use javascript to tell the server when the user leaves the page. But the webserver washes it's hands of the page once it leaves the server, while the user might keep the page open for a week.
If you use javascript on the page to fire off a notice to your server when the page unloads you can take some action. But, you can't tell if he's leaving your page for another one of your pages, another website, or closing the browser.
And that last notice isn't guaranteed to always be sent, so you can't rely on it completely.
So using the javascript notice to clean up objects (caches or sessions) is a flawed system. You're better with cache & session invalidation strategies that are independent of the onunload notice.
If the goal of this is to cleanup objects in your code-behind, is it good enough to rely on the session timeout? It would be a 20 minute delay before cleaning up those objects (or whatever you have your session timeout set for).
But it's an easy and dependable way to do it. In your Global.asax file you'd just do this:
Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)
' Clean up stuff
End Sub
As mentioned, you can do it unreliably in JavaScript, but I am assuming from the wording of your question that you want to do it in the Server-side code ("the code-behind").
That is impossible since the code-behind is running on a different computer (the web server) and has no idea what is going on at the user's computer unless the browser sends a request back to the server (which requires some Javascript or other client side code).
If you must, use the session timeout events to clean up any state information you are storing beyond the lifetime of a request.
Euuwww ... well ok. My problem it's because I've stored in a Session variable an objects (with a bunch of search criterias). By storing it in a session variable, if the user go back to my search page result, it will list back the same result as last time. But, after some reflexion (not in code but in my head and after seen your answer :oP), I will add a boolean property in my object which will mean something like "IsDirty" or "HasBeenListed". And when i will load back, if its set to dirty, it's gonna redirect back to another page.
Thank David.