System.IndexOutOfRangeException due to parameter & variables - c#

With C# & ASP.net, I have a master page and a content page. On a content page, I have a text box, where the user can input a value and then hit a button. This button runs a stored SQL procedure, and uses the user input as a parameter, then puts the results into an html table to display.
My webpage will launch, but the error is thrown after hitting the button with a user input. I think my issue is related to the parameter (#PN), the parameter variable (param), user input to variable (inputX). Error message reads
System.IndexOutOfRangeException was unhandled by user code
Message=An SqlParameter with ParameterName '#PN' is not contained by
this SqlParameterCollection.
C# Code as follows
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.Windows.Forms;
using System.Text;
using System.Configuration;
namespace NSV3
{
public partial class Fancy : System.Web.UI.Page
{
private string inputX = string.Empty;
protected void Page_Load(object sender, EventArgs e)
{
Label1.Attributes.Add("onClick", "CallMe();");
}
public void btnTemp_Click(object sender, EventArgs e)
{
string inputX = TextBox1.Text.ToString();
Label2.Text = "You've selected " + inputX;
SqlParameter param = new SqlParameter();
param.ParameterName = "#PN";
param.Value = inputX;
DataTable dt = this.GetData();
StringBuilder html = new StringBuilder();
html.Append("<table border = '1'>");
html.Append("<tr>");
foreach (DataColumn column in dt.Columns)
{
html.Append("<th>");
html.Append(column.ColumnName);
html.Append("</th>");
}
html.Append("</tr>");
foreach (DataRow row in dt.Rows)
{
html.Append("<tr>");
foreach (DataColumn column in dt.Columns)
{
html.Append("<td>");
html.Append(row[column.ColumnName]);
html.Append("</td>");
}
html.Append("</tr>");
}
html.Append("</table>");
PlaceHolder1.Controls.Add(new Literal { Text = html.ToString() });
}
public DataTable GetData()
{
string constr = "editted";
string sql = #"EXEC [ERP_Reports].[dbo].[udsp_WhereUsed]
#IMA_ItemID_INPUT = #PN,
#IMA_RecordID_INPUT = NULL,
#RecursionLevel = NULL,
#FetchSequence = NULL,
#QtyPerAssy_PrevLevel = NULL";
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(sql))
{
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.Connection = con;
cmd.Parameters["#PN"].Value = inputX;
sda.SelectCommand = cmd;
using (DataTable dt = new DataTable())
{
sda.Fill(dt);
return dt;
}
}
}
}
}
}
}

In GetData method, inside the SqlDataAdapter 'using', try the following:
...
cmd.Connection = con;
cmd.Parameters.AddWithValue("#PN", inputX);
sda.SelectCommand = cmd;
...
The problem is that cmd.Parameters["#PN"] does not exist when you set its Value so you get the exception.

You need to add the Param to the sqlCommand
cmd.Parameters.AddWithValue("#PN", inputx);
You also don't need this code in your btnTemp_Click method
SqlParameter param = new SqlParameter();
param.ParameterName = "#PN";
param.Value = inputX;

Related

C# C0246 While Filtering DataGridView with Listbox whose items come from SQL Server

I share with you a piece of code that works except the part where I'm trying to loop in the items of my listbox. That's why I'm here asking you for some help.
Lately, I switched from VBA to C# so I'm still new on this and don't undertsand everything yet.
So, the below code connect to my SQL server DB and fetch data both within my listbox and a DataGridView. I can filter with two textboxes also.
So now I have items within my listbox and my db's view within the DataGridview. I'd like to filter my DataGridview (which is filled by a datatable ) with my Listbox's item. I miss only a silly part I guess. Why Do I get this CS0246 "ListItem could not be found"
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsAppTest
{
public partial class Form1 : Form
{
//Initialize the component and display the items within my listbox CS_Bonds_listBox
public Form1()
{
InitializeComponent();
string connetionString = #"Data Source=my_server;Initial Catalog=my_db;Integrated Security=SSPI";
SqlConnection conn = new SqlConnection(connetionString);
conn.Open();
DataSet ds = new DataSet();
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT DISTINCT RatingProvider FROM Bonds", conn);
adapter.Fill(ds);
this.CS_Bonds_listBox.DataSource = ds.Tables[0];
this.CS_Bonds_listBox.DisplayMember = "RatingProvider";
}
private void Form1_Load(object sender, EventArgs e)
{
}
DataTable dtTEST = new DataTable();
// Next, when clicking on my button Connect, I retrieve my db into a Datatable that is displayed within //the Datagridview1
private void buttonConnect_Click(object sender, EventArgs e)
{
string connetionString = #"Data Source=my_server;Initial Catalog=my_db;Integrated Security=SSPI";
SqlConnection cnn= new SqlConnection(connetionString);
cnn.Open();
MessageBox.Show("Connection Open !");
String sql = "Select * from Bonds";
SqlCommand command = new SqlCommand(sql, cnn);
SqlDataAdapter sqlDA = new SqlDataAdapter();
sqlDA.SelectCommand = command;
sqlDA.Fill(dtTEST);
dataGridView1.DataSource = dtTEST;
cnn.Close();
}
private void ISIN_Bonds_textBox_TextChanged(object sender, EventArgs e)
{
DataView dv = dtTEST.DefaultView;
dv.RowFilter = "ISIN LIKE '" + ISIN_Bonds_textBox.Text + "%'";
dataGridView1.DataSource = dv;
}
private void Ticker_Bonds_textBox_TextChanged(object sender, EventArgs e)
{
DataView dv1 = dtTEST.DefaultView;
dv1.RowFilter = "Ticker LIKE '" + Ticker_Bonds_textBox.Text + "%'";
dataGridView1.DataSource = dv1;
}
private void CS_Bonds_listBox_SelectedIndexChanged(object sender, EventArgs e)
{
string conString = #"Data Source=my_server;Initial Catalog=my_db;Integrated Security=SSPI";
string query = "SELECT ISIN, Ticker, CrediSight, FROM Bonds";
string condition = string.Empty;
foreach (ListItem item in CS_Bonds_listBox.Items)
{
condition += item.Selected ? string.Format("'{0}',", item.Value) : "";
}
if (!string.IsNullOrEmpty(condition))
{
condition = string.Format(" WHERE Country IN ({0})", condition.Substring(0, condition.Length - 1));
}
using (SqlConnection con = new SqlConnection(conString))
{
using (SqlCommand cmd = new SqlCommand(query + condition))
{
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
cmd.Connection = con;
using (DataTable dt = new DataTable())
{
sda.Fill(dt);
dataGridView1.DataSource = dt;
//dataGridView1.DataBind();
}
}
}
}
}
}
}
This line has a problem:
foreach (ListItem item in CS_Bonds_listBox.Items)
A ListItem is a WebForms thing, and your application is a WinForms thing; your listbox doesn't contain a list of ListItem objects so this line of code wouldn't work out anyway, even if the relevant web namespace was imported.
Because you've bound your listbox to a datatable the list it is showing is full of DataRowView objects, so that's what you need to process. A DataRowView has a Row property that gives you the underlying row, which in turn can be accessed by a column name.
Additionally, to make your life easier a listbox has a SelectedItems property so you don't need to check every item for being selected:
foreach (DataRowView drv in CS_Bonds_listBox.SelectedItems)
{
var dr = drv.Row as DataRow;
var rp = dr["RatingProvider"];
condition += $"'{rp}',"
}
Your condition will end up with a trailing comma as a result of this, so trim it off before you build an IN clause with it:
condition = condition.TrimEnd(',');
This technique could be susceptible to SQL Injection hacking if the user manages to change the text showing in the list items.
A better way to handle the problem is via parameterization. You'd do it like this:
var cmd = new SqlCommand("SELECT * FROM table WHERE Country IN(", connStr);
int i = 0;
foreach (DataRowView drv in CS_Bonds_listBox.SelectedItems)
{
var dr = drv.Row as DataRow;
var rp = dr["RatingProvider"];
cmd.CommandText += $"#p{i},";
cmd.Parameters.Add($"#p{i}", SqlDbType.VarChar).Value = rp;
i++;
}
cmd.CommandText = cmd.CommandText.TrimEnd(',') + ")";
using(var da = new SqlDataAdapter(cmd))
{
var dt = new DataTable();
da.Fill(dt);
someGridView.DataSource = dt;
}
This builds an sql that looks like SELECT * FROM table WHERE Country IN(#p0,#p1,#p2.... i.e. we have concatenated parameter placeholders in rather than concatenating values in. At the same time we have filled the parameters collection with the parameter values
It also means that our database can't be hacked via our program, and our app doesn't die in a heap when the user selects a country with a name like Cote d'Ivoire
Some other things to note to tidy your code up:
SqlDataAdapter can take a string SQL and a string connection-string. You don't need to make a SqlCommand for it. You don't need to open and close conenctions for it; it knows how to do all this itself. I only used a SqlCommand because I was building the parameters collection as I went. Ordinarily I'd do using(var da = SqlDataAdapter("SELECT...", "Server=..") because it makes things nice and tidy.
This means e.g. your constructor can be simply:
//put this here once
private string _connStr = #"Data Source=my_server;Initial Catalog=my_db;Integrated Security=SSPI";
public Form1()
{
InitializeComponent();
var dt = new DataTable();
using(var da = new SqlDataAdapter("SELECT DISTINCT RatingProvider FROM Bonds", _connStr))
adapter.Fill(dt);
this.CS_Bonds_listBox.DataSource = dt;
this.CS_Bonds_listBox.DisplayMember = "RatingProvider";
}

Run all code within a page consecutively in C# (Using Visual Studio)

I have values from controls txtUser and txtAppNum on a page webform1.aspx. I am bringing those values to a page, Login.aspx. The code from Login.aspx is below. In the login.aspx page, I want to take the values from the controls txtUserand txtAppNum in webform1.aspx page, I want to check the values against a database, if the values are in the database, I want the page to redirect back to webform1.aspx.
My questions is, when I run the code, only Page_Load but not CheckRecord. Basically when I run the page, I can see the values carried over from the webform1.aspx page to login.aspx, but then that's it, nothing else happens.
What am I doing wrong? Any thoughts, I would greatly appreciate it, I have been stuck on this for a few days. Thanks!
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; //to communicate with the Server database
using System.Configuration;
using System.Data; //to use DataSet or DataTable
using System.Text; //for StringBuilder
namespace BLAA_3
{
public partial class login : System.Web.UI.Page
{
public void Page_Load(object sender, EventArgs e)
{
Page PreviousPage = Page.PreviousPage;
if (PreviousPage != null)
{
lblUserLogin.Text = ((TextBox)PreviousPage.FindControl("txtUser")).Text;
lblAppLogin.Text = ((TextBox)PreviousPage.FindControl("txtAppNum")).Text;
}
{
string _connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
}
}
public void CheckRecord(object sender, EventArgs e)
{
//get the connection
using (SqlConnection conn = new SqlConnection(#"Data Source=ServerInfo"))
{
//write the sql statement to execute
string sql = "select username FROM BLAA_users WHERE username = #username";
//instantiate the command object to fire
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
//attatch the parameter to pass, if no parameter is in the sql no need to attatch
SqlParameter[] prms = new SqlParameter[1];
prms[0] = new SqlParameter("#username", SqlDbType.VarChar, 50);
prms[0].Value = lblUserLogin.Text.Trim();
cmd.Parameters.AddRange(prms);
conn.Open();
object obj = cmd.ExecuteScalar();
conn.Close();
if (obj != null)
{
Response.Redirect("~/WebForm1.aspx");
}
else
Response.Redirect("http://www.google.com");
}
}
}
}
}
Is CheckRecord an event handler? If not, you don't need the sender and eventArgs in your signature for CheckRecord it can be public void CheckRecord().
It's not being called because your load event isn't calling it. So, inside your Page_Load function.
public void Page_Load(object sender, EventArgs e)
{
Page PreviousPage = Page.PreviousPage;
if (PreviousPage != null)
{
lblUserLogin.Text = ((TextBox)PreviousPage.FindControl("txtUser")).Text;
lblAppLogin.Text = ((TextBox)PreviousPage.FindControl("txtAppNum")).Text;
}
{
string _connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
}
CheckRecord();
}
public void CheckRecord()
{
//get the connection
using (SqlConnection conn = new SqlConnection(#"Data Source=ServerInfo"))
{
//write the sql statement to execute
string sql = "select username FROM BLAA_users WHERE username = #username";
//instantiate the command object to fire
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
//attatch the parameter to pass, if no parameter is in the sql no need to attatch
SqlParameter[] prms = new SqlParameter[1];
prms[0] = new SqlParameter("#username", SqlDbType.VarChar, 50);
prms[0].Value = lblUserLogin.Text.Trim();
cmd.Parameters.AddRange(prms);
conn.Open();
object obj = cmd.ExecuteScalar();
conn.Close();
if (obj != null)
{
Response.Redirect("~/WebForm1.aspx");
}
else
Response.Redirect("http://www.google.com");
}
}
}

Close firefox webpage and debug

My following code has two problems.
1- It doesn't go to the next row in dataset (when I run it, it just run firefox for 2916 times). I change this it from
var test = url.Replace("<userid>", Convert.ToString(row[userID]));
to
var test = url.Replace("<userid>", Convert.ToString(row["userID"]));
but it shows an error (Column 'userid' does not belong to table).
2- I want to close the firefox webpage page at the end of each loop and for next loop it runs again(because of performance issue)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.OleDb;
using System.Net;
namespace test2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
OleDbConnection conn = new OleDbConnection();
conn.ConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\hidden.accdb";
conn.Open();
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = conn;
cmd.CommandText = "Select * from hidden";
DataTable dt = new DataTable();
//To read data from dataset
OleDbDataAdapter adapter = new OleDbDataAdapter();
adapter.SelectCommand = cmd;
//Store the userID
adapter.Fill(dt);
int userid=0,trackid=0;
int counter=0;
foreach(DataRow row in dt.Rows)
{
string url = "http://abcd/<userid>?groups=<userid>";
var test = url.Replace("<userid>", Convert.ToString(row[userid]));
System.Diagnostics.Process.Start(url);
string client = (new WebClient()).DownloadString("http://abcd/userid?groups=userid");
if (client.ToLower() == (Convert.ToString(trackid).ToLower()))
{
counter++;
}
int ave = counter / 2916;
MessageBox.Show("Average = " + counter);
}
conn.Close();
}
}
}
string url = "http://abcd/<userid>?groups=<userid>";
var test = url.Replace("<userid>", Convert.ToString(row["userid"])); // You need ""
System.Diagnostics.Process.Start(test); // You should use variable test, which contains your url with <userid> replaced.

Passing parameter programmatically and displaying in crystal reports

I have a crystal report in which I set the datasource and parameter programmatically. This works when I just display regular data in the report. However, when I try to show the parameter value in the report header (it's a date), I get prompted to enter the parameter.
Any ideas as to what's causing this? I'm new to crystal reports so this might be a very simple problem.
Here's my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Data.SqlClient;
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Shared;
namespace CrystalReportsTestApp
{
public partial class ReportForm : Form
{
ReportDocument report = new ReportDocument();
public ReportForm()
{
InitializeComponent();
}
private void ConfigureCrystalReports()
{
string reportPath = "mypath\\CrystalReport1.rpt";
report.Load(reportPath);
}
private void RunReportButton_Click(object sender, EventArgs e)
{
DateTime date = dateTimePicker1.Value;
DataSet reportData = new DataSet();
SqlConnection conn = null;
SqlDataAdapter da = null;
try
{
conn = new SqlConnection(connectionString);
conn.Open();
da = new SqlDataAdapter();
SqlCommand cmd = new SqlCommand("cms.GetActiveEntityAccounts", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#EndDate", SqlDbType.DateTime).Value = date;
da.SelectCommand = cmd;
da.Fill(reportData, "DataTable1");
}
finally
{
if (conn != null)
{
conn.Close();
}
}
report.SetDataSource(reportData);
report.SetParameterValue("#EndDate", date);
crystalReportViewer1.ReportSource = report;
crystalReportViewer1.RefreshReport();
}
private void ReportForm_Load(object sender, EventArgs e)
{
ConfigureCrystalReports();
}
}
}
The problem was the following line towards the end:
crystalReportViewer1.RefreshReport();
This caused the report parameters to refresh and not just the report data.
You need to pass the Parameters to CrystalReportViewer control.
Use the below code after report.SetDataSource(reportData);.
CrystalDecisions.Shared.ParameterField parameterField = new CrystalDecisions.Shared.ParameterField();
parameterField.Name = "#EndDate";
//Create a new Discrete Value
CrystalDecisions.Shared.ParameterDiscreteValue parameterDiscreteValue = new CrystalDecisions.Shared.ParameterDiscreteValue();
parameterDiscreteValue.Value = date;
//Add the value
parameterField.CurrentValues.Add( parameterDiscreteValue );
//Add the parameter field
crystalReportViewer1.ParameterFields.Add( parameterField );
crystalReportViewer1.ReportSource = report;
crystalReportViewer1.RefreshReport();

c# asp.net dropdown list select value

I am getting confused with my code and not sure how to implement what I want.
I have two sql tables one that has OfficeID and matching OfficeName and another one that contains user. I have a page that allows a person to edit information about the person. When the page is loaded it supposed to select from the drop down list the current OfficeName of a person whose information is being edited. Thus I have this:
This is probably extremely inefficient and confusing for my level of knowledge of C# and SQL, but none the less I am determined to learn how to do it. What I have currently is Before the creation of the drop down list I get the users Id, then select from the database his corresponding officeID, then while creating the drop down list I check for the OfficeID to correspond to the ones from the other table. If it found the match it will set it as the selected value for the drop down list.
am I on the right track? I need to figure out how to compare SESLoginID = loginID before I convert loginID before hand. Any help?
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Functions;
using HelloApp;
public partial class UserUpdate : Page
{
private Int32 loginID = 0;
protected void Page_Load(object sender, EventArgs e)
{
loginID = Convert.ToInt32(Request.QueryString["SESLoginID"]);
if (!Page.IsPostBack)
{
BindBusinessUnitDDL();
}
}
protected void BindBusinessUnitDDL()
{
SqlConnection conn;
string sql;
SqlCommand cmd;
int error;
conn = Database.DBConnect(out error);
sql = String.Format("SELECT OfficeID FROM SESLogin WHERE SESLoginID = loginID");
cmd = new SqlCommand(sql, conn);
SqlDataReader rdrr = cmd.ExecuteReader();
ListItem office = new ListItem();
office.Value = Convert.ToString(rdrr.GetInt32(0));
Database.DBClose(conn);
sql = String.Format(
"SELECT OfficeID, OfficeName FROM Office");
cmd = new SqlCommand(sql, conn);
SqlDataReader rdr = cmd.ExecuteReader();
DropDownList ddlBusinessUnit = (DropDownList)(this.LoginFormView.FindControl("ddlBusinessUnit"));
while (rdr.Read())
{
ListItem myItem = new ListItem();
myItem.Value = Convert.ToString(rdr.GetInt32(0));
myItem.Text = rdr.GetString(1);
ddlBusinessUnit.Items.Add(myItem);
if(office.Value == myItem.Value){
ddlBusinessUnit.SelectedValue = myItem.Text;
}
}
Database.DBClose(conn);
ddlBusinessUnit.DataBind();
PageUser myUser = new PageUser();
}
A different version of the code where there exists a procedure to return OfficeName using an LoginID. Doesnt work either gives an error:
System.Data.SqlClient.SqlException: Conversion failed when converting the nvarchar value ' SELECT
[OfficeName]
FROM sesuser.SESLogin
INNER JOIN sesuser.Office
ON sesuser.Office.OfficeID = sesuser.SESLogin.OfficeID
WHERE SESLoginID LIKE '287'' to data type int.
public partial class UserUpdate : Page
{
private Int32 loginID = 0;
private String loginIDE = "";
protected void Page_Load(object sender, EventArgs e)
{
loginIDE = Request.QueryString["SESLoginID"];
loginID = Convert.ToInt32(Request.QueryString["SESLoginID"]);
if (!Page.IsPostBack)
{
BindBusinessUnitDDL();
}
}
protected void BindBusinessUnitDDL()
{
SqlConnection connec = null;
SqlCommand cmd = null;
string sqls = "";
int errNum = 0;
connec = Database.DBConnect(out errNum);
if (errNum != 0)
throw new Exception("Database Connection Error.");
sqls = "Login_GetOffice";
cmd = new SqlCommand(sqls, connec);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#userID", loginIDE);
string office = (string)cmd.ExecuteScalar();
SqlConnection conn;
string sql;
int error;
conn = Database.DBConnect(out error);
sql = String.Format(
"SELECT OfficeID, OfficeName FROM Office");
cmd = new SqlCommand(sql, conn);
SqlDataReader rdr = cmd.ExecuteReader();
DropDownList ddlBusinessUnit = (DropDownList)(this.LoginFormView.FindControl("ddlBusinessUnit"));
while (rdr.Read())
{
ListItem myItem = new ListItem();
myItem.Value = Convert.ToString(rdr.GetInt32(0));
myItem.Text = rdr.GetString(1);
ddlBusinessUnit.Items.Add(myItem);
if(office == myItem.Text){
myItem.Selected = true;
}
}
Database.DBClose(conn);
ddlBusinessUnit.DataBind();
PageUser myUser = new PageUser();
}
You can assign a DataSource and Bind the results you get from the query say via a DataTable.
Set the DataTextField and DataValueField
Then you can say something like ddl.Items.FindByText("requiredloginid").Selected = true after the Data is bound to the dropdown.
Why are you using
ddlBusinessUnit.DataBind();?
You are binding any data source to the dropdownlist.
Can you specify on which line you are getting error?
Thanks
Ashwani

Categories

Resources