Form Authentication in ASP.net - c#

Greetings of the day!
I'm using Form Authentication, in registration it is OK, but while login, it's doing wrong, it is just doing opposite.
In Registration, suppose I entered password 123, now it will convert that password using form-authentication, and save in DB, now while login, if user enter 123 then it will be changed, and try to match with the stored one in DB.
In my case, it is doing opposite, if both password match, it shows, custom error message..and if not then increase counter variable for locking account
Please go over my code, and help me out....
Database:-
CREATE TABLE [dbo].[tblUsers](
[ID] [int] IDENTITY(1,1) NOT NULL,
[UserName] [nvarchar](15) NULL,
[Password] [nvarchar](15) NULL,
[Email] [nvarchar](200) NULL,
[RetryAttempts] [int] NULL,
[IsLocked] [bit] NULL,
[LockedDateTime] [datetime] NULL,
PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE proc [dbo].[sp_RegisterUser]
#UserName nvarchar(15),
#Password nvarchar(15),
#Email nvarchar(200)
As
Begin
Declare #Count int
Declare #ReturnCode int
Select #Count= COUNT(UserName) from tblUsers where UserName=#UserName
if(#Count=1)
Begin
Set #ReturnCode=-1
End
else
Begin
Set #ReturnCode=1
insert into tblUsers(UserName,Password,Email) values(#UserName,#Password,#Email)
End
Select #ReturnCode as ReturnValue
End
CREATE proc [dbo].[SP_AuthenticateUser]
#UserName nvarchar(15),
#Password nvarchar(15)
As
Begin
Declare #Count int
Declare #RetryCount int
Declare #AccountLocked bit
Select #AccountLocked= ISNULL(IsLocked,0) from tblUsers where UserName=#UserName
If(#AccountLocked=1)
Begin
Select 1 as AccountLocked,0 as Authenticate,0 as RetryAttempts
End
Else
Begin
Select #Count= COUNT(UserName) from tblUsers where UserName=#UserName and Password=#Password
If(#Count=1)
Begin
Select 0 as AccountLocked,1 as Authenticate,0 as RetryAttempts
End
Else
Begin
Select #RetryCount=ISNULL(RetryAttempts,0) from tblUsers where UserName=#UserName
Set #RetryCount=#RetryCount+1
If(#RetryCount<=3)
Begin
Update tblUsers set RetryAttempts=#RetryCount where UserName=#UserName
Select 0 as AccountLocked,0 as Authenticate,#RetryCount as RetryAttempts
End
Else
Begin
Update tblUsers set IsLocked=1,LockedDateTime=GETDATE() where UserName=#UserName
Select 1 as AccountLocked,0 as Authenticate,0 as RetryAttempts
End
End
End
End
Design:-
Registration_Page-
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Registration.aspx.cs" Inherits="Registration" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div style="font-family:Arial">
<table style="border: 1px solid black">
<tr>
<td colspan="2">
<b>User Registration</b>
</td>
</tr>
<tr>
<td>
User Name
</td>
<td>
:<asp:TextBox ID="txtUserName" runat="server">
</asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidatorusername"
runat="server" ErrorMessage="User Name required" Text="*"
ControlToValidate="txtUserName" ForeColor="Red">
</asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td>
Password
</td>
<td>
:<asp:TextBox ID="txtPassword" TextMode="Password" runat="server">
</asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidatorPassword"
runat="server" ErrorMessage="Password required" Text="*"
ControlToValidate="txtPassword" ForeColor="Red">
</asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td>
Confirm Password
</td>
<td>
:<asp:TextBox ID="txtConfirmPassword" TextMode="Password" runat="server">
</asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidatorConfirmPassword"
runat="server" ErrorMessage="Confirm Password required" Text="*"
ControlToValidate="txtConfirmPassword" ForeColor="Red"
Display="Dynamic"></asp:RequiredFieldValidator>
<asp:CompareValidator ID="CompareValidatorPassword" runat="server"
ErrorMessage="Password and Confirm Password must match"
ControlToValidate="txtConfirmPassword" ForeColor="Red"
ControlToCompare="txtPassword" Display="Dynamic"
Type="String" Operator="Equal" Text="*">
</asp:CompareValidator>
</td>
</tr>
<tr>
<td>
Email
</td>
<td>
:<asp:TextBox ID="txtEmail" runat="server">
</asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidatorEmail"
runat="server" ErrorMessage="Email required" Text="*"
ControlToValidate="txtEmail" ForeColor="Red"
Display="Dynamic"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="RegularExpressionValidatorEmail"
runat="server" ErrorMessage="Invalid Email" ControlToValidate="txtEmail"
ForeColor="Red" Display="Dynamic" Text="*"
ValidationExpression="\w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*">
</asp:RegularExpressionValidator>
</td>
</tr>
<tr>
<td>
</td>
<td>
<asp:Button ID="btnRegister" runat="server" Text="Register"
onclick="btnRegister_Click"/>
</td>
</tr>
<tr>
<td colspan="2">
<asp:Label ID="lblMessage" runat="server" ForeColor="Red">
</asp:Label>
</td>
</tr>
<tr>
<td colspan="2">
<asp:ValidationSummary ID="ValidationSummary1" ForeColor="Red" runat="server" />
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
Login Page:_
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div style="font-family:Arial">
<table style="border: 1px solid black">
<tr>
<td colspan="2">
<b>Login</b>
</td>
</tr>
<tr>
<td>
User Name
</td>
<td>
:<asp:TextBox ID="txtUserName" runat="server">
</asp:TextBox>
</td>
</tr>
<tr>
<td>
Password
</td>
<td>
:<asp:TextBox ID="txtPassword" TextMode="Password" runat="server">
</asp:TextBox>
</td>
</tr>
<tr>
<td>
<asp:CheckBox ID="chk_boxRememberMe" runat="server" Text="Remember Me" />
</td>
<td>
<asp:Button ID="btnLogin" runat="server" Text="Login" OnClick="btnLogin_Click" />
</td>
</tr>
<tr>
<td>
<asp:Label ID="lblMessage" runat="server" ForeColor="Red"></asp:Label>
</td>
</tr>
</table>
<br />
Click here to register
if you do not have a user name and password.
</div>
</form>
</body>
</html>
Code Behind:-
Registration Page:-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web.Security;
public partial class Registration : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnRegister_Click(object sender, EventArgs e)
{
if (Page.IsValid)
{
string CS = ConfigurationManager.ConnectionStrings["con"].ConnectionString;
using (SqlConnection Conn=new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("sp_RegisterUser",Conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter UserName = new SqlParameter("#UserName",txtUserName.Text);
string EncryptPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text, "SHA1");
SqlParameter Password = new SqlParameter("#Password", EncryptPassword);
SqlParameter Email = new SqlParameter("#Email", txtEmail.Text);
cmd.Parameters.Add(UserName);
cmd.Parameters.Add(Password);
cmd.Parameters.Add(Email);
Conn.Open();
int ReturnCode=(int) cmd.ExecuteScalar();
if (ReturnCode==-1)
{
lblMessage.Text = "User Name alredy exists";
}
else
{
Response.Redirect("~/Login.aspx");
}
}
}
}
}
Login Page:-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web.Security;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnLogin_Click(object sender, EventArgs e)
{
//Login_WebConfig();
// Login_DataBase();
if (AuthenticateUser(txtUserName.Text, txtPassword.Text))
{
FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, chk_boxRememberMe.Checked);
}
else
{
lblMessage.Text = "Invalid username/password";
}
}
//protected void Login_WebConfig()
//{
// if (FormsAuthentication.Authenticate(txtUserName.Text, txtPassword.Text))
// {
// FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, chk_boxRememberMe.Checked);
// }
// else
// {
// lblMessage.Text = "Invalid user name/password";
// }
//}
protected void Login_DataBase()
{
}
private bool AuthenticateUser(string username, string password)
{
string CS = ConfigurationManager.ConnectionStrings["con"].ConnectionString;
using (SqlConnection Conn = new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("SP_AuthenticateUser", Conn);
cmd.CommandType = CommandType.StoredProcedure;
string EncryptPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(password, "SHA1");
SqlParameter paramUserName = new SqlParameter("#UserName", username);
SqlParameter paramPassword = new SqlParameter("#Password", EncryptPassword);
cmd.Parameters.Add(paramUserName);
cmd.Parameters.Add(paramPassword);
Conn.Open();
int ReturnCode = (int)cmd.ExecuteScalar();
return ReturnCode == 1;
}
}
}
Web Config:-
<?xml version="1.0"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<authentication mode="Forms">
<forms loginUrl="Login.aspx" defaultUrl="Welcome.aspx" timeout="2" protection="All">
<!--<credentials passwordFormat="Clear">
<user name="rkbisht" password="1234"/>
</credentials>-->
</forms>
</authentication>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
<appSettings>
<add key="ValidationSettings:UnobtrusiveValidationMode" value="None" />
</appSettings>
<connectionStrings>
<add name="con" connectionString="Data Source=.;Initial Catalog=Security_Learning;Integrated Security=true"/>
</connectionStrings>
</configuration>

Basically, you are not using the right tool for the job.
You are not acutually using FormsAuthentication and you are also not saving the hash in a config file so FormsAuthentication.HashPasswordForStoringInConfig is not what you should be using.
It is worth taking the time to get this right. Here is a starting point:
https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/consumer-apis/password-hashing
Note, you should be using a hash and a salt, the salt should be unique to each user.
Personally I use the Microsoft.AspNetCore.Cryptography.KeyDerivation nuget package with an implementation similar to the following:
Helper Class
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
using Resources;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
public static class SecurityHelper
{
public static int DefaultIterations = 10000
//KeyDerivation.Pbkdf2
/// <summary>
/// Generates a random salt
/// </summary>
/// <returns>A byte array containing a random salt</returns>
public static byte[] GetRandomSalt()
{
byte[] saltBytes = new byte[32];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetNonZeroBytes(saltBytes);
return saltBytes;
}
public static string GeneratePasswordHash(string plainPassword, int iterations, out string generatedRandomSalt)
{
generatedRandomSalt = Convert.ToBase64String(GetRandomSalt());
return Convert.ToBase64String(ComputeHash(plainPassword, generatedRandomSalt, iterations));
}
public static string GetPasswordHash(string plainPassword, string existingSalt, int iterations)
{
return Convert.ToBase64String(ComputeHash(plainPassword, existingSalt, iterations));
}
private static byte[] ComputeHash(string plainText, string salt, int iterations)
{
return KeyDerivation.Pbkdf2(
password: plainText,
salt: Convert.FromBase64String(salt),
prf: KeyDerivationPrf.HMACSHA256,
iterationCount: iterations,
numBytesRequested: 32);
}
}
Your workflow now changes:
When you save the password, you need to save the salt as well
When authenticating the user, get the user by UserName from the database, calculate the hash for the entered password, using the saved salt, compareing the result with the saved hash.
Roughly
//Registration
using (SqlConnection Conn=new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("sp_RegisterUser",Conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter UserName = new SqlParameter("#UserName",txtUserName.Text);
string Salt = string.Empty;
string Password = SecurityHelper.GeneratePasswordHash(txtPassword.Text, SecurityHelper.DefaultIterations, out salt);
;
SqlParameter Password = new SqlParameter("#Password", Password);
SqlParameter Email = new SqlParameter("#Email", txtEmail.Text);
SqlParameter Salt = new SqlParameter("#Salt", Salt);
cmd.Parameters.Add(UserName);
cmd.Parameters.Add(Password);
cmd.Parameters.Add(Email);
Conn.Open();
int ReturnCode=(int) cmd.ExecuteScalar();
if (ReturnCode==-1)
{
lblMessage.Text = "User Name alredy exists";
}
else
{
Response.Redirect("~/Login.aspx");
}
}
//Log In
private bool AuthenticateUser(string username, string password)
{
//Get the following from your database based on username
string savedHash = //fromDB;
string savedSalt = //fromDb;
return (SecurityHelper.GetPasswordHash(password, savedSalt, SecurityHelper.DefaultIterations) == tempUser.Password)
}
I've simplified this somewhat. I also save the iteration against the user in the database, in case we need to increase the default iterations.
My last bit of adivce, so some reading on why "salting" is a good thing.

Your authentication stored procedure (SP_AuthenticateUser) returns 3 columns but you are calling it using ExecuteScalar. You need to get the dataset and check the second column.
private bool AuthenticateUser(string username, string password)
{
string CS = ConfigurationManager.ConnectionStrings["con"].ConnectionString;
using (SqlConnection Conn = new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("SP_AuthenticateUser", Conn);
cmd.CommandType = CommandType.StoredProcedure;
string EncryptPassword = FormsAuthentication.HashPasswordForStoringInConfigFile(password, "SHA1");
SqlParameter paramUserName = new SqlParameter("#UserName", username);
SqlParameter paramPassword = new SqlParameter("#Password", EncryptPassword);
cmd.Parameters.Add(paramUserName);
cmd.Parameters.Add(paramPassword);
Conn.Open();
var reader = cmd.ExecuteReader();
reader.Read();
return reader["Authenticate"] as bool;
}
}
Also, make sure you reset the retry counter after successful authentication.
Select #Count= COUNT(UserName) from tblUsers where UserName=#UserName and Password=#Password
If(#Count=1)
Begin
Update tblUsers set RetryAttempts = 0 where UserName = #UserName
Select 0 as AccountLocked,1 as Authenticate,0 as RetryAttempts
End
Your code has a few other problems too, but those two are likely to be causing the behavior noted in your question.
Here is a better way to hash your password.
The user will have to keep signing on unless you set a forms auth cookie. Click here for ideas on how.
You probably don't need credentials in your web.config. You only need to put them there if you intend to use FormsAuthentication.Authenticate. You seem to be using a database instead.

Related

asp.net web application: Invalid postback or callback argument error on button click

I am working on developing an asp.net web application page with a set of cascading drop downs, text boxes and buttons on my page. The drop down lists are populated from the database and are dependent on previous drop downs. The buttons are supposed to write the selected values from the drop down and text boxes to the database.
The page gets loaded with the correct DDL lists. It works fine to write to the database if I only enter a value in the text box and click on the button.
It returns the following error if I select a value from the drop down list and enter a value in the text box and then click the button to add values to the database.
Error message:
"Invalid postback or callback argument. Event validation is enabled using in configuration or <%# Page EnableEventValidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation."
I did some research and understand there can be security implications if I set enableEventValidation="false", so I don't want to use that option.
What is the other option? How do I use ClientScriptManager.RegisterForEventValidation method as suggested in the error message?
Here is the code I am using: Since it is still under development, I have not added any validations on the DDL or Text Boxes, which I intend to do eventually.
newlevel.aspx
<%# Page Title="" Language="C#" MasterPageFile="~/Main.Master" `AutoEventWireup="true" CodeBehind="newlevels.aspx.cs" Inherits="COA.newlevels" `%>
<%# Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<%--<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>--%>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<div>
<table>
<tr>
<td>Totaling Level A</td>
<td>
<asp:DropDownList ID="ddlTotalingLevelA" runat="server" Width="250" OnSelectedIndexChanged="ddlTotalingLevelA_SelectedIndexChanged" ></asp:DropDownList>
<asp:CascadingDropDown ID="cdlTotalingLevelA" TargetControlID="ddlTotalingLevelA" PromptText="Select Totaling Level A"
PromptValue="" ServicePath="ServiceCS.asmx" ServiceMethod="GetLevelAList" runat="server"
Category="TOTALING_LEVEL_A" LoadingText="Loading..." />
</td>
</tr>
<tr>
<td>Totaling Level B</td>
<td>
<asp:DropDownList ID="ddlTotalingLevelB" runat="server" Width="250"></asp:DropDownList>
<asp:CascadingDropDown ID="cdlTotalingLevelB" TargetControlID="ddlTotalingLevelB" PromptText="Select Totaling Level B"
PromptValue="" ServicePath="ServiceCS.asmx" ServiceMethod="GetLevelBList" runat="server"
Category="TOTALING_LEVEL_B" ParentControlID="ddlTotalingLevelA" LoadingText="Loading..." />
</td>
<td><asp:TextBox ID="txtTotalingLevelB" runat="server" required></asp:TextBox></td>
<td>
<asp:Button ID="ButtonTotalingLevelB" runat="server" Text="Add New Totaling Level B" OnClick="ButtonTotalingLevelB_Click" />
</td>
</tr>
<tr>
<td>Totaling Level C</td>
<td>
<asp:DropDownList ID="ddlTotalingLevelC" runat="server" Width="250"></asp:DropDownList>
<asp:CascadingDropDown ID="cdlTotalingLevelC" TargetControlID="ddlTotalingLevelC" PromptText="Select Totaling Level C"
PromptValue="" ServicePath="ServiceCS.asmx" ServiceMethod="GetLevelCList" runat="server"
Category="TOTALING_LEVEL_C" ParentControlID="ddlTotalingLevelB" LoadingText="Loading..." />
</td>
<td><asp:TextBox ID="txtTotalingLevelC" runat="server"></asp:TextBox></td>
<td>
<asp:Button ID="ButtonTotalingLevelC" runat="server" Text="Add New Totaling Level C" OnClick="ButtonTotalingLevelC_Click" />
</td>
</tr>
<tr>
<td>Totaling Level D</td>
<td>
<asp:DropDownList ID="ddlTotalingLevelD" runat="server" Width="250"></asp:DropDownList>
<asp:CascadingDropDown ID="cdlTotalingLevelD" TargetControlID="ddlTotalingLevelD" PromptText="Select Totaling Level D"
PromptValue="" ServicePath="ServiceCS.asmx" ServiceMethod="GetLevelDList" runat="server"
Category="TOTALING_LEVEL_D" ParentControlID="ddlTotalingLevelC" LoadingText="Loading..." />
</td>
<td><asp:TextBox ID="txtTotalingLevelD" runat="server"></asp:TextBox></td>
<td>
<asp:Button ID="ButtonTotalingLevelD" runat="server" Text="Add New Totaling Level D" OnClick="ButtonTotalingLevelD_Click" />
</td>
</tr>
<tr>
<td>Totaling Level E</td>
<td>
<asp:DropDownList ID="ddlTotalingLevelE" runat="server" Width="250"></asp:DropDownList>
<asp:CascadingDropDown ID="cdlTotalingLevelE" TargetControlID="ddlTotalingLevelE" PromptText="Select Totaling Level E"
PromptValue="" ServicePath="ServiceCS.asmx" ServiceMethod="GetLevelEList" runat="server"
Category="TOTALING_LEVEL_E" ParentControlID="ddlTotalingLevelD" LoadingText="Loading..." />
</td>
<td><asp:TextBox ID="txtTotalingLevelE" runat="server"></asp:TextBox></td>
<td>
<asp:Button ID="ButtonTotalingLevelE" runat="server" Text="Add New Totaling Level E" OnClick="ButtonTotalingLevelE_Click" />
</td>
</tr>
<tr>
<td>Totaling Level F</td>
<td>
<asp:DropDownList ID="ddlTotalingLevelF" runat="server" Width="250"></asp:DropDownList>
<asp:CascadingDropDown ID="cdlTotalingLevelF" TargetControlID="ddlTotalingLevelF"
PromptValue="" ServicePath="ServiceCS.asmx" ServiceMethod="GetLevelFList" runat="server"
Category="TOTALING_LEVEL_F" ParentControlID="ddlTotalingLevelE" LoadingText="Loading..." />
</td>
<td><asp:TextBox ID="txtTotalingLevelF" runat="server"></asp:TextBox></td>
<td>
<asp:Button ID="ButtonTotalingLevelF" runat="server" Text="Add New Totaling Level F" OnClick="ButtonTotalingLevelF_Click" />
</td>
</tr>
</table>
</div>
</asp:Content>
newlevels.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;
using System.Configuration;
using System.Data;
namespace ChartOfAccounts
{
public partial class newlevels : System.Web.UI.Page
{
SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Chpcs"].ToString());
protected void Page_Load(object sender, EventArgs e)
{
}
protected void ButtonTotalingLevelB_Click(object sender, EventArgs e)
{
connection.Open();
SqlCommand cmd = connection.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "INSERT INTO [SCM].[LKP_TOTALING_LEVEL_B]([TOTALING_LEVEL_B],[TOTALING_LEVEL_A],[UNARY_OPERATOR],[SORTINGORDER]) VALUES('" + ddlTotalingLevelB.SelectedItem.Value + "','" + txtTotalingLevelB.Text + "','" + "','0')";
cmd.ExecuteNonQuery();
connection.Close();
}
protected void ButtonTotalingLevelC_Click(object sender, EventArgs e)
{
connection.Open();
SqlCommand cmd = connection.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "INSERT INTO [SCM].[LKP_TOTALING_LEVEL_B]([TOTALING_LEVEL_B],[TOTALING_LEVEL_A],[UNARY_OPERATOR],[SORTINGORDER]) VALUES('" + ddlTotalingLevelC.Text + "','" + txtTotalingLevelC.Text + "','" + "','0')";
cmd.ExecuteNonQuery();
connection.Close();
}
protected void ButtonTotalingLevelD_Click(object sender, EventArgs e)
{
connection.Open();
SqlCommand cmd = connection.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "INSERT INTO [SCM].[LKP_TOTALING_LEVEL_B]([TOTALING_LEVEL_B],[TOTALING_LEVEL_A],[UNARY_OPERATOR],[SORTINGORDER]) VALUES('" + ddlTotalingLevelD.Text + "','" + txtTotalingLevelD.Text + "','" + "','0')";
cmd.ExecuteNonQuery();
connection.Close();
}
protected void ButtonTotalingLevelE_Click(object sender, EventArgs e)
{
connection.Open();
SqlCommand cmd = connection.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "INSERT INTO [SCM].[LKP_TOTALING_LEVEL_B]([TOTALING_LEVEL_B],[TOTALING_LEVEL_A],[UNARY_OPERATOR],[SORTINGORDER]) VALUES('" + ddlTotalingLevelE.Text + "','" + txtTotalingLevelE.Text + "','" + "','0')";
cmd.ExecuteNonQuery();
connection.Close();
}
protected void ButtonTotalingLevelF_Click(object sender, EventArgs e)
{
connection.Open();
SqlCommand cmd = connection.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "INSERT INTO [SCM].[LKP_TOTALING_LEVEL_B]([TOTALING_LEVEL_B],[TOTALING_LEVEL_A],[UNARY_OPERATOR],[SORTINGORDER]) VALUES('" + ddlTotalingLevelF.Text + "','" + txtTotalingLevelF.Text + "','" + "','0')";
cmd.ExecuteNonQuery();
connection.Close();
}
protected void ddlTotalingLevelA_SelectedIndexChanged(object sender, EventArgs e)
{
}
}
}

OnClick button working only after second time Asp.NET c#

I'm new to web development and right now I'm working on a website. I have a problem with a Save button on an ASP.Net (front end) web form (back end is in C#). The button is supposed to save data entered in a textbox to a database.
When the Save button is clicked the first time, the page just 'reloads' and clear the textbox and nothing is saved in the SQL Server database (dbo connection). Then when I click the same 'Save' button a second time after re-entering information in the textbox, it actually saves to the database and goes back to a main menu page (as expected). And if I try to re-enter different information, the save button will be working just fine.
The problem happens when a user logs in and navigate to the page where he enters the data and saves it. It will never ever work the first time.
Unfortunately because of confidential purposes, I have to omit and rename certain file paths/directories and tables name!
Here's my Asp.NET code:
<%# Page Language="C#" debug="True" Inherits="Default" src="Default.cs" AutoEventWireup ="true"%>
<%# Register TagPrefix="ob" TagName="ComboTree" Src="/obout/Combotree/ComboTree.ascx" %>
<%# Reference Control="/obout/Combotree/ComboTree.ascx" %>
<HTML>
<HEAD>
<!-- #INCLUDE VIRTUAL="/.../" -->
</HEAD>
<BODY >
<FORM runat="server">
<BASEFONT face="Arial, Helvetica, Sans Serif" color=black size=2>
<TABLE height="100%" cellSpacing=0 cellPadding=0 width="780" align=Center border=0>
<!-- #INCLUDE VIRTUAL="/.../" -->
<TR VALIGN="top">
<!-- #INCLUDE VIRTUAL="/.../" -->
`enter code here`<TD vAlign=top width="100%" HEIGHT="100%">
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0 HEIGHT="100%">
<!-- #INCLUDE VIRTUAL="/.../" -->
<TR>
<!-- #INCLUDE VIRTUAL="/.../" -->
<TD vAlign=top align=left >
<!--- START YOUR CODE HERE!!!!! --->
<script>
function disableListItems(checkBoxListId, disable)
{
// Get the checkboxlist object.
ctr = 0;
while(1 == 1)
{
checkbox = document.getElementById(checkBoxListId + "_" + ctr);
if(checkbox == null)
{
return;
}
checkbox.checked = true;
checkbox.disabled = disable;
ctr++;
}
}
function checkForm()
{
var errMsg = "";
if(isBlank(document.getElementById("tbName").value))
{
errMsg += "\n-Folder Name";
}
if(errMsg!="")
{
alert("The following fields cannot be left blank." + errMsg);
return false;
}
return true;
}
</script>
<font Class="heading">File Library - <ASP:Label ID="lbTitle" RunAt="Server"/> Folder</font>
<INPUT Type="Hidden" ID="hdFolderID" RunAt="Server"/>
<INPUT Type="Hidden" ID="hdParentFolderID" RunAt="Server"/>
<TABLE CellPadding="4" CellSpacing="0" Width="100%" >
<TR>
<TD ColSpan="2" Class="spreadsheet_line"> </TD>
</TR>
<TR>
<TD Class="Spreadsheet"><B>Name</B></TD>
<TD Class="Spreadsheet" Width="100%"><ASP:TextBox ID="tbName" Columns="34" RunAt="Server"/></TD>
</TR>
<TR VAlign="Top" Visible="False" RunAt="Server">
<TD Class="Spreadsheet" NOWRAP><B>Description</B></TD>
<TD Class="Spreadsheet"><ASP:TextBox ID="tbDescription" TextMode="Multiline" Cols="25" Rows="5" RunAt="Server"/></TD>
</TR>
<TR>
<TD Class="Spreadsheet"><B>Active?</B></TD>
<TD Class="Spreadsheet"><ASP:CheckBox ID="cbActive" RunAt="Server"/></TD>
</TR>
<TR Visible="False" RunAt="Server">
<TD Class="Spreadsheet"><B>Folder</B></TD>
<TD Class="Spreadsheet"><ob:ComboTree id="ctFolders" runat="server"/></TD>
</TR>
<TR VAlign="Top" ID="trLicensees" RunAt="Server">
<TD Class="Spreadsheet"><B>Departments</B></TD>
<TD Class="Spreadsheet">
<ASP:DropDownList ID="ddLicensee" DataTextField="Name" DataValueField="DepartmentId" RunAt="Server"/>
<ASP:CheckBox ID="cbAll" Text="All" RunAt="Server"/>
<div style="text-align: left; width: 30%; margin-left:-3px">
<ASP:CheckBoxList ID="cblLicensees" DataTextField="Name" DataValueField="DepartmentId" style="background-color:F3F3F3" RunAt="Server"/> <!--**-->
</div>
</TD>
</TR>
<TR>
<TD Class="Spreadsheet" Align="Right" ColSpan="2">
<ASP:ImageButton ID="btnSave" OnClick="btnSave_OnClick" ImageUrl="/images/buttons/btnSave.gif" RunAt="Server"/>
</TD>
</TR>
</TABLE>
<!--- END YOUR CODE HERE!!!!! --->
</TD>
<!-- #INCLUDE VIRTUAL="/.../" -->
</TR>
<!-- #INCLUDE VIRTUAL="/.../" -->
</TABLE>
</TD>
<!-- #INCLUDE VIRTUAL="/.../" -->
</TR>
<!-- #INCLUDE VIRTUAL="/.../" -->
</TABLE>
</BASEFONT>
</FORM>
</BODY>
</HTML>
And here's the (back end) code for the Save button written in C#:
public void btnSave_OnClick(object sender, System.Web.UI.ImageClickEventArgs E){
int counter = int.Parse(Request.Cookies["counter"].Value);
counter++;
Response.Cookies["counter"].Value = counter.ToString();
try{
SqlConnection Conn = GetConnection();
string SQL;
SqlCommand Cmd;
SqlDataReader Dtr;
if(hdFileID.Value=="")
{
Response.Write("Executing Save (adding new folder to DB");
SQL = "EXEC sp_File_Add #Name,#Description,#UserID";
Response.Write("Save successfully executed. Added to DB");
}
else
{
Response.Write("Executing Save (saving info of folder to DB");
SQL = "EXEC sp_File_Update #Name,#Description,#UserID,#FileID";
Response.Write("Save successfully executed. Saved to DB");
}
Cmd = new SqlCommand(SQL,Conn);
Cmd.Parameters.Add(new SqlParameter("#Name", SqlDbType.VarChar));
Cmd.Parameters["#Name"].Value = tbName.Text;
Cmd.Parameters.Add(new SqlParameter("#Description", SqlDbType.Text));
Cmd.Parameters["#Description"].Value = tbDescription.Text;
Cmd.Parameters.Add(new SqlParameter("#UserID", SqlDbType.Int));
Cmd.Parameters["#UserID"].Value = Convert.ToInt32(hdUserID_Global.Value);
if(hdFileID.Value!="")
{
Cmd.Parameters.Add(new SqlParameter("#FileID", SqlDbType.Int));
Cmd.Parameters["#FileID"].Value = Convert.ToInt32(hdFolderID.Value);
}
Cmd.ExecuteNonQuery();
if(hdFileID.Value=="")
{
SQL = "SELECT MAX(FileID) AS FileID FROM tbl_File WHERE CreatedByUserID=#UserID";
Cmd = new SqlCommand(SQL,Conn);
Cmd.Parameters.Add(new SqlParameter("#UserID", SqlDbType.Int));
Cmd.Parameters["#UserID"].Value = Convert.ToInt32(hdUserID_Global.Value);
Dtr = Cmd.ExecuteReader();
if(Dtr.Read())
{
hdFileID.Value = Dtr["FileID"].ToString();
}
Dtr.Close();
}
SQL = "DELETE FROM tbl_FileLicense ";
SQL += " WHERE FileID=#FileID ";
Cmd = new SqlCommand(SQL,Conn);
Cmd.Parameters.Add(new SqlParameter("#FileID", SqlDbType.Int));
Cmd.Parameters["#FileID"].Value = Convert.ToInt32(hdFileID.Value.ToString());
Cmd.ExecuteNonQuery();
if(ddLicense.Visible)
{
SQL = "EXEC sp_doc_Folder_Add #FileID,#LicenseID,#UserID";
Response.Write("Save successfully executed. Added to DB");
Cmd = new SqlCommand(SQL,Conn);
Cmd.Parameters.Add(new SqlParameter("#FolderID", SqlDbType.Int));
Cmd.Parameters["#FileID"].Value = Convert.ToInt32(hdFileID.Value.ToString());
Cmd.Parameters.Add(new SqlParameter("#LicenseID", SqlDbType.Int));
Cmd.Parameters["#LicenseID"].Value = Convert.ToInt32(ddLicense.SelectedItem.Value.ToString());
Cmd.Parameters.Add(new SqlParameter("#UserID", SqlDbType.Int));
Cmd.Parameters["#UserID"].Value = Convert.ToInt32(hdUserID_Global.Value);
Cmd.ExecuteNonQuery();
}
else
{
}
Conn.Close();
Response.Redirect("/Library/Default2.aspx?FileID=" + Request["RootFileID"].ToString());
Response.End();
}
catch (Exception e){
Response.Write("An error occurred while saving: " + e);
Response.End();
}
}
I've been struggling for more than 2 days on that and I don't see why the button is not firing the first time but only as from the 2nd time. Any help will be greatly appreciated. Thank you.
You should open connection i.e Conn.open() before executing cmd.ExecuteNonQuery() method.
Try this, if it still doesn't work, in first line of webform.aspx i.e. <%# Page Language="C#" add this attribute and see if it works: EnableEventValidation="false". Also check the flow of code by setting breakpoints.
I got it to work by adding EnableViewState = False in the <FORM runat="server"> tag in the asp.NET code

asp.net C# - DataList2 Refresh based on the value of DataList1

I am new to ASP.NET and C#. I want to refresh the 2nd DataList (DataList2) when a user clicks on the (+) sign.
Datalist1 will list all Company records with a column that has a (+) sign. If a user clicks the (+), it will expand (DataList2) below the company and list all the contact names.
Please help. Thanks!
<%# Page Language="C#" AutoEventWireup="true" CodeFile="CompanyList.aspx.cs" Inherits="_CompanyList" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<link id="Link1" rel="stylesheet" runat="server" media="screen" href="/Apps/ERP/ERP_Styles.css" />
</head>
<body>
<form id="form1" runat="server">
<table style="width:100%" border="0">
<tr>
<td style="width:20%"></td>
<td style="width:60%">
<p class="PageTitle">Company List</p>
</td>
<td style="width:20%">
<asp:Button ID="myBtn" runat="server" Text="Click me"
OnClientClick="window.parent.location.href='/Apps/ERP/ASPX/UploadContact/UploadContact.aspx'; return false;" />
</td>
</tr>
</table>
<%-- ////////////////////////////////////// Start Data Row ///////////////////////////////////////// --%>
<table width="595px">
<asp:DataList BackColor="#ffffff" id="DataList1" DataSourceID="dsCompanyList" runat="server" Width="100%">
<ItemTemplate>
<tr>
<td>
<asp:LinkButton ID="LinkButton1" runat="server" Text="+" CommandArgument='<%#Container.ItemIndex%>'
OnCommand="LinkButton1_Command"
></asp:LinkButton>
</td>
<td><%#Eval("Row")%></td>
<td><%#Eval("Company")%></td>
</tr>
<asp:Panel ID="pnlChildView" runat="server">
<asp:DataList ID="DataList2" runat="server" Width="100%">
<ItemTemplate>
<tr>
<td><%#Eval("FirstName")%></td>
<td><%#Eval("LastName")%></td>
</tr>
</ItemTemplate>
</asp:DataList>
</asp:Panel>
</ItemTemplate>
</asp:DataList>
</table>
<asp:SqlDataSource ID="dsCompanyList" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnApps %>"
SelectCommand="SELECT ROW_NUMBER() OVER (ORDER By MatchFlag ASC) AS ROW
, Company FROM (
SELECT DISTINCT(Company) AS Company, MatchFlag
--,InsertFlag, MatchFlag
FROM dbo.Import_CompanyContact icc
WHERE RefNum = #RefNum
AND MatchFlag = 2
) a "
>
<SelectParameters>
<asp:QueryStringParameter Name="RefNum" QueryStringField="RefNum" DefaultValue="0" Type="Int16" />
</SelectParameters>
</asp:SqlDataSource>
</form>
</body>
</html>
The code behind .cs file
using System;
using System.Collections.Generic;
//using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class _CompanyList : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void LinkButton1_Command(object sender, CommandEventArgs e)
{
//pass index of item in command argument
int itemIndex = Convert.ToInt32(e.CommandArgument);
//depending on your needs bind the details on demand
//or preload during ItemDataBound
Panel childViewPanel = (Panel)DataList1.Items[itemIndex].FindControl("pnlChildView");
if (childViewPanel != null)
{
//toggle visibility of childViewPanel and bind child list if panel is visible
if (childViewPanel.Visible)
{
DataList childList = (DataList)childViewPanel.FindControl("DataList2");
if (childList != null)
{
int keyValue = (int)DataList1.DataKeys[itemIndex];
//bind the list using DataList1 data key value
childList.DataSource = "SELECT FirstName, LastName FROM dbo.Import_CompanyContact WHERE Company = 'Applied Micro'"; //get data using keyValue
childList.DataBind();
}
}
}
}
}
There are a few things needed to make this work for you, but first - please consider using stored procedures or at least parameterized queries.
You are attempting to access the .DataKeys of the "parent" DataList but you never included that on your definition. In order to accurately do this, you're going to need to change your source query to include some key value (instead of just ROW_NUMBER() (not a key) and Company):
<asp:DataList BackColor="#ffffff"
id="DataList1"
DataSourceID="dsCompanyList"
runat="server"
Width="100%"
DataKeyField="YourKeyField">
Then, you'll need to alter your code-behind to set the .DataSource of your "child" DataList...and while I'm using your query, please consider using something other than dynamic SQL:
protected void LinkButton1_Command(object sender, CommandEventArgs e)
{
int itemIndex = Convert.ToInt32(e.CommandArgument);
Panel childViewPanel = (Panel)DataList1.Items[itemIndex].FindControl("pnlChildView");
if (childViewPanel != null)
{
if (childViewPanel.Visible)
{
DataList childList = (DataList)childViewPanel.FindControl("DataList2");
if (childList != null)
{
int keyValue = (int)DataList1.DataKeys[itemIndex];
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["YourConnectionString"].ConnectionString))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("SELECT FirstName, LastName FROM dbo.Import_CompanyContact WHERE Company = " + keyValue, con))
{
cmd.CommandType = CommandType.Text;
using (SqlDataReader dr = cmd.ExecuteReader())
{
childList.DataSource = dr;
childList.DataBind();
}
}
}
}
}
}
}

Output parameter from SQL Server not printing to web form

I have a store procedure
create proc spAddEmployees
#Name varchar(50),
#Gender varchar(10),
#Salary int,
#EmployeeId int out
as
begin
insert into tblEmployees values (#Name, #Gender, #Salary)
select EmployeeId = SCOPE_IDENTITY()
end
which has an output parameter that tells the user the current scope_identity
The markup looks like
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<table style="border: 1px solid black; font-family:Arial">
<tr>
<td>
Employee Name
</td>
<td>
<asp:TextBox ID="txtEmployeeName" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td>
Gender
</td>
<td>
<asp:DropDownList ID="ddlGender" runat="server">
<asp:ListItem>Male</asp:ListItem>
<asp:ListItem>Female</asp:ListItem>
</asp:DropDownList>
</td>
</tr>
<tr>
<td>
Salary
</td>
<td>
<asp:TextBox ID="txtSalary" runat="server"></asp:TextBox>
</td>
</tr>
<tr>
<td colspan="2">
<asp:Button ID="btnSubmit" runat="server" Text="Submit"
onclick="btnSubmit_Click" />
</td>
</tr>
<tr>
<td colspan="2">
<asp:Label ID="lblMessage" runat="server"></asp:Label>
</td>
</tr>
</table>
And the code behind
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
//read from the config file so you don't have to hardcode the connection string
string cs = ConfigurationManager.ConnectionStrings["dbcs"].ConnectionString;
//when you use the using statement the database connection is automatically closed for you
using(SqlConnection con = new SqlConnection(cs))
{
SqlCommand cmd = new SqlCommand("spAddEmployees", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Name", txtEmployeeName.Text);
cmd.Parameters.AddWithValue("#Gender",ddlGender.SelectedValue);
cmd.Parameters.AddWithValue("#Salary", txtSalary.Text);
SqlParameter outputParmeter = new SqlParameter();
outputParmeter.ParameterName = "#EmployeeId";
outputParmeter.SqlDbType = SqlDbType.Int;
outputParmeter.Direction = ParameterDirection.Output;
cmd.Parameters.Add(outputParmeter);
con.Open();
cmd.ExecuteNonQuery();
string EmpId = outputParmeter.Value.ToString();
lblMessage.Text = "Employee Id = " + EmpId;
}
}
}
This program should add a new row to the tblEmployees table and then output to the user the output parameter of the stored procedure. It runs and adds the row to the number when the button is clicked, but the output parameter isn't being printed to the screen. Thoughts?
Perhaps:
select EmployeeId = SCOPE_IDENTITY()
In the stored procedure should be:
select #EmployeeId = SCOPE_IDENTITY()
The syntax in the stored procedure isn't right.
You should use
select #EmployeeId = SCOPE_IDENTITY()
^
and also the usual way to retrieve the output parameter is through the command collection. I am not sure that in the process the parameter is replaced somewhere
string EmpId = cmd.Parameters["#EmplyeeId"].Value.ToString();

How to get a runtime control id

Using asp.net and c#
Asp.net code
<asp:Button ID="btnAddNew" runat="server" Text="Add New"
onclick="btnAddNew_Click" />
<div id="divAdd" runat="server" style="display:none" >
<table width="100%">
<tr>
<td colspan="1">First Name :</td>
<td colspan="1" align="left"><asp:TextBox ID="txtFName" runat="server" ></asp:TextBox> </td>
</tr>
<tr>
<td colspan="1">Last Name :</td>
<td colspan="1" align="left"><asp:TextBox ID="txtLName" runat="server" ></asp:TextBox> </td>
</tr>
<tr>
<td colspan="1">Date Of Birth :</td>
<td colspan="1" align="left"><asp:TextBox ID="txtDob" runat="server" ></asp:TextBox> </td>
</tr>
<tr>
<td colspan="1">Age :</td>
<td colspan="1" align="left" ><asp:TextBox ID="txtAge" runat="server" ></asp:TextBox> </td>
</tr>
<tr>
<td colspan="2" align="center">
<asp:Button ID="btnSave" runat="server" Text="Save" OnClientClick=" return validate()" type="submit" />
<asp:Button ID="btnClose" runat="server" Text="Close" OnClientClick ="return clear()" type="submit" />
</td>
</tr>
</table>
</div>
C# Code
static void Insert()
{
try
{
string connectionString =
"server=JEBW1011ZAHID;" +
"initial catalog=employee;" +
"integrated security = true";
using (SqlConnection conn =
new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(
"INSERT INTO [NyhedTB] ([NyhedDato], [NyhedTitel], [NyhedTekst]) " +
"VALUES (#NyhedDato, #NyhedTitel, #NyhedTekst)", conn))
{
cmd.Parameters.AddWithValue("#NyhedDato", txtfname.Text);
cmd.Parameters.AddWithValue("#NyhedTitel", txtlanme.Text);
cmd.Parameters.AddWithValue("#NyhedTekst", txtage.Text);
int rows = cmd.ExecuteNonQuery(); // Inserted rows number
}
}
}
catch (SqlException ex)
{
//Log exception
//Display Error message
}
}
Showing error as txtfname does not exist.
Need code help
You Insert method is static. It doesn't have access to any page elements. I would recommend you passing those values as parameters to the method instead of coupling it with your UI:
static void Insert(string fName, string lName, string age)
{
try
{
string connectionString =
"server=JEBW1011ZAHID;" +
"initial catalog=employee;" +
"integrated security = true";
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(
"INSERT INTO [NyhedTB] ([NyhedDato], [NyhedTitel], [NyhedTekst]) " +
"VALUES (#NyhedDato, #NyhedTitel, #NyhedTekst)", conn))
{
cmd.Parameters.AddWithValue("#NyhedDato", fName);
cmd.Parameters.AddWithValue("#NyhedTitel", lName);
cmd.Parameters.AddWithValue("#NyhedTekst", age);
int rows = cmd.ExecuteNonQuery(); // Inserted rows number
}
}
}
catch (SqlException ex)
{
//Log exception
//Display Error message
}
}
and then when calling this method from your code behind you could pass whatever values you want:
protected void SomeButton_Click(object sender, EventArgs e)
{
Insert(txtfname.Text, txtlanme.Text, txtage.Text);
}
Now your Insert method is a little more reusable as it is no longer coupled to your UI.
Remove the static in your method
Put this code public void Insert() instead of static void Insert()

Categories