Way around ASP.NET session being shared across multiple tab windows
I'm storing some value in an asp.net session on the first page. On the next page, this session value is being read. However if multiple tabs are opened and there are multiple page 1->page 2 navigation going on, the value stored in session gets mixed up since the session is shared between the browser tabs.
I'm wondering what are the options around this :
Query String: Passing value between the pages using query string, I don't want t开发者_StackOverflow中文版o take this approach since there can be multiple anchor tags on page 1 linking to page 2 and I can not rewrite the URLs of each tag since they are dynamic.
Cookies??? In-memory cookies are shared across browser tabs too, same as the session cookie, rite ?
Any other option?
PS: Page 1 to page 2 is not a form submit.
I figured out a solution :
Using Javascript assign a unique id like a guid to the browser window / tab by assigning the guid value to the window.name property. window.name property is unique to each browser window/tab and won't be shared across the windows.
Using the guid as the key, read and write data to your ASP.NET session via a webservice. Since javascript does not have access to asp.net session, you will need to use a webservice and call it's method through javascript.
The data can be transfered between javascript and webservice via JSON.
- Give each page a guid. Store the guid in a hidden field.
- Use this guid as the session key that stores a struct with all the variables etc. for that page.
- You can now pull information for a specific page "rendering" and passes data to the session struct to the new "rendering" in the code-behind.
This is similar to what ViewState does automatically.
EDIT
Comment response
I don't think that's possible as you described it.
In your question you mentioned page 1 to 2 navigation. If the user types in the URL for page 2 in the browser then how do you tie that current page 2 rendering with the previous page 1?
You need something to do so, unless the code-behind can search a list of incomplete workflows that have stopped at page 1 and uses that as the previous guid value for the new page 2 rendering.
Comment response 2
You can find all the links on the page and modify those but it hints that something is wrong ( in my opinion ). But...
http://www.extremeexperts.com/Net/Articles/LoopingthroughControls.aspx
Gives you a simple way of processing all controls on the page. You can test to see if the control is a hyperlink easily. Not that all links will need that runat="server" parameter set for this to work.
Could you use ViewState instead of SessionState?
Update:
Or perhaps a combination of ViewState and SessionState.
Here's an example sequence:
- On Page 1, user chooses "Red". Value is stored in SessionState.
- User navigates to Page 2. Value is read from SessionState and stored in ViewState of Page 2.
- User opens a second Page 1 in a new tab and chooses "Blue". Value is stored in SessionState, so "Red" is replaced with "Blue".
- User navigates to Page 2. Again, value is read from SessionState and stored in ViewState.
- User returns to original Page 2 (the one on the first tab) and performs a PostBack. Value is read from ViewState. Value is still "Red".
- User returns to second Page 2 (the one of the second tab) and performs a PostBack. Value is read from ViewState. Value is still "Blue".
In other words, use SessionState for transitions between pages. Use ViewState for PostBacks of same page.
Does that help?
It sounds like you want each page to keep it's own values, separate from each other.
- If you can use Post (eg: you can keep from manipulating the URL on the client), hidden input tags can do the job well. You'll certainly want to encapsulate this, since doing it manually would be a huge pain. Otherwise:
- If you're using ViewState, you could use that. Otherwise:
- You get the values or an ID (which would be better. see below) into the URL. A last resort, because the human will be able to screw this up. Or they might bookmark it and cause confusion when they come back a week later.
If the values cannot be sent to the client, then you need to pass a "PageSessionID" or something down to the client. This ID is either a guid (better if security is an issue) or some value you get in a way to guarantee uniqueness. Send to the client in a hidden input tag or in ViewState (or url if no other choice), and store related data on the server based on that ID.
Cookies won't work for you purposes.
Another way to do it is to use a Server.Transfer or a CrossPagePostBack. Then you can access all of the previous page's variables using Page.PreviousPage. If Page.PreviousPage is null, you know the user came to the page directly and you should process page 2 with that in mind.
I can't really recommend it though, because with Server.Transfer you don't update the URL in the browser and CrossPagePostBack makes everything a postback, which can lead to problems like the back button not working "normally".
I'm designing an asp.net system like this to allow multiple pages, tabs, sessions on one or more machines, to create and edit guid based key requests based on a smallish tree of sql records, using a wizard interface so this is basically a long running web app saving data that is only written to the database at the end when the user submits. We don't want the same data being editing by more than one user or tab.
I plan to use the guid key to create/claim a lock object stored in appstate. The lock object also has userid/timestamp/PageToken. The page token is a guid but can be null if the page token based session object is pre-created for another page in the same session [so can pass more data to the new page] or the token can be valued the session object is created for the current page. When the session object is created based on the key, it can be used to store normal session type data, which is now unique for this key, rather than shared across the entire session.
So the first page creates the key object in app state w/o a pagetoken and then links to the new page that ckaims the key object from appstate using its querystring with the key, and by matching userid/timestamp/PageToken with null or a valued token. If it matches and was a null token, the token is created and stored in the key object and in the viewstate.
If another page comes in with the same query string matching the guid key, it can try to claim the appstate key object but will fail unless has the same userid/timestamp/PageToken in the key object having got the page token form the viewstate. And if everything matched, updates the timestamp. If the timestamp is too old, 15 minutes, the the key object can be stolen. and If the old page comes back looking for it the page token will no longer match and claiming will fail due to either the timestamp too old or the page token not matching.
The token can be null or valued when the key object is created. If it starts out null when created, then anyone can claim with a new token but must match the timestamp pretty close.
Then the related key object which can be a larger size, is stored in the session using the page token as the key into session data such as a serializeable dictionary in case this needs a sql backing store.
So we are able lock data across the entire web app all users, we can expire and reclaim the locks after say 15 minutes of non use, and have key based data for tabs, pages, new sessions and different browsers.
精彩评论