Here is an overview of my ASP.NET Page setup. Framework is 4.0.
There is a Page with tabs with a user control in each tab of it. There's a lock button on the Page which locks and unlocks the page. The page will be auto locked when any user opens it. This is the current setup. But now we need the following scenario:
The Page should not be locked on user opening it. But when he tries to edit or change any info in the fields of the Page it should lock the Page. I guess this is more of a client side Issue. So, when another user tries to open the Page and edits it, it will be locked for him too as it is a separate client. So, there should be a mechanism in ASP.NET to notify the server that a page is locked when user tries to edit the info on the Page so when other users try to modify the page, they get a 'locking' error.
So my question is how do I achieve the above and what are the things to consider?
I know in ASP.NET we can write code for user events like clicking a button etc.. but not sure of techniques for achieving the above. Any input would be a great help.
You could store something in the application cache with an expiry period set to however long you want the page 'locked' for. Each time there is a postback you would check for this value in the cache and either 'lock' the page or return an error to the user. Each time the page is loaded when not postback you would disable the button and/or input controls.
Something like this in Page_Load should be a reasonable starting point:
string usernameWhoHasLock = (string)Cache["PageIsLockedByUser"];
if (usernameWhoHasLock == null)
{
// Page is not locked, lock it:
usernameWhoHasLock = HttpContext.Current.Identity.Name;
Cache.Insert("PageIsLockedByUser", isLocked, null, EXPIRYDETAILS);
}
else
{
// Page is locked. If IsPostback, allow edits if is the user with the lock, otherwise return an error. If not postback, disable the edit button unless is the user with the lock.
}
For the arguments to supply to Cache.Insert decide what expiry policy you need and refer to the documentation here. IsPostback documented here.
you may consider implementing pessimistic locking in database where record will be explicitly locked and stay locked unless it's released (in this case saved/cancelled). not very easy to implement properly though.
Related
I have inherited an ASP.NET site (4.5). The site is running on a single server (in a hosted environment) using an automatically generated ViewState encryption key.
Whenever the site is restarted, in spite of users being correctly re-directed to the login page (which is basically an asp:Login control with some text), they will get MAC verification errors until they close their browser.
I would like to know if it is possible/how to ensure that the ViewState is completely culled / cleared whenever a user logs-in to prevent this problem from happening. Do I need to do a brute-force re-direct or something similar?
I note that the login control's DestinationPageUrl is set to a static value, rather than the page in the query string, would this be an issue?
Answers that suggest disabling ViewState validation, generating static keys or implementing persistent ViewState handling will be down-voted. Thanks.
I believe this is well-covered by the SO post linked below, and probably a few others and blogs (googling "viewstate mac validation failed" reveals a number of explanations and fixes.)
Validation of viewstate MAC failed when on page for 20+ minutes
In some cases setting PostBackUrl on the login Button to equal the page name that you will be posting back to will fix the issue.
I had a case where it did not, and I was selling a COTS product and could not always rely on users updating their configuration to avoid this notorious issue. To overcome this issue, I used a little bit of javascript. The solution goes like so:
Create a "splash screen" page which can also function as a screen saver, perhaps it could show a logo and randomly move it around the page every few seconds for a nice effect (I did this). Clicking on or hitting a key on the splash screen page should navigate the user to the login form page URL.
From the Login form, render the value of Session.Timeout (integer in minutes) into javascript.
Write a javascript function that fires on window.load and uses setInterval() or the like to monitor how long the unauthenticated-user has been sitting on your login form. When the session timeout is about to expire, redirect to the splash screen page created in #1.
(Instead of the splash screen method, you could force a refresh of the login form - but if a user leaves their browser on your login form over the weekend this will prevent your ASP.NET app from automatically shutting down due to inactivity (assuming you have a site that has low enough traffic volume to actually shutdown due to inactivity)).
Example code: (put this in your login.aspx)
<script type="text/javascript">
var sessionTimeout = <%=Session.Timeout.ToString()%>;
var sessionTimeoutMs = sessionTimeout * 1000;
var refreshLoginForm = false;
var redirectToSplashPage = true;
setTimeout(function()
{
if(window.console && window.console.log) { window.console.log("ASP.NET Session expired."); }
if(refreshLoginForm)
{
// method 1: refresh login form to get a fresh viewstate
window.location.href = window.location.href;
}
else if (redirectToSplashPage)
{
// method 2: redirect to a splash screen / screen saver page
// that will link back to login form and request a fresh viewstate.
window.location.href = "login_splashscreen.html";
}
}, sessionTimeoutMs);
</script>
I have a current problem where on one page, the Viewstate info is disappearing if we open a different page and do a few postbacks there, ie:
Open ListPage, change form selected options and do postback
Press button that opens AddPage on new Tab
On AddPage, add several new entries doing several postbacks, close tab
Go back to ListPage try to refresh the grid
On ListPage, viewstate is empty
So if I have a property that is storing and getting it's value from viewstate, on step 5 is getting null from viewstate.
if (ViewState["Stuff"] == null)
return MyObject.Default;
else
return (MyObject)ViewState["Stuff"];
From my understanding viewstate history size is by default 9 ( <sessionPageState historySize="9" /> ) but I wasn't expecting this to be shared between different pages and don't want to change this value.
I can go around the properties stored by storing them in session with a Guid generated per page, but the form controls and anything that got it's value from the database needs to be re-setted.
Is there any way to make the viewstate history independent between tabs/windows? Or any idea how to go around it?
I'm using Telerik controls on each page if that helps.
Edit: this explanation helped me understand how exactly the viewstate info is stored in session and how sessionPageState configuration affects it.
Found out what was happening,
By default the Pages are storing the ViewState in Session, ie, using the System.Web.UI.SessionPageStatePersister. Knowing this, then the observed behaviour is normal. It only stores a certain amount of page states (postbacks) and for every postback, the older info get lost, no matter in which tab/page the postback is being made of, as long as it's in the same session.
I added this to my pages to tell it to store the ViewState in the page itself, in an hidden field. That was already what I assumed it was happening.
protected override PageStatePersister PageStatePersister
{
get
{
return new HiddenFieldPageStatePersister(this);
}
}
I get stuck in a very unusual problem. I've a code written in C# which is simply checking IsPostBack property on the Page_Load. I know that IsPostBack remains false when page lands for the first time and bocme true only when any control post the form to the server (having runat=sever).
I also know that if we hit refresh, the IsPostBack property should change to false (since refresh is not a postback).
This is the sample code:
if (!IsPostBack)
{
// If I click on any control on the page, and then hit refresh,
// the code inside this block should execute, but this is not happening.
// After first postback, I tried refreshing the page for more than
// ten times, but always finds IsPostBack=true
// ...
}
else
{
// ...
}
I clicked on a server side button (a postback), then hit refresh. I assume it will go to the if block but no luck. No matter how many times i hit Refresh on browser, IsPostBack is always true. which is truly an unusual activity I've never seen before.
I would really appreciate any help. I need to know why this is happening, is this a browser related problem or something else? I used mozilla and chrome.
Every time I hit refresh, I get a warning on both browsers.
On chrome: Confirm form submission
The page that you're looking for used info that you entered, returning to that page might cause any action you took to be repeated.Do you want to continue?
On mozilla: Confirm
To display the page, firefox must send info that will repeat any action...
Thanks in advance for any kind help.
Praveen
Most browser will do a post of the same data if you refresh after posting.
This is the meaning of the dialogues you have seen (they are asking if you want to re-post - click yes/OK means a re-post).
In order to avoid the re-post, simply go to the address bar and press enter. That will cause a new request to be issues rather than a re-post.
Those dialogs that the browsers put up tell you that they are going to do a postback instead of just get'ting the page. And you can see in your code that the warnings are accurate - any handlers that were invoked on the original postback will get invoked a second time. This is one of the main problems with postbacks - they essentially break the refresh key. If you just want to load the page, you have to mouse up to the address bar and hit enter. This will load the page with IsPostback false.
I am building a web application in asp.net and c#, I am storing text of textbox in Session variable like this:
Session["data"]=TextBox1.Text;
and on the button click event I am redirecting user to another page.In the second page I am using this variable Session["data"] and in page2 there is a back button where I am again Redirecting to page1 where the textbox1 is present.Now on the button click event where I am redirecting to page2 and event is code like this,
Session["data"]=TextBox1.Text;
Response.Redirect("page2.aspx");
now when I am accessing the value of the Session["data"] it is giving me the previous value.As the content of TextBox1 may get changed,these changes have not been shown.
Please tell me where I am going wrong.
I dont think the code you are using is worng. You please make a break point and check it again that the values are assigning correctly
Or
You just set the session to null and then assign the textbox value to it on the click event.
Read this I think Respone.Redirect might be causing you to lose your session data
Don't redirect after setting a Session variable (or do it right)
A problem I see over and over again on the ASP.NET forums is the
following: In a login page, if the user and password have been
validated, the page developer wants to redirect to the default page.
To do this, he writes the following code:
Session["Login"] = true;
Response.Redirect("~/default.aspx");
Well, this doesn't work. Can you
see why? Yes, it's because of the way Redirect and session variables
work. When you create a new session (that is, the first time you write
to a Session variable), ASP.NET sets a volatile cookie on the client
that contains the session token. On all subsequent requests, and as
long as the server session and the client cookie have not expired,
ASP.NET can look at this cookie and find the right session. Now, what
Redirect does is to send a special header to the client so that it
asks the server for a different page than the one it was waiting for.
Server-side, after sending this header, Redirect ends the response.
This is a very violent thing to do. Response.End actually stops the
execution of the page wherever it is using a ThreadAbortException.
What happens really here is that the session token gets lost in the
battle. There are a few things you can do to solve this problem.
First, in the case of the forms authentication, we already provide a
special redirect method: FormsAuthentication.RedirectFromLoginPage.
This method is great because, well, it works, and also because it will
return the user to the page he was asking for in the first place, and
not always default. This means that the user can bookmark protected
pages on the site, among other things. Another thing you can do is use
the overloaded version of Redirect:
Response.Redirect("~/default.aspx", false);
This does not abort the
thread and thus conserve the session token. Actually, this overload is
used internally by RedirectFromLoginPage. As a matter of facts, I
would advise to always use this overloaded version over the other just
to avoid the nasty effects of the exception. The non-overloaded
version is actually here to stay syntactically compatible with classic
ASP.
I don't really see what you want to do here. You say it works (the Session["data"] contains the text of TextBox1?) but you don't see any changes? What changes did you expect? Please give us some more information about this part of the question:
As the content of TextBox1 may get changed,these changes have not been shown.
Thanks.
Update:
Try clearing or remove the session and then refill it.
Session.Remove("data");
Session.Clear();
I have a page that requires the user to go through several steps, however step is performed on the same ASPX page with different panels being displayed.
However this is a requirement that each step has a different URL, this could be a simple as a query string parameter, for example:
Step 1:
/member/signup.aspx?step=1
Step 2:
/member/signup.aspx?step=2
Step 3:
/member/signup.aspx?step=3
However I don't want to have to redirect the user to the new URL each time they continue to the next step, this would involve a lot of redirecting and also a switch statement on the page load to work out which step the user is on.
It would be better if I could alter the URL that is displayed to the user when the original request is sent back to the user, i.e. the user click "next" on step 1 the page then does some processing and then alters response so that the user then sees the step 2 URL but without any redirection.
Any ideas would be greatly appreciated.
Could you convert your Panels into steps in a Wizard control?
It would be a little more complicated than you probably want, but you could achieve this effect with the PostBackUrl property of the submitting button. I'm assuming each panel has its own "submit" button, and they could all use this property to "advance" the process. The drawback is that in order to get to submitted controls, you'd need to use the Page.PreviousPage property in order to access any controls and their values.
You could programmatically alter the PostbackUrl property of your 'Next' button on each Page_Load, based on the query string value. This is a bit strange though, as you wouldn't be able to use a standard event handler for the button click, and you'd have to use the PreviousPage property of the Page to get the data from the previous tab.
I'd say challenge this requirement. Why would anyone need to jump into the middle step? If it's a case of displaying the progress to the user, do this on the page, not in the URL.
You require that each step has different URL, than Response.Redirect is the only option. As you want to avoid the redirection, you can use IFrame but IFrame URL is not visible to user on his browser. I think redirect option is ugly(for both SERVER and CLIENT) as in this case, you first post on the page and than get that page. The best solution is POST BACK with some varible tracking step.
You could implement a form or url rewriting so that your urls end up being
/member/signup/step1/
/member/signup/step2/
/member/signup/step3/
To do this use the
HttpContext.RewritePath method which means you can rewrite /member/signup/step1/ to /member/signup.aspx?step=1 for example. See an example here.
I would also use the PRG (post request get) pattern so that each next link posts the form data of that step to the session then redirects the user top the correct next url. this will ensure that the user can navigate back and forth through the steps safely and also the url will remain intact in all your posts.
Check out server.transfer