direct SQL execution to get count using Enterprise library - asp.net

I am new to asp.net development and using enterprise library in my application in the following way.
Database db = DatabaseFactory.CreateDatabase();
DbCommand cmd = db.GetStoredProcCommand("sp_MakePayment");
db.AddInParameter(cmd, "#BillGenID", System.Data.DbType.Int32);
db.SetParameterValue(cmd, "#BillGenID", billgenID);
db.AddInParameter(cmd, "#PayDate", System.Data.DbType.String, 50);
db.SetParameterValue(cmd, "#PayDate", mypaydate.Text);
db.AddInParameter(cmd, "#TransNo", System.Data.DbType.String, 50);
db.SetParameterValue(cmd, "#TransNo", transno.Text);
db.AddInParameter(cmd, "#AmtToPay", System.Data.DbType.Double);
db.SetParameterValue(cmd, "#AmtToPay", Convert.ToDouble(paidamount.Text));
////Execute Stored Procedure
int i = 0;
i = db.ExecuteNonQuery(cmd);
Now I am in a situation where i need to run this inlnie query using the same method to get the count of records and read in a variable. for example following query to find existing bill.
string bill_id = "1234";
string dofpayment = "11/03/2011";
mysql = "Select count(*) from payments where bill_id = " + bill_id + " and payment_date = " + dofpayment ;
Now how to incorporate the above lines using the enterprise library block.
thanks

If you enterprise library supports text commands alongside with stored procedures, then you should write a code which creates a text command and then passes your bill_id and dofpayment as parameters to it.
Otherwise, you need to create a stored procedure with these two parameters and then call that in similar way shown in your code example for stored procedure.
I hope this helps!

string sSql = "SELECT CustomerID, CompanyName, City, Country" + " FROM Customers WHERE Country = #sCountry"; Database db = DatabaseFactory.CreateDatabase(); DBCommandWrapper cmd = db.GetSqlStringCommandWrapper(sSql); cmd.AddInParameter("#sCountry", DbType.String, sCountry); DataSet ds = new DataSet(); db.LoadDataSet(cmd, ds, "Customers");
please read the msdn reference

Related

SQL Server User-Defined Table Type and .NET

I had a need to pass an integer array to a stored procedure from .NET and so I googled the topic and eventually ran across Arrays and Lists in SQL Server 2008, written by Erland Sommarskog and supposedly considered the standard manner in which one goes about this process.
I've tried two different manners to pass a user-defined table type to a stored procedure, but I'm getting exceptions with each one. Both of these manners are similar to what Erland Sommarskog uses in the link above.
Manner #1 - Use DataTable as SqlParameter
DataTable dt = new DataTable();
dt.Columns.Add("n", typeof(int));
// Just adding 3 test rows to the DataTable
DataRow dr = dt.NewRow();
dr["n"] = 1;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["n"] = 2;
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["n"] = 3;
dt.Rows.Add(dr);
// Creation of the SqlParameter
SqlParameter p = new SqlParameter();
p.ParameterName = "#ids";
p.Direction = ParameterDirection.Input;
p.SqlDbType = SqlDbType.Structured;
p.TypeName = "lstInt_TblType";
p.Value = dt;
// Blows up here
DataSet ds = DAWrapper.GetDataSet(
Common.GetDB(),
"usp_Test",
new SqlParameter[] { p });
The exception that I get states:
The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Parameter 1 ("#ids"): Data type 0x62 (sql_variant) has an invalid type for type-specific metadata.
Manner 2 - Use List as SqlParameter
List<SqlDataRecord> lstSDR = new List<SqlDataRecord>();
SqlMetaData[] tvp_definition = { new SqlMetaData("n", SqlDbType.Int) };
// Just adding 3 test rows
SqlDataRecord rec = new SqlDataRecord(tvp_definition);
rec.SetInt32(0, 50);
lstSDR.Add(rec);
rec = new SqlDataRecord(tvp_definition);
rec.SetInt32(0, 51);
lstSDR.Add(rec);
rec = new SqlDataRecord(tvp_definition);
rec.SetInt32(0, 52);
lstSDR.Add(rec);
// Creation of the SqlParameter
SqlParameter p = new SqlParameter();
p.ParameterName = "#ids";
p.Direction = ParameterDirection.Input;
p.SqlDbType = SqlDbType.Structured;
p.TypeName = "lstInt_TblType";
p.Value = lstSDR;
// Blows up here
DataSet ds = DAWrapper.GetDataSet(
Common.GetDB(),
"usp_Test",
new SqlParameter[] { p });
And the exception that I get for this ones states:
No mapping exists from object type System.Collections.Generic.List`1[[Microsoft.SqlServer.Server.SqlDataRecord, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] to a known managed provider native type.
Other Info
lstInt_TblType is the User-Defined Table Type in my SQL Server 2008. It does exist (I triple-checked this!). It has one column called "n", of type int, primary key and doesn't allow nulls. I copied exactly how Erland set his up.
I also verified that the stored procedure usp_Test works from SQL Server Manager Studio, so I'm fairly certain that the exceptions are not issuing from that direction. This is the t-sql that I used to verify that the stored procedure works:
DECLARE #ids lstInt_TblType
INSERT #ids(n) VALUES(1),(2),(3)
EXEC usp_Test ids
Any suggestions on where to go with this would be greatly appreciated. Thanks!
*EDIT: *
The stored procedure usp_Test:
ALTER PROCEDURE [dbo].[usp_Test]
(
#ids lstInt_TblType READONLY
)
AS
BEGIN
SET NOCOUNT ON;
select *
from dbo.dat_MetaData
where MetaDataTypeID in (select n from #ids)
END
GO
Found a different way to go about doing it. This way uses the System.Data.SqlClient libraries to create a connection to the database, specify the stored procedure name, and then pass a parameter in as a DataTable that serves as the SQL Server user-defined table type.
using (SqlConnection conn = new SqlConnection(connStr)) {
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "dbo.usp_Test";
cmd.Parameters.AddWithValue("#ids", dt);
conn.Open();
using (SqlDataReader sqlReader = cmd.ExecuteReader()) {
DataTable retTbl = new DataTable();
retTbl.Load(sqlReader);
}
}
You can also find good examples of how to pass table-valued parameter data to a stored procedure in Microsoft's own Table-Valued Parameters reference.

Avoiding SQL injection when saving user-agent using ASP.net

I'm saving the browser user-agent of my users for stats purposes.
As you already know, user-agent can be modified. I would like to know if I should do anything to protect against SQL Injection.
I'm using Stored Procedures for inserting.
Many thanks.
Use parameters with stored procedures or use parameters with dynamic SQL.
Here's the example from MSDN:
SqlDataAdapter dataAdapter = new SqlDataAdapter(
"SELECT CustomerID INTO #Temp1 FROM Customers " +
"WHERE CustomerID > #custIDParm; SELECT CompanyName FROM Customers " +
"WHERE Country = #countryParm and CustomerID IN " +
"(SELECT CustomerID FROM #Temp1);",
connection);
SqlParameter custIDParm = dataAdapter.SelectCommand.Parameters.Add(
"#custIDParm", SqlDbType.NChar, 5);
custIDParm.Value = customerID.Text;
SqlParameter countryParm = dataAdapter.SelectCommand.Parameters.Add(
"#countryParm", SqlDbType.NVarChar, 15);
countryParm.Value = country.Text;
connection.Open();
DataSet dataSet = new DataSet();
dataAdapter.Fill(dataSet);
Use a prepared statement. Make sure you use a prepared statement for all SQL operations, even if the data comes out of the database.

why this code enter two entries into the database

i have a code that retrieve some content and enter it the database :
MySqlConnection conn = new MySqlConnection(#"connection string");
MySqlCommand cmd = new MySqlCommand("INSERT INTO copy (id) VALUES ('" + Page.User.Identity.Name + "')", conn);
MySqlCommand cmd2 = new MySqlCommand("INSERT INTO copy (cv) VALUES ('" + mainEditor.Content.Replace("'", "''") + "')",conn);
conn.Open();
cmd.ExecuteNonQuery();
cmd2.ExecuteNonQuery();
conn.Close();
it connects and enters the data fine but it enters the data in two not one (it creates two rows instead of one)
i am using asp.net 3.5 and mysql 5.0
what am i doing wrong, thanks.
It's inserting two rows because you're executing two INSERT statements. Each time you run an INSERT it does just that: inserts a row.
I'm guessing you wanted to create a single row with both the id and cv fields populated. The SQL syntax for that is INSERT INTO copy (id, cv) VALUES ('x', 'y');
So:
MySqlCommand cmd = new MySqlCommand("INSERT INTO copy (id) VALUES ('" + Page.User.Identity.Name + "', '" + mainEditor.Content.Replace("'", "''") + "')",conn);
It's because two separate inserts are running. You can insert more than one value, try this:
MySqlCommand cmd = new MySqlCommand("INSERT INTO copy (id, cv) VALUES ('" + Page.User.Identity.Name + "', '" + mainEditor.Content.Replace("'", "''") + "')", conn);
You can comma separate the fields, and the values so it inserts into one record. Executing 2 insert commands will always create 2 records.
You didn't say which driver you're using so I'll use the documentation I found for dotConnect. I would try to use something along these lines (explanation of code below)
using( var conn = new MySqlConnection(#"connection string"))
using( cmd = new MySqlCommand("", conn) ){
cmd.CommandText = #"
INSERT INTO copy (id, cv)
VALUES (:name, :userContent)";
cmd.Parameters.Add("name", MySqlType.[correct type]]).Value = Page.User.Identity.Name;
cmd.Parameters.Add("userContent", MySqlType.[correct type], [column size]).Value = mainEditor.Content;
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
The use of the using construct is because MySqlConnection and MySqlCommand classes both implement the IDisposable interface so they need to be disposed of when you're done using them to avoid possible resource leaks.
The :name and :userContent is what I found in documentation for creating parametrized queries. This will allow the database driver to take care of escaping all of the special characters out of user input to avoid SQL injection attacks. This part is actually really important, there are some REALLY sophisticated SQL injection attacks out there, so there's a good chance simply escaping ' (as you were doing) isn't enough.

MySQL / ASP.NET Stored Procedures

Hopefully this is not a ServerFault question...
I'm working forward on migrating a project from storing data in XML Serialization to a MySQL database. I'm using the example provided me from a previous question answered yesterday.
Connecting using phpMyAdmin and MySQL Workbench I've created a Stored Procedure called 'sprocOrderSelectSingleItem'. It seems to work well with MySQL for all I can tell. When I run the SHOW CREATE PROCEDURE sprocOrderSelectSingleItem it returns the following:
CREATE DEFINER=username#% PROCEDURE sprocOrderSelectSingleItem(IN orderID INTEGER)
BEGIN SELECT * FROM tblOrders WHERE ID=orderID; END
My cooperative ASP.NET code goes something like this:
public static Order GetItem(int ID)
{
Order objOrder = null;
using (OdbcConnection objConnection = new OdbcConnection(Utils.ApplicationConfiguration.ConnectionString))
{
OdbcCommand objCommand = new OdbcCommand("sprocOrderSelectSingleItem", objConnection);
objCommand.CommandType = CommandType.StoredProcedure;
objCommand.Parameters.AddWithValue("orderID", ID);
objConnection.Open();
using (OdbcDataReader objReader = objCommand.ExecuteReader())
{
if (objReader.Read())
{
objOrder = FillDataRecord(objReader);
}
objReader.Close();
}
objConnection.Close();
}
return objOrder;
}
When I view the page I get the following error message:
ERROR [42000] [MySQL][ODBC 5.1 Driver][mysqld-5.0.77]You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'sprocOrderSelectSingleItem' at line 1
Really not catching on to what could be missing or going wrong. Are there any additional tests I should/could be running to confirm things are working on the MySQL side? Am I missing a step to pass the Stored Procedure call correctly in ASP.NET? The code breaks at the line of:
using (OdbcDataReader objReader = objCommand.ExecuteReader())
Replacing the line of
OdbcCommand objCommand = new OdbcCommand("sprocOrderSelectSingleItem", objConnection);
with this instead
OdbcCommand objCommand = new OdbcCommand("SELECT * FROM tblOrders WHERE ID=" + ID + ";", objConnection);
and everything works as expected.
Thanks for any help you guys can provide.
Your can run an execute on sprocOrderSelectSingleItem in Mysql directly with the ID parameter.
It will show that your StoredProc run correctly.
Here is a sample code in C# that call a stored proc.
OdbcCommand salesCMD = new OdbcCommand("{ CALL SalesByCategory(?) }", nwindConn);
salesCMD.CommandType = CommandType.StoredProcedure;
OdbcParameter myParm = salesCMD.Parameters.Add("#CategoryName", OdbcType.VarChar, 15);
myParm.Value = "Beverages";
OdbcDataReader myReader = salesCMD.ExecuteReader();
Look at the "Call" in the OdbcCommand and the "?" for the parameter that is later supplied with a value.
Can you try something like below:
OdbcCommand cmd = new OdbcCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "{call LoadCustCliOrders(?,?,?,?)}";
cmd.Parameters.Add("CUST_ID",OdbcType.Int);
cmd.Parameters.Add("CLIENT_ID",OdbcType.Int);
cmd.Parameters.Add("DATE_FROM",OdbcType.Date);
cmd.Parameters.Add("DATE_TO",OdbcType.Date);
...
cmd.Parameters["CUST_ID"].Value = _CustId;
cmd.Parameters["CLIENT_ID"].Value = _ClientId;
cmd.Parameters["DATE_FROM"].Value = _DateFrom;
cmd.Parameters["DATE_TO"].Value = _DateTo;
cmd.ExecuteReader
Are you sure that you are using the same username or user with the same access privileges.
I think you need to add the word "CALL" before the stored proc.
It should be CALL sprocOrderSelectSingleItem and try.

Preventing SQL Injection in ASP.Net

I have this code
UPDATE OPENQUERY (db,'SELECT * FROM table WHERE ref = ''"+ Ref +"'' AND bookno = ''"+ Session("number") +"'' ')
How would I prevent SQL Injections on this?
UPDATE
Here's what i'm trying
SqlCommand cmd = new SqlCommand("Select * from Table where ref=#ref", con);
cmd.Parameters.AddWithValue("#ref", 34);
For some reason everything I try and add it doesn't seem to work I keep getting SQL Command mentioned below.
The error is this
'SqlCommand' is a type and cannot be used as an expression
I'm taking over someone else's work so this is all new to me and I would like do things the right way so if anyone can provide any more help on how to make my query above safe from SQL injections then please do.
UPDATE NO 2
I added in the code as VasilP said like this
Dim dbQuery As [String] = "SELECT * FROM table WHERE ref = '" & Tools.SQLSafeString(Ref) & "' AND bookno = '" & Tools.SQLSafeString(Session("number")) & "'"
But I get an error Tools is not declared do I need to specify a certain namespace for it to work?
UPDATE
Has anyone got any ideas on the best of getting my query safe from SQL injection without the errors that i'm experiencing?
UPDATE
I now have it so it work without the parameters bit here's my updated source code any idea why it won't add the parameter value?
Dim conn As SqlConnection = New SqlConnection("server='server1'; user id='w'; password='w'; database='w'; pooling='false'")
conn.Open()
Dim query As New SqlCommand("Select * from openquery (db, 'Select * from table where investor = #investor ') ", conn)
query.Parameters.AddWithValue("#investor", 69836)
dgBookings.DataSource = query.ExecuteReader
dgBookings.DataBind()
It works like this
Dim conn As SqlConnection = New SqlConnection("server='server1'; user id='w'; password='w'; database='w'; pooling='false'")
conn.Open()
Dim query As New SqlCommand("Select * from openquery (db, 'Select * from table where investor = 69836') ", conn)
dgBookings.DataSource = query.ExecuteReader
dgBookings.DataBind()
The error i'm getting is this
An error occurred while preparing a query for execution against OLE DB provider 'MSDASQL'.
And it's because it isn't replacing the #investor with the 69836
Any ideas?
SOLUTION
Here is how I solved my problem
Dim conn As SqlConnection = New SqlConnection("server='h'; user id='w'; password='w'; database='w'; pooling='false'")
conn.Open()
Dim query As New SqlCommand("DECLARE #investor varchar(10), #sql varchar(1000) Select #investor = 69836 select #sql = 'SELECT * FROM OPENQUERY(db,''SELECT * FROM table WHERE investor = ''''' + #investor + ''''''')' EXEC(#sql)", conn)
dgBookings.DataSource = query.ExecuteReader
dgBookings.DataBind()
Now I can write queries without the worry of SQL injection
Try using a parameterized query here is a link http://www.aspnet101.com/2007/03/parameterized-queries-in-asp-net/
Also, do not use OpenQuery... use the this to run the select
SELECT * FROM db...table WHERE ref = #ref AND bookno = #bookno
More articles describing some of your options:
http://support.microsoft.com/kb/314520
What is the T-SQL syntax to connect to another SQL Server?
Edited
Note: Your original question was asking about distributed queries and Linked servers. This new statement does not reference a distributed query. I can only assume you are directly connecting to the database now. Here is an example that should work.
Here is another reference site for using SqlCommand.Parameters
SqlCommand cmd = new SqlCommand("Select * from Table where ref=#ref", con);
cmd.Parameters.Add("#ref", SqlDbType.Int);
cmd.Parameters["#ref"] = 34;
Edited:
Ok Jamie taylor I will try to answer your question again.
You are using OpenQuery becuase you are probably using a linked DB
Basically the problem is the OpenQuery Method takes a string you cannot pass a variable as part of the string you sent to OpenQuery.
You can format your query like this instead. The notation follows servername.databasename.schemaname.tablename. If you are using a linked server via odbc then omit databasename and schemaname, as illustrated below
Dim conn As SqlConnection = New SqlConnection("your SQL Connection String")
Dim cmd As SqlCommand = conn.CreateCommand()
cmd.CommandText = "Select * db...table where investor = #investor"
Dim parameter As SqlParameter = cmd.CreateParameter()
parameter.DbType = SqlDbType.Int
parameter.ParameterName = "#investor"
parameter.Direction = ParameterDirection.Input
parameter.Value = 34
Use parameters instead of concatenating your SQL query.
Assuming your database engine being SQL Server, here's a piece of code which I hope will help.
Using connection As SqlConnection = new SqlConnection("connectionString")
connection.Open()
Using command As SqlCommand = connection.CreateCommand()
string sqlStatement = "select * from table where ref = #ref and bookno = #bookno";
command.CommandText = sqlStatement
command.CommandType = CommandType.Text
Dim refParam As SqlDataParameter = command.CreateParameter()
refParam.Direction = ParameterDirection.Input
refParam.Name = "#ref"
refParam.Value = Ref
Dim booknoParam As SqlDataParameter = command.CreateParameter()
booknoParam.Direction = ParameterDirection.Input
booknoParam.Name = "#bookno"
booknoParam.Value = Session("number")
Try
Dim reader As SqlDataReader = command.ExecuteQuery()
' Do your reading job here...'
Finally
command.Dispose()
connection.Dispose()
End Try
End Using
End Using
To sum it all up, avoid SQL statement concatenation at all cost, and use parameterized quesries!
Here is an interesting link that brings you through SQL injection problem resolution on MSDN:
How To: Protect From SQL Injection in ASP.NET
use sqlparameters like:
SqlCommand cmd = new SqlCommand("Select * from Table where id=#id", con);
cmd.Parameters.AddWithValue("#id", 34);
you can use parameterized queries.
http://www.functionx.com/aspnet/sqlserver/parameterized.htm
SqlCommand cmd = new SqlCommand("Select * from Table where ref=#ref", con);
cmd.Parameters.AddWithValue("#ref", 34);
it does not work because it is written in C#, not VB.
Try something like
Dim cmd As New SqlCommand("Select * from Table where ref=#ref", con)
cmd.Parameters.AddWithValue("ref", 34)
My preferred way is to let Visual Studio handle it all by creating a DAL:
http://www.asp.net/data-access/tutorials/creating-a-data-access-layer-cs
Use LINQ. It parametrizes queries automatically.
Check out ORM as an alternative (very good way to go if you are building something medium-sized or big). It takes a little time to configure it, but then development becomes VERY fast. You choose from the native, Linq to SQL or Entity Framework, OR, try any other ORM which works with .NET.

Resources