I've created a form to send message for admin, and when I click on send button all things are fine and data are sent and saved to the database and I print success message. But if I refresh the page -by pressing F5- the message is sent again to the server and database!. How can I fix this problem ?
I just want to send message to the server once when I click on send button, not on refresh page.
my code is
<asp:Button ID="btnsenddata" runat="server" OnClientClick="return validate()" OnClick="btnsenddata_Click" Text="SendData" />
protected void btnsenddata_Click(object sender, EventArgs e)
{
//this place i connect to DB
}
This is a commond issue. The behavior is by design: The information of the
button that was pressed is actually re-sent to the server (along with all
other information of the controls) when the page is being refreshed.
A nice way of workaround i found, while surfing the net, is (this way is on the server side) to use HashTable:
//Class member
HashTable ht = new HashTable();
btnMyButton_Click(object sender, EventArgs e)
{
ht =(Hashtable)Application["UserOKHashtable"]
if ((ht.ContainsKey(Session["UserSessionKey"]))
{
// double - clicked or user pressed refresh
return;
}
else
{
(ht.Add(Session["UserSessionKey"],UserName);
// your code here
// and finally
((Hashtable)Application["UserOKHashtable"])
.Remove(Session["UserSessionKey"]);
}
}
Remember to remove the user's session key from the hashtable at the end
of the procedure, otherwise the user will only be able to click the
button once during the whole session.
If you search for "prevent double post", you will find more information and possible workaround for it.
hope it'll help :)
I would put a OnClick handler on the button. So, in your .asp file <asp:Button id="btnMyButton" runat="server" OnClick="btnMyButton_Click"
Then on the aspx.cs side you add method 'btnMyButton_Click' and put your code in there
btnMyButton_Click(object sender, EventArgs e)
{
//your code to update database goes here
}
You will have to come up with some method, probably in the database, to ensure that repeated messages are not sent within a certain period of time. You can't easily get around the F5 issue because all that does is tell the browser to repeat exactly what it did the last time. This means the same data is sent to the user. That is the trick, any check you put in must store the data within the server since the client will just replay the last action.
You could hold a session variable to let you know when the user sent this form last (just ensure you check for Session["sentform"] != null when checking for the session variable)
Also, you could create a simple log in the database to say what user clicked (if you have logged in users), the time it was last sent, and something that will let you identify which page, message requestor was fired. Then you can ask the database if this user has sent message for page/process X within the last couple minutes and return true or false.
Related
I have the following project :
It's a page that on Page_Load it fills a TextBox named Email and a TextBox named UserName with a value obtained from asking a database.
Then there is this button, if the email is not null(user is not registered) it will let you register, otherwise it will let you change the email linked to your username.
The thing is, when trying to modify the email, doing an update query, the page preloads, taking the new value placed on Textbox Email the same that is retrieved from the database, making so it will never change.
I've tried to see if it executes the query and it does.
I've tried everything, keeping the variable on a hidden label, creating two different buttons with no luck as when it reloads the code those values are empty again.
I was thinking if I could keep the variable somehow that isn't cookies.
I think You know What is happening.. On every Post back the Page_Load event resetting your Textbox Value
Use IsPostBack to bind the value only on 1st load of page
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//bind dropdown and fill textbox here
TxtName.Text = "Your values";
GetDropdowns();
}
}
I hope this will solve your issue
I totally agree with Kanis XXX, you can use IsPostBack to fill the values only at the start page, and not on other postbacks. In my experience, there are some other advices for your problems:
Using Viewstate, Session state,... to keep your working variable. You can have more detail here: https://kimphuc.wordpress.com/2009/10/18/the-difference-between-viewstate-sessionstate-cookies-and-cache-in-asp-net/
Try to use UpdatePanel, this could be useful in some cases, let you refresh or update data just a part of your page, not the whole page. https://msdn.microsoft.com/en-gb/library/bb398864%28v=vs.100%29.aspx
I have page A and page B. You can do the following things in page A:
Do stuff on page A (e.g., choose an item in a list box), which causes an UpdatePanel in page A to be redrawn with additional information.
Move on to page B. This is done with a Button and Response.Redirect.
Now the problem is as follows:
The user does stuff on page A. Page A is now different from its initial state.
The user moves to page B.
The user hits the back button of the browser.
What happens: Page A in its initial state is shown.
What I would like to happen: Page A in its final state is shown (i.e., with the "correct" item selected in the list box).
I know about ScriptManager.AddHistoryPoint! As far as I can see, it does not solve my problem:
I could call AddHistoryPoint every time something is done on page A. This is bad, because it litters the browser history with lots of entries. (A new entry every time a different list box item is selected.) But that's exactly what I want to avoid by using an UpdatePanel! Of course, if there were a ReplaceLastHistoryPoint method, that would be perfect, but I did not find one...
I tried to call AddHistoryPoint right before Response.Redirect, to save only the last state of page A, but, alas, that doesn't work (no history point is saved). This is not surprising, considering how Response.Redirect works.
Is there some solution I have missed? I'm using .NET 3.5SP1, in case it matters.
This is a bit of an old question, but I'll go ahead and provide the mechanism I use for this. The basic idea is that instead of allowing AddHistoryPoint to manage your name-value pairs, just allow it to manage a key to your NameValueCollection that you keep somewhere else, like in your Session cache. Then as subsequent Ajax requests come in, you never make another call to AddHistoryPoint; instead, you just replace your NameValueCollection with the state of the current request.
The only other bit is to keep track of whether you're on your first Ajax call and need to make that first call to AddHistoryPoint or not.
My code looks something like this:
protected void Page_LoadComplete(object sender, EventArgs e) {
if (!ScriptManager.GetCurrent(this).IsNavigating && (IsCallback || IsInAsyncPostback())) {
var state=new NameValueCollection();
//OnCallbackHistory(state); // this gets state for all interested parties
if (state.Count != 0) {
string key=ViewState["HistoryStateKey"] as string; // empty on first AJAX call
if (string.IsNullOrEmpty(key) || ScriptManager.GetCurrent(this).EnableHistory) {
key=CallbackHistoryKeyRoot+Interlocked.Increment(ref callbackHashKey).ToString();
ViewState["HistoryStateKey"]=key;
ScriptManager.GetCurrent(this).AddHistoryPoint("", key);
}
Session[key]=state;
}
}
}
Instead of calling AddHistoryPoint on the server you could call addHistoryPoint on the client using the Sys.Application class, http://msdn.microsoft.com/en-us/library/vstudio/cc488025(v=vs.90).aspx.
So you'd add a client side click listener to the button which would addHistoryPoint on the client before the button does the post back and redirect.
I have a form to edit employee information. If the user wishes to enter a new e-mail address for the selected employee, there is a textbox and a button that says "Add Email Address." Very simple, you enter the e-mail address, click Add Email Address. It postsback and that button's event handler executes the INSERT to the database.
The problem:
If you press F5 to refresh the page after that postback, it causes the same postback to occur, even if the textbox is blank. In other words, for every time you hit F5, the actions in the event handler for that Add Email Address button occur again. If I hit F5 ten times, the same e-mail address shows up in the database ten times.
One suggestion I found said, "just re-direct to the same page after you apply your changes." The reason this is not ideal in our case is that it's a rather lengthy form of employee data --- if the user makes a bunch of changes to the overall form (such as FirstName, LastName, etc.), then makes an e-mail addition before applying the changes elsewhere, those changes elsewhere would be lost if we re-directed to the same page.
The very long winded solution I can think of is, capture all of the data in ViewState, carry it across the re-direct to the same page, then use a query string in the URL to determine if we want to fill in the data from ViewState. Before I embark on that path, I'm hoping that instead of that, there is some method I just don't know that says like, PostbackButDontRetainPostbackData() (wishful thinking, I know).
In the handler for that Add Email Address button check if the email already exists in the database. If it does, do not add the email again and display an appropriate message to the user. Usually forms have a reserved area like a hidden div for this purpose so in case anything goes wrong the div will be populated with error messages and displayed to the user.
Also, it would help to display a confirmation message to the user when their data is successfully received and processed.
UPDATE
If you don't like to show any messages to the user, simply do nothing after you find out that the email already exists in the database. e.g.:
public void AddEmailToDB(string email)
{
// first find out if the email already exists in the database
bool isDuplicate = ...;
// if it does, simply return and do nothing
if(isDuplicate) return;
// if control reaches here then the email is not
// a duplicate and you can do your normal processing
}
UPDATE II
If you don't want the browsers to show a messagebox everytime a user presses F5 after a postback, you can do a partial postback using AJAX by wrapping your email textbox and add button in an UpdatePanel, it's very easy to use.
I have a save button which when clicked should make some changes in the database.
if (bFound== false)
{
// Giving the warning message
// If user presses cancel then abort
// Prepare the list of dbId needs to be deleted
deletedBSIds.Add(dbId);
}
Here if the bFound field is true it should not execute the above statement, but if it is false it should go in the condition and then ask if the user want to save changes "yes" or "no".
If the user says yes it should go to the command "deletedBSIds.Add(dbId);" and keep executing further but if the user presses No it should basically abort and do nothing at all.
Is there a way to do this?
Any help would be appreciated.
This is a server side event. so i think cannot add a click event in my button/..
Here the message box only pops up if the bFoung field is false. or else it will not pop up at all.
Please correct me if u feel i am wrong..
thanks
You'll want to add the following to the button:
button.OnClientClick = "return ConfirmThis();";
You'll then need to add the ConfirmThis function to the Page:
Page.ClientScript.RegisterScriptBlock(GetType(), "ConfirmThis",
#"function ConfirmThis() {
if(condition) { //where condition checks the bfound element.
return confirm(""Are you sure you want to delete this?"");
}
return true;
}");
Doing this approach you're going to want to try and be able to test the bfound condition on the client side in the javascript. If the bfound value is stored in a textbox or HiddenField you should use the document.getElementById function. If the bfound value is known when you are creating the page, you can inject it into the ConfirmThis function directly, of pass it into the ConfirmThis function as a parameter.
Edit in response to your edit:
You have two options when trying to elicit a confirm from the user:
Using client side logic that is already sent to the browser to perform the confirm. This is the example that I have given above.
The "Other" option is to send the page back with a modal dialog, or using the confirm box. You will then get the user's confirmation back in a completely new postback to the server. So you'll need to rethink your logic to be able to temporarily store the information from the first post back and wait for the second post back to finalize the desired action.
Of the two examples, the first option is cleaner and requires no temporary memory and saves the user an additional postback.
Because both options are going to require you to rework the logic asking for the confirm, if at all possible I would try to convert the logic required for the condition to show the confirm dialog to be able to be performed on the client's computer with javascript.
Is there any way you can precalculate the bfound variable, or at the least, send enough information for it to be calculated on the client?
If you still feel like using option 2 after all of my pleading:
use the following code (based on http://www.dotnetspider.com/resources/1521-How-call-Postback-from-Javascript.aspx:
if(bfound)
{
//save all the information you need in temporary information
ViewState["InformationINeedToFinishAfterPostback"] = ImportantInformation;
Page.ClientScript.RegisterScriptBlock(GetType(), "postbackmethod", Page.ClientScript.GetPostBackEventReference(this, "MyCustomArgument"));
Page.ClientScript.RegisterStartupScript(GetType(), "startupconfirm",
#"if(confirm(""are you sure?"") {
__doPostBack('__Page', 'MyCustomArgument');
}");
}
Now to handle the postback add the following code to your page_load:
if(Request("__EVENTARGUMENT") == "MyCustomArgument")
{
ImportantInformation = (CastToAppropriateType)ViewState["InformationINeedToFinishAfterPostback"];
//finalize the desired action here.
}
But... I would still recommend the first option. But now you have the code you will need for both options. Also, I didn't test this code, so you're bound to encounter syntactic problems, but it gets you on the right track.
I'm not all that sure what bfound is supposed to represent, but you can't execute 1/2 way through some server code and then go back to the client- ASP.NET does not work that way.
Typically you will do the confirmation with some client side JavaScript. Google ASP.NET Yes/no confirm to find lots of different ways to do this...
Once you've done this you can then conditionally execute the server side code.
You could use the Javascript confirm() function to display a dialog box to the user with 'OK' and 'Cancel' prompts. You could then store the user's choice in a hidden field and trigger a postback. This article explains how to render Javascript code to the client using ASP.NET.
Since you are using ASP.NET you can add an attribute to your button:
btnDelete.Attributes.Add("onclick", "return confirm('Are you sure?');");
Where btnDelete is your Button.
So I am experiencing an issue with an .aspx page and some server side code, where I am getting unexpected results.
The goal of this page is simple, there are 5 radio buttons and a button with a server side onclick function. The idea is the user picks 1 of the 5 radio buttons, and then clicks the button. Upon clicking the button I verify (not using form validation, because I wanted a different feel) that a button is checked, and then store the selected option in a database.
Due to the fact that the number of radio buttons may change in the future I decided to try and abstract the number of radio buttons to make it easier on my self to change in the future.
So at the top of my server side code I created a list of possible options.
I then have a registerVote function that takes in a RadioButton object, and a number to grab a setting from the config file. I throw those 2 values into a wrapper class, and then add them to the list of possible options.
Finally when the submit button is pressed, I iterate through all possible options to see which one is checked, and grab its associated value.
public partial class VotePanel : System.Web.UI.Page
{
List<VoteOption> voteOptions = new List<VoteOption>();
public string registerVote(RadioButton newRadioButton, int voteOption)
{
voteOptions.Add(new VoteOption(newRadioButton, voteOption));
return ConfigurationManager.AppSettings["vote_option_" + voteOption];
}
protected void Submit_Click(object sender, EventArgs e)
{
//Check vote
string vote_value = "";
bool someButtonChecked = false;
foreach (VoteOption vo in voteOptions)
{
if (!someButtonChecked && vo.button.Checked)
{
vote_value = vo.movie;
someButtonChecked = true;
}
}
//....
}
}
class VoteOption
{
public RadioButton button;
public int vote_value;
public VoteOption(RadioButton r, int v)
{
button = r;
vote_value= v;
}
}
The code I use in page to add a radio button looks like this
<asp:RadioButton ID="RadioButton1" runat="server" GroupName="Vote" style="position: relative; top: 3px;" /><%=registerMovie(RadioButton1,1)%>
Now for the problem I am experiencing. Whenever the submit button is clicked, the list has a count of zero, and looks like it has been reinitialized. I validated that values are being added, by returning the list count in the registerVote method, and objects are indeed being added, but for some reason are not available to the Submit function.
Now variables on a page like this shouldn't reinitialize right? I also tested a string, and it did not reset and was available to the Submit button. What I did was define a class variable string time = DateTime.Now.Ticks.toString(); and displayed that after the submit button was clicked, and the time was always the same reguardless of how many times I clicked it.
So why would my List reinitialize, but not a string? Any ideas?
Keep in mind that your page class will be constructed and destructed for every request - no state will be maintained between each page load, it is up to you to properly recreate state as needed. In this case it appears that your list voteOptions is not being recreated before Submit_Click is called.
You'll have to register all your voting options regardless of whether the page is in a postback or not inside the Page_Load or OnInit handlers of the page. This will reconstruct voteOptions, which will then be accessed when Submit_Click is called.
Take a look at the ASP.NET Page Life Cycle.
The problem seems to be that you are constructing the List<VoteOption> voteOptions at page render then expecting it to still be there on postback. The Page object does not exist past the point that the page is delivered to the browser, so your list of vote options gets disposed of as well when the browser has received the page.
You'll either need to reconstruct the voteOption list before or during Submit_Click on postback, or give yourself enough information in the value of the radio button that you don't need it.
I don't see in your code any place where the list that you are building is placed in memory. I believe you are rebuilding it on each page reload. P.s. might be my reading but you created a function called registerVote and you are calling a method called registerMovie so that might be your problem.
You could place the list in the session and get it back from session.
Personnally I would change the code to
1) Check if the list is in memory and get it. If not in memory call a method to generate it once and then place it in memory.
2) Use a RadioButtonList on your page that you can then bind to your list as a data source.
asp.net is stateless, so every postback (such as clicking Submit) recreates the server-side class. If you want your list to persist between calls, you should save it in ViewState or a Hidden field. Not sure about the string though; what you're describing doesn't fit the asp.net lifecycle.