Asp.Net SQL Refresh page duplicate inserts? - asp.net

I have a *.aspx page that contains a text box and a button. When the user enters information in to the textbox and clicks post, it inserts the data into my sql database. The issue is, that if the user hits refresh, it will keep inserting the same data into the database. I am pretty sure the whole "click" method is called, not just the insert call. I tried messing with sessions but it complains. I am not really sure what to do. I am looking for a simple easy fix.
protected void PostButton_Click(object sender, EventArgs e)
{
string wpost = (string)Session["WallPost"];
DateTime wtime = (DateTime)Session["WallDateTime"];
if (txtWallPost.Text.Length > 0 && !wpost.Equals(txtWallPost.Text))
{
string strCon = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["SocialSiteConnectionString"].ConnectionString;
using (SqlConnection conn = new SqlConnection(strCon))
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "INSERT INTO [WallTable] ([UserId], [FriendId], [WallPost]) VALUES (#UserId, #FriendId, #WallPost)";
cmd.Parameters.AddWithValue("#UserId", User.Identity.Name);
cmd.Parameters.AddWithValue("#FriendId", User.Identity.Name);
cmd.Parameters.AddWithValue("#WallPost", txtWallPost.Text);
conn.Open();
cmd.ExecuteNonQuery();
Session.Add("WallPost", txtWallPost.Text);
Session.Add("WallDateTime", new DateTime());
conn.Close();
txtWallPost.Text = "";
LoadWallPosts();
}
}
}
return;
}

If the PostButton_Click is the server handler for the click event on your button then insert code shold be executed only if the user hits the post button - it should not happen in case of refresh.
I am pretty sure is not enough - to be sure put a breakpoint in your PostButton_Click method, hit F5 to run in debug mode and see if the breakpoint gets hit with a refresh.
If so it means that:
you are calling explicitly
PostButton_Click from somewhere
else (Page_Load?)
PostButton_Click was accidentally
set as event handler for some other
event on the page
A quick way of verifying hypotesis 1 & 2 is to run a search for PostButton_Click and see where you are calling it from or if it set as handler for some other element (maybe your form?) in the markup.

Add Response.Redirect(Request.Url.ToString(), false); to your button event and that should solve the problem.

if he refreshes or press the back button the post will happen again, thus your page will process the same data thus insert once again.
You have to change your logic

It would be preferable to redirect the client to another page after the insert, however, if you really need the client stay in the same page, you can use a (bool) variable on your page to state if the insert has been done, and skip the insert logic if it has been executed before

Related

How to prevent PostBack while clicking button in ASP.NET

The following picture is view of one of my WebForms in project. I am currently facing following problem: I am loading CSV file, the program analyzes it and displays it as a Table. Then, using DropDownLists and Textboxes below, user chooses day, project and hours in order to decrease hours, which have been assigned to the project (imagine project x, which has budget of 100.000$ and has 150h to be burned by workers. Each worker burns his own hours and web admin can see how many hours can be burned and how does the budget look like). When I decrease hours for some day, for example project x, Monday, 8h- the page reloads and all the things, including table, dropdownlists and textboxes are closed and user add project hours for another days.
Please see the code that is responsible for changes in the database and is executed during Submit button click:
private void decreaseProjHours()
{
if (IsPostBack)
{
string nameOfProject = DropDownList1.SelectedValue;
int dayID = DropDownList2.SelectedIndex;
int hours = Convert.ToInt32(TextBox3.Text);
if ((nameOfProject == "") || (dayID > 7 || dayID < 0) || hours < 0)
{
Response.Write("You have entered invalid data in one of the fields!");
return;
}
//decreasing from total hours assigned to project
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["WorkTimeDBConnectionString"].ConnectionString);
conn.Open();
string getTotalProjectH = "select hours from projects where project_name='" + nameOfProject + "'";
SqlCommand com = new SqlCommand(getTotalProjectH, conn);
int check = Convert.ToInt32(com.ExecuteScalar().ToString());
if (check - hours < 0)
{
Response.Write("No more hours can be reported for project" + nameOfProject);
conn.Close();
return;
}
else
{
try
{
string tryUpdate = "update projects set hours='" + (check - hours) + "'" + " where project_name='" + nameOfProject + "'";
SqlCommand com1 = new SqlCommand(tryUpdate, conn);
com1.ExecuteNonQuery();
}
catch (Exception ex)
{
Response.Write(ex.ToString());
conn.Close();
return;
}
}
}
}
Is is the problem with PostBack? I already tried making OnClientClick return false and Button3.Attributes.Add("onclick", "return false;")- the operation of modifying the database fails then and nothing is submitted.
What should I do? Is it really problem with PostBack or something else refreshes my webpage?
EDIT:
Button3.Attributes.Add("onclick", "return false;");
Button3.OnClientClick = "decreaseProjHours(); return false;";
Button3.UseSubmitBehavior = false;
Thanks in advance,
Kokos
You have more or less the correct code in the line
Button3.OnClientClick = "decreaseProjHours(); return false;";
However the problem is that it looks for a javascript function decreaseProjHours(), which I'm assuming you don't have since you have that method on the server side in your code behind. OnClientClick is by definition a client-side handler and so the method needs to be defined on the client side. Since it can't find the javascript function, it fails to execute the next line return false;.
If you need that code to execute first and then return false to prevent postback, you need to put the code in a javascript function instead of in the code-behind. You can then have that fuction either return true or false if you wish, instead of having the additional return statement in the OnClientClick definition.
Note that if you have a server-side click handler defined as well, this won't execute if there is no postback; i.e. the server-side OnClick handler only executes if the client side returns true.

How to get textbox value in ASP.NET click eventhandler

Somehow one of my stored procedures just stopped executing from aspx page. It works if I run it from SQL Server using EXEC. But when I click a button on my aspx page which assigns parameters and values, and launches this procedure, page reloads but data is not updated. This button can run create or update procedure, depending on the page parameters in the address bar. But nothing is executed.
In the aspx page I create that button like this:
<asp:Button id="btnSaveChanges" runat="server"
class="class_Button Normal Enabled"
OnClick="btnSaveChanges_Click" Text="Save changes" Width="100" />
Then in the code-behind file:
protected void btnSaveChanges_Click(object s, EventArgs e)
{
//if (Page.IsValid)
//{
SqlCommand sqlComm1 = new SqlCommand();
SqlConnection sqlConn1 = new SqlConnection("Server=localhost\\SqlExpress;Database=TestDB;Integrated Security=true");
sqlConn1.Open();
if(param_id == 0)
{
sqlComm1 = new SqlCommand("dcspCreateEmpDetails", sqlConn1);
}
if(param_id > 0)
{
sqlComm1 = new SqlCommand("dcspUpdateEmpDetails", sqlConn1);
}
sqlComm1.CommandType = CommandType.StoredProcedure;
if (param_id > 0)
sqlComm1.Parameters.AddWithValue("#empID", param_id);
sqlComm1.Parameters.AddWithValue("#empName1", tbName1.Text);
sqlComm1.Parameters.AddWithValue("#empSurname", tbSurname.Text);
sqlComm1.Parameters.AddWithValue("#empBirthDate", Convert.ToDateTime(tbBirthDate.Text));
sqlComm1.ExecuteNonQuery();
//}
sqlConn1.Close();
}
That's it. Page is valid, 100%. And even if I remove validation check, no result.
Here is the procedure:
CREATE PROCEDURE dcspUpdateEmpDetails
#empID int,
#empName1 nvarchar(50) = null,
#empSurname nvarchar(50) = null,
#empBirthDate datetime = null
AS
UPDATE Employees
SET
name_1 = #empName1,
surname = #empSurname,
date_of_birth = #empBirthDate
WHERE (employee_id = #empID)
Hope you'll help me with it, guys. I really don't understand what happened to this stuff...
Updates for the topic:
Examining debug messages I found, that textbox loses its text before the stored procedure in the OnClick event takes this text as a parameter.
Is it really normal that server first restores the page and only after that it executes code in OnClick event? I think it's logically incorrect because Page_Load is designed to load the default page, while buttons and other controls are used to change and manipulate content of a page. Why do I need those controls if their code can't execute timely?
I took my backup copy and copied all stuff regarding this problem to my current version. It was just the same absolutely identical code. I just replaced current code with the same code from backup and it works now. What was that?
I can't mark anything as an answer because there are only comments here. I'll mark this one.

RDLC Report Viewer - How to reset the input parameters programmatically

I have a RDLC control on my website. This is client side report. I am using ASP.net 3.5 with Visual Studio 2010 There are a number of filtering criteria which the report takes as the input parameters. There is a SQl server 2008 R2 Stored Procedure which generates the results. One of the inputs is a datetime textbox with associated calendar control. There is a 'Refresh' button. Clicking this refreshes the report. I wanted to add some validations for date. All my validations work fine. My issue is when a user enters wrong characters in the datetime textbox, the report fails which is correct but when the user hits refresh button though the error vanishes the report still displays the error message.
Is there a way to refresh the parameters when locally calling the report.
This is my simple code -
protected void BtnRefresh_Click(object sender, EventArgs e)
{
//check object session
LoginSessionData.IsValid();
//Hide the display panel
DisplayMessage.Visible = false;
//add a try catch block here
try
{
ReportViewer1.LocalReport.Refresh();
}
catch (Exception ex)
{
m_logger.Error(ex);
}
}
You can set parameter values to blank or otherwise using this:
ReportParameter p1 = new
ReportParameter("ShowDescriptions", checkBox1.Checked.ToString());
ReportParameter p2 = new
ReportParameter("MyDate", DateTime.Now.ToString());
ReportViewer1.LocalReport.SetParameters(new ReportParameter[] { p1, p2 });

Asp.Net on refresh, a duplicate post is inserted...should only be one post

I have a asp:textbox that allows a user to enter information. When the user clicks the asp:button, it inserts the text from the textbox into my sql database, and then redirects back to the page. If the user hits refresh, the event from the button gets called again. I need to rectify this so that it no longer gets called or it doesn't repost the information.
protected void PostButton_Click(object sender, EventArgs e)
{
if (txtWallPost.Text.Length > 0)
{
string strCon = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["SocialSiteConnectionString"].ConnectionString;
using (SqlConnection conn = new SqlConnection(strCon))
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "INSERT INTO [WallTable] ([UserId], [FriendId], [WallPost]) VALUES (#UserId, #FriendId, #WallPost)";
cmd.Parameters.AddWithValue("#UserId", User.Identity.Name);
cmd.Parameters.AddWithValue("#FriendId", User.Identity.Name);
cmd.Parameters.AddWithValue("#WallPost", txtWallPost.Text);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
txtWallPost.Text = "";
LoadWallPosts();
Response.Redirect("~/UserPages/UserProfile.aspx?view="+"wall");
}
}
}
return;
}
Classic problem, with a classic solution: Redirect After Post. You just need to redirect the user to another page (or the same page...) after processing the POST - that way when they hit refresh, the last request (and the one to be repeated) will be a GET.
See:
Refresh the page after a postback action in asp.net
How do I use the “Post/Redirect/Get” a.k.a. “Redirect after Post” with asp.net
Page Refresh Causes Duplicate POST in ASP.NET Applications
Curing the “Back Button Blues”
I ended up just adding a session id for the wall post text. In the post method, it checks to make sure the textbox text, is different from that of the session text. On refresh it clears out the session and therefore works fine.

asp.net gridview sort without data rebind

I am trying to make a gridview sortable which uses a stored procedure as a datasource, I would not want it to rerun the query each time to achieve this. How would I get it to work my current code is:
protected override void OnPreRender(EventArgs e)
{
if (!IsPostBack)
{
SqlCommand cmd2 = new SqlCommand("SR_Student_Course_List", new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["RDCV2ConnectionString"].ConnectionString));
try
{
cmd2.CommandType = CommandType.StoredProcedure;
cmd2.CommandTimeout = 120;
cmd2.Parameters.Add("student_id", SqlDbType.Char, 11).Value = student;
cmd2.Connection.Open();
grdCourses.DataSource = cmd2.ExecuteReader();
grdCourses.DataSourceID = string.Empty;
grdCourses.DataBind();
} finally
{
cmd2.Connection.Close();
cmd2.Connection.Dispose();
cmd2.Dispose();
}}}
This code just binds the data when it isn't a postback, the gridview has viewstate enabled. On pressing the column headers a postback happens but no sorting occurs. If anyone has a simple fix for this please let me know or even better an ajax sort which would avoid the postback would be even better. The dataset is relatively small however takes a long time to query which is why I would not like to requery on each sort.
If you are not paging the results, and just doing a read, then something like the jquery tablesorter plugin would be a quick and easy fix. I have used this on tables of up to 1400 rows and works great, although ~> few hundred probably better on slow putas.
If the gridview is editable, then aspnet event/input validation might spit a dummy if you don't go through the proper registration of client scripts etc.
You could try storing the data in view state (or cache).
In your case, I would use a SqlDataAdapter and fill a DataTable. Then, put the DataTable into a Session variable. When the GridView is sorting, check if the Session variable still exists. If it does not, then fill the DataTable again. Finally sort the DataTable using a DataView and rebind the GridView with the DataView.

Resources