How to prevent a user from resubmitting a form? - asp.net

I am developping a Single Page Application.
At the end of the application, the user gets to submit his contact information (name, phone number, etc). This sends an Email and modifies the page to a "Thanks for submitting [...]" page.
The problem is, the client can press the Back button and REsend the Email.
Is there a way to prevent this sort of.. spam?
Code
Sub BT_Send(sender As Object, e As EventArgs) Handles BT_Send.Click
Try
'Creating the Email Message
Dim mailMessage As New MailMessage()
mailMessage.To.Add("SomeOne#a.com")
mailMessage.From = New MailAddress("Robot#a.com", "Robot")
mailMessage.Subject = "Test"
mailMessage.IsBodyHtml = True
mailMessage.Body = LBL_Emailbody.Text & _
"<br><br><br><div style=""font-size: 0.7em;"">Robot speaking, I will not answer if you send me a message.</div>"
Dim smtpClient As New SmtpClient("Something.com")
smtpClient.Send(mailMessage)
PNL_Before.Visible = False
PNL_After.Visible = True
Catch ex As Exception
LBL_errorEmail.Visible = True
'Should never happen...
End Try
End sub

Here is a very simple example, where I use a static variable on page and avoid database.
the asp.net page is
<asp:Literal runat="server" ID="txtInfos"></asp:Literal><br />
<asp:TextBox runat="server" ID="txtEmail"></asp:TextBox><br />
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />/>
and the code behind.
static Dictionary<string, DateTime> cLastSubmits = new Dictionary<string, DateTime>();
private static readonly object syncLock = new object();
protected void Button1_Click(object sender, EventArgs e)
{
DateTime cWhenLast;
lock (syncLock)
{
var cNowIs = DateTime.UtcNow;
if (cLastSubmits.TryGetValue(txtEmail.Text, out cWhenLast))
{
if (cWhenLast > cNowIs )
{
txtInfos.Text = "Please contact us again after 10 seconds";
return;
}
else
{
// ok I let him submit the form, but note the last date time.
cLastSubmits.Remove(txtEmail.Text);
}
}
foreach(var DelMe in cLastSubmits.Where(x => cNowIs > x.Value).ToList())
cLastSubmits.Remove(DelMe.Key);
// if reach here, note the last datetime of submit
cLastSubmits.Add(txtEmail.Text, cNowIs.AddSeconds(10));
}
// and submit the form.
txtInfos.Text = "thank you for submit the form";
}
Some notes.
If you have many pools (web garden), then this may left user to
submit at the same time up to the pool you have.
Of course if a user submit fake data this can not protect you, and thats why we can use:
The honey pot trick.
captcha
Other control thats understands the bots
Code that understand the re-submit.

Related

session not working asp.net

I got a problem this session :
it's not working
protected bool ValidateForm()
{
if (username.Text == "")
{
Err.Text = "please enter username" + "<br/>";
return false;
}
if (password.Text == "")
{
Err.Text = "please enter password" + "<br/>";
return false;
}
return true;
}
protected void login_Click(object sender, EventArgs e)
{
if (ValidateForm())
{
SqlDataReader rd1 = Connection.Query("select count(id) as count from sarcadmintable where username ='" + username.Text+"'",true);
if(rd1.Read())
{
if (rd1["count"].ToString() == "0") Err.Text = "please check your username" + "<br/>";
else
{
SqlDataReader rd = Connection.Query("select * from sarcadmintable where username ='" + username.Text + "'", true);
if (rd.Read())
{
if (rd["password"].ToString() != password.Text)
Err.Text = "password is not correct" + "<br/>";
else
{
Session["id"] = rd["user_id"].ToString();
Session["prev"] = rd["prev"].ToString();
if (!String.IsNullOrEmpty(Request.QueryString["Return"].ToString()))
Response.Redirect(Encryption.Decypt_URL(Request.QueryString["Return"]));
else
Response.Redirect("Main/Default.aspx");
}
}
}
}
}
}
thats the code for login its work fine
... in the header of the master.site I put this code :
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (Session["user_id"] == null || Session["user_id"].ToString() == "" || Session["user_id"].ToString() == "0") Response.Redirect("~/Login.aspx?Return=" + Encryption.Encypt_URL(Request.Url + ""));
SqlDataReader rd = Connection.Query("select firstname + ' ' + lastname as name from sarcuser where id=" + int.Parse(Session["id"].ToString()), true);
if (rd.Read())
{
label1.Text = rd["name"].ToString();
}
}
}
and in the web.config :
<!--<sessionState cookieless="true" regenerateExpiredSessionId="true" timeout="525600" mode="InProc" stateNetworkTimeout="525600"/>-->
<globalization requestEncoding="utf-8" responseEncoding="utf-8" culture="he-IL"/>
</system.web>
I make the session as a comment so I take the default for session
but its not working ... every time I press login with true username and password ... its redirect me to the login page ... and take the session as empty string
but the login code is fine and recover the right value ... any help ?
Consider this code in Page_Load
if (Session["user_id"] == null || Session["user_id"].ToString() == "" || Session["user_id"].ToString() == "0") Response.Redirect("~/Login.aspx?Return=" + Encryption.Encypt_URL(Request.Url + ""));
you are checking for user_id (Session["user_id"]) while you are storing with key id (Session["id"] = ....) in login button click handler
Edit: The above solution added
Previously provided out of context answer, left below as I think it may be useful for someone to know about this
The code that you are writing in the Page_Load event handler of master page, put that code in PreRender event handler and your label will be updated properly.
protected override void OnPreRender(EventArgs e)
{
if (!IsPostBack)
{
if (Session["user_id"] == null || Session["user_id"].ToString() == "" || Session["user_id"].ToString() == "0")
Response.Redirect("~/Login.aspx?Return=" + Encryption.Encypt_URL(Request.Url + ""));
SqlDataReader rd = Connection.Query("select firstname + ' ' + lastname as name from sarcuser where id=" + int.Parse(Session["id"].ToString()), true);
if (rd.Read())
{
label1.Text = rd["name"].ToString();
}
}
}
Now why this is happening?
This is happening because the Page_Load of the master page is called before the button_Click of the content page (Refer: Sequence that events are raised for Pages, UserControls, MasterPages and HttpModules. So the execution happens as follows:
Your browser request the page (login.aspx)
Login class is instantiated
OnPreInit of Login page is invoked (which specifies the master page)
Master page is instantiated
Login.Page_Load is executed
Master.Page_Load is executed
Your browser is requested to redirect to login.aspx
Execution terminates (why? because Response.Redirect causes current thread to terminate. If you want to prevent this abnormal termination and execute the complete page, pass 'false' as second parameter to Response.Redirect(url, false)
So, as you can see above, your button_click is never executed.
How to make user login
There are multiple options:
Do not use the same master page for the login page.
On the master page, check if current page is login.aspx, ignore the checking of login
Create a master page that specify the UI design and functionality that is same across public and authenticated access (call this master1.master). Create another master page (master2.master) which specify the check for authenticated user and functionality specific to authenticated user. Now login page will user master1.master as the master page and authenticated pages will user master2.master as master page. (somewhat same as first point, but the UI design is now placed in one master page only)
Any other that developers out there could suggest
Note: As suggested above, checking for authenticated user in PreRender is not recommended at all (that was just to update the label) as it may cause some code to be executed which should be prevented in one case or the other.
I don't see any actual user.authenticate() in your code. Is your page managed by another layer of authentication somewhere? For eg. I go to an open page, enter my credentials, you check my credentials, redirect me to a page that authenticates me and then boom I am back at login page. Also you might consider moving your authentication to the page_init unless you want to do it on every postback. I think you need to post a bit more here.

Log-in control if username is not found the label text should answer username not found

got a few question here. As you all know ive created a class wherein ill just instantiate it on my .aspx page.On my .aspx page ive got a logincontrol named login1. Now im getting error when user.UserName = Nothing and stop on this user.UserName = Nothing saying Object reference not set to an instance of an object..Could you help me debug the problem. All i want is that if the username is not on the database the lblmessage should say Error Username is invalid and if it is correct then it will check on the password. Please do help. Thanks and more power guys.
Aspx page
Protected Sub LoginButton_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim user As New User
Dim userDAL As New UserDAL
user = userDAL.SelectByUsername(Login1.UserName)
If user.UserName = Nothing Then
Login1.FailureText = "Invalid Username"
Else
If Login1.Password <> user.Password Then
Login1.FailureText = "Invalid password"
Else
Login1.FailureText = "success"
End If
End If
End Sub
UserDAL.vb
Public Function SelectByUsername(ByVal userName As String) As User
Try
'select * from User where Username = 'userName'
Dim sqlConn As New SqlConnection(_connString)
sqlConn.Open()
Dim sqlCmd As New SqlCommand("select * from [Users] where Username = '" & userName & "'", sqlConn)
Dim dr As SqlDataReader = sqlCmd.ExecuteReader()
'Create user collection
Dim user As User = Nothing
While dr.Read()
'Create User object
user = New User
user.UserName = dr("UserName").ToString
user.Password = dr("Password").ToString
user.FirstName = dr("FirstName").ToString
user.Surname = dr("Surname").ToString
End While
dr.Close()
Return user
Finally
If _sqlConn IsNot Nothing Then
If _sqlConn.State = Data.ConnectionState.Open Then
_sqlConn.Close()
End If
End If
End Try
Return Nothing
End Function
Instead of comparing with user.Username, first you compare with only user i.e.,
If user Is Nothing Then
Why Bcoz in your SelectByUsername function you are returning Nothing if it is invalid username. Try it and reply.
I would go with the simplest answer on this. Add a validation Summary to your control that returns the required value ("Username Not Valid") and then in your code to validate do a
if(Page.IsValid) (This is C# code but VB should be very close to this)
That should solve your problem.
Here's a quick snippet
<asp:TextBox id="TextBox1" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator id="RequiredFieldValidator1" runat="server" ErrorMessage="User Name Not Valid" ControlToValidate="TextBox1"></asp:RequiredFieldValidator>
Now of note this error message would display to the right of the text box, however you can style it or even set it to a validation group.
The required field validator or validation group with a validation summary forces client side validation with ASP.NET for postback so when the submit button fires it will run a test and determine if Page.IsValid == true or false;
http://msdn.microsoft.com/en-us/library/aa479013.aspx

Insert data into Access database upon checkbox-click event of ASP.net

I'm trying to make asp.net page
Criteria
I have product list. (using listview)
ProductID Proudct name Price ADD TO CART(checkbox)
Now I am using access 2007 for database. C# for code behind file. I want add product in to database which is on the event of checkbox. So if user check 10 item check box Out of 20 . I want write insert query on event of checkbox
Is it possible to do it? If it possible please provide me knowledge/ code how can I do it?
Please keep in mid that I am new and learning stage so make it easy or put gudieline in comments.
It sounds like you want to use the OnCheckedChanged event.
<asp:CheckBox ID="CheckBox1" runat="server" Text="Hello World!" OnCheckedChanged="CheckBox1_CheckedChanged" />
And in your code behind:
protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
//CREATE CONNETION HERE
OleDbConnection conn = new OleDbConnection ("<YOUR CONNECTION STRING HERE>");
OleDbCommand command = new OleDbCommand();
command.Connection = conn;
//CREATE YOUR OWN INSERT/UPDATE COMMAND HERE
command.CommandText= "<YOUR COMMAND TEXT HERE>";
command.Parameters.Add ("#Argument1", OleDbType.String).Value = CheckBox1.Text;
command.ExecuteNonQuery();
conn.Close();
}

How to indicate create user control if user already exists

I am using Create User control with my own sql server database, I am not sure what event is there which can indicate the create user control to show its Duplicate UserName Error Message if there is an existing Username or email.
Please let me know.
thanks,
If you were using aspnet membership then CreateUser Control would have done the work itself. But from your question I guess you are not using so. In this case you will have to use logic to check for existing username. You can use Custom Validator and create a server side validation with it.
Example:
.aspx
<asp:TextBox ID="txtUserName" runat="server" MaxLength="150"></asp:TextBox>
<asp:CustomValidator ID="CustomValidator1" runat="server" OnServerValidate="CustomValidator1_ServerValidate"
ControlToValidate="txtUserName" Display="Dynamic"
ErrorMessage="UserName Already Exists"
ToolTip="Please select a different UserName" ValidationGroup="Register">
</asp:CustomValidator>
The code behind can have:
protected void CustomValidator1_ServerValidate(object source, ServerValidateEventArgs args)
{
SqlCommand objcmd = new SqlCommand("Select * from Login_Table where UserName='" + args.Value + "'",con);
SqlDataReader objReader;
con.Open();
objReader = objcmd.ExecuteReader();
if (objReader.HasRows)
{
args.IsValid = false;
}
else {
args.IsValid = true;
}
con.Close();
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
if (!Page.IsValid)
{
return;
}
// your registration code
}
Remember to keep the submit button under the same Validation Group as the Custom Validator i.e. "Register" in this case. You can have the control inside ajax update panel further. Hope this helps :)

ASP.NET Web Page Not Available

It's pretty difficult to show code for ASP.NET here, so I will try my best to describe my problem.
I have a FileUploadControl and a Button that calls a function when it's clicked. It seems that the Button function works when there is nothing chosen for my FileUploadControl. However, when there is something chosen in the FileUploadControl (I have selected a file to upload), there is a problem when I click the button. It completely does not matter what the function does (it could just be writing to a label, even when it has nothing to do with the FileUploadControl). The error I get is:
This webpage is not available.
The webpage at http://localhost:2134/UploadMedia/Default.aspx might be temporarily down or it may have moved permanently to a new web address.
I have searched on Google, and people seem to have had problems with this, but different causes from me. They have said that their ASP.NET Development Server port is actually different from their port in the address bar. This is not the case for me.
Also, another problem people have had is with Use Dynamic Ports. I have tried both true and false. I have also tried different ports, and I have always gotten the same error.
This is really driving me crazy because it doesn't matter what the code in the buttonFunction is, it doesn't work as long as there is something in the FileUploadControl. If there is nothing, it seems to work fine.
Here is the code for the ASP.NET Controls:
<asp:FileUpload id="FileUploadControl" runat="server" />
<asp:Button runat="server" id="UploadButton" text="Upload" OnClick="uploadClicked" />
<br /><br />
<asp:Label runat="server" id="StatusLabel" text="Upload status: " />
And this is the code for the button function:
protected void uploadClicked(object sender, EventArgs e)
{
if (FileUploadControl.HasFile)
{
string filename = Path.GetFileName(FileUploadControl.FileName);
//Check if the entered username already exists in the database.
String sqlDupStmt = "Select songPath from Songs where songPath ='" + Server.MapPath("~/Uploads/") + filename + "'";
SqlConnection sqlDupConn = new SqlConnection(#"Data Source = .\SQLEXPRESS; AttachDbFilename = |DataDirectory|\Database.mdf; Integrated Security = True; User Instance = True;");
SqlCommand sqlDupCmd = new SqlCommand(sqlDupStmt, sqlDupConn);
sqlDupCmd.Connection.Open();
SqlDataReader sqlDupReader = sqlDupCmd.ExecuteReader(CommandBehavior.CloseConnection);
if (sqlDupReader.Read())
{
StatusLabel.Text = "Upload status: The file already exists.";
sqlDupReader.Close();
}
else
{
sqlDupReader.Close();
//See "How To Use DPAPI (Machine Store) from ASP.NET" for information about securely storing connection strings.
String sqlStmt = "Insert into Songs values (#songpath);";
SqlConnection sqlConn = new SqlConnection(#"Data Source = .\SQLEXPRESS; AttachDbFilename = |DataDirectory|\Database.mdf; Integrated Security = True; User Instance = True; uid=sa; pwd=password;");
SqlCommand cmd = new SqlCommand(sqlStmt, sqlConn);
SqlParameter sqlParam = null;
//Usage of Sql parameters also helps avoid SQL Injection attacks.
sqlParam = cmd.Parameters.Add("#userName", SqlDbType.VarChar, 150);
sqlParam.Value = Server.MapPath("~/Uploads/") + filename;
//Attempt to add the song to the database.
try
{
sqlConn.Open();
cmd.ExecuteNonQuery();
FileUploadControl.SaveAs(Server.MapPath("~/Uploads/") + filename);
songList.Items.Add(filename);
StatusLabel.Text = "Upload status: File uploaded!";
}
catch (Exception ex)
{
StatusLabel.Text = "Upload status: The file could not be uploaded. The following error occured: " + ex.Message;
}
finally
{
sqlConn.Close();
}
}
}
}
But this buttonfunction provides the same results:
protected void uploadClicked(object sender, EventArgs e)
{
StatusLabel.Text = "FooBar";
}
Has anyone had this problem before, or might know what the cause is?
Thanks!
My friend helped me figure it out. It was because ASP.NET only allowed uploads of 4MB sizes. I had to go into the web.config or the machine.config file and change the value of MaxRequestLength to be larger than 4096. This solved it.

Resources