Safety of C# DataTable as SQL Parameter - c#

I read a lot about SQL injections lately and I know a SqlParameter will not prevent injections for sure, but is a table parameter as safe as a single parameter?
Some untested uncompiled example code for clarification:
Is this...
SQL:
CREATE PROCEDURE dbo.InsertSingle
#Name nvarchar(max),
#Phone nvarchar(max)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO FooBar.dbo.SomeTable
VALUES(#Name, #Phone)
END
GO
C#:
foreach(User u in Users)
{
Connection.Open();
SqlCommand com = Connection.CreateCommand();
com.CommandType = CommandType.StoredProcedure;
com.CommandText = "dbo.InsertSingle";
SqlParameter p = new SqlParameter("#Name", u.Name);
com.Parameters.Add(p);
p = new SqlParameter("#Phone", u.Phone);
com.Parameters.Add(p);
com.ExecuteScalar();
}
as safe as this?
SQL:
CREATE PROCEDURE dbo.InsertBunch
#ValuesAsTable dbo.ValuesAsTableType READONLY
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO FooBar.dbo.SomeTable
SELECT *
FROM #ValuesAsTable
END
GO
C#:
DataTable valuesAsTable = Users.GetSomeInsertData();
Connection.Open();
SqlCommand com = Connection.CreateCommand();
com.CommandType = CommandType.StoredProcedure;
com.CommandText = "dbo.InsertBunch";
SqlParameter p = new SqlParameter("#valuesAsTable", valuesAdTable);
p.SqlDbType = SqlDbType.Structured;
p.TypeName = "dbo.ValuesAsTableType";
com.Parameters.Add(p);
com.ExecuteScalar();
I really tried to search it, but I cannot find good input. Can anyone link me in the right direction?
Thanks in advance

Typed parameters will prevent SQL injection if there is no possibility that they get interpreted as literal commands, and executed. Whether they are transported as scalar or table-valued parameters, does not make any difference in this regard.

Related

MySQLDataReader not reading C#

The Stored Procedure:
BEGIN
SELECT * FROM `user` WHERE `EmailAddress`= #p0 AND `Password` = #p1;
END
Where #p0 and #p1 are Varchar(100).
And the code:
using (MySqlConnection con = new MySqlConnection(Database.MySQLConstring))
{
using (MySqlCommand cmd = new MySqlCommand("LoginCheck", con))
{
cmd.CommandType = CommandType.StoredProcedure; //"LoginCheck"
cmd.Parameters.AddWithValue("email", Email);
cmd.Parameters.AddWithValue("password", Pword);
con.Open();
MySqlDataReader reader = cmd.ExecuteReader();
UserModel UM = new UserModel();
While (reader.Read())
{
UM.UserId = (int)reader["UserID"];
UM.DisplayName = (string)reader["DisplayName"];
UM.Moderator = (int)reader["Moderator"];
}
con.Close();
While(!string.IsNullOrEmpty(UM.DisplayName) && UM.UserId != 0)
{
Result = 1;
return UM;
}
Result = -1;
return UM;
}
}
The code runs succesfull until it comes to the while(reader.Read()) part, then it skips it and goes to the con.close(). No errors or exceptions are thrown. It worked when I was using it when everything was SQL and not MySQL ,but I need to get it working in MySQL.
When I run the stored Procedure itself in de databse then I get my result that I need. but when I use the code it will skip the While part of the code.
If I were going to execute a procedure that was declared as:
CREATE PROCEDURE x(em VARCHAR, pw VARCHAR) --declaration of parameters
BEGIN
SELECT * FROM `user` WHERE `EmailAddress`= em AND `Password` = pw;
END
I would ensure the parameters in my C# code were named the same as in the declaration of the stored procedure:
cmd.Parameters.Add(new MySqlParameter("em", Email));
cmd.Parameters.Add(new MySqlParameter("pw", Password));
I suspect that your query is not getting any rows, because the values you set never make it into the parameters, and are hence never used to query. reader.Read() returns false, because there are no rows. Also make sure that the values for EMail and Password that you're querying really do exist in the table
Try as a debugging thing, to make your query like:
SELECT UserID, DisplayName, Moderator FROM `user` WHERE `EmailAddress`= #p0 AND `Password` = #p1
UNION ALL
SELECT 0, CONCAT_WS(' ', 'There is no user with email/password of', #p0, '/', #p1), '' FROM DUAL;
Or however your parameters are named now..
Your reader.Read()should now return true because this query should always return a row, so inspect the value of DisplayName, it should tell what search terms were applied

Parameter not passed from program to stored procedure

I am passing the parameter like in C# page,
conn.Open();
MySqlCommand cmd = new MySqlCommand(sql, conn);
cmd.CommandText = commandtype.storedprocedure;
cmd.Parameters.AddWithValue("?user", user)
cmd.Parameters.AddWithValue("?name", name);
On the mysql stored procedures used 2 parameter for record exists finds
#id integer,
#name varchar(200)
BEGIN
IF EXISTS (SELECT * FROM usertable WHERE id = #id and mode =0 limit 1 )
THEN
UPDATE usertable SET name = name where id=#id and mode = 0;
ELSE
INSERT INTO usertable (name, mode)VALUES (#name`enter code here`,0);
END IF;
END
Another way of sending variables to a stored proc that I've used with no problem:
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#name", SqlDbTpye.Varchar).Value = name;
I think you can specify variable by size and type like this:
SqlDbTpye.Varchar,200
But not able to test that right now.
You need to make sure the prefixes for the parameters match. If you use "#" in your stored procedure, you need to use "#" in C#, too, not "?".
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#user", user)
cmd.Parameters.AddWithValue("#name", name);

How to call an Oracle Procedure from C#

From C# Code, I'm trying to call a PACKAGE.PROCEDURE() from Oracle. In this simple example I should get one value from the procedure call, but all I get is error:
wrong number or types of arguments in call to 'RETURN_NUM'
The procedure is declared as follows:
PROCEDURE return_num(xNum OUT NUMBER) AS
BEGIN
xNum:= 50;
dbms_output.put_line('hello world ' || xNum);
END;
C# code:
Oraclecon.Open();
OleDbCommand myCMD = new OleDbCommand("TEST.return_num", Oraclecon);
myCMD.CommandType = CommandType.StoredProcedure;
myCMD.Parameters.Add("xNum", OleDbType.Numeric);
OleDbDataReader myReader;
myReader = myCMD.ExecuteReader();
Can some one please point out what I'm doing wrong. Then in a real scenario I would like to call a procedure that returns a set of values from a custom Type, such as:
TYPE r_interface_data IS RECORD
(
object_id VARCHAR2(16),
obj_type VARCHAR2(32)
);
TYPE t_interfase_data IS TABLE OF r_interface_data;
How can I approach that. Thanks!
UPDATE: In my particular case I ended-up doing the following approach
using (OleDbCommand cmd = new OleDbCommand("PACKAGE.procedure_name"))
{
cmd.CommandType = CommandType.StoredProcedure;
SqlManager sqlManager = new SqlManager();
return sqlManager.GetDataSet(cmd);
}
I don't think you're that far off... try this:
OracleCommand cmd = new OracleCommand("return_num", Oraclecon);
cmd.Parameters.Add(new OracleParameter("xNum", OracleDbType.Decimal,
ParameterDirection.Output));
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
OracleDecimal d = (OracleDecimal)cmd.Parameters[0].Value;
double result = d.ToDouble();
result now contains the out parameter from the procedure.
I think your problem is you were attempting to use a DbDataReader on a stored procedure. DbDataReader is for queries.
Also, I used ODP.net -- that may or may not have contributed to your issue, that you were using Ole.

SQL SERVER 2005 return value

Hi all I have the following stored procedure
#UserName varchar(150),
#UserEmail varchar(300),
#UserPassword varchar(150),
#ContactNumber varchar(150),
#ContactMobile varchar(150),
#AreaOfCountry varchar(150),
#UserId int OUTPUT,
#AllreadyReg int OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
--DECLARE #UserId int, #AllreadyReg int
IF (SELECT COUNT(UserId) FROM Users WHERE (UserName = #UserName) OR (UserEmail = #UserEmail)) > 0
BEGIN
SET #UserId = 0
SET #AllreadyReg = 1
END
ELSE
BEGIN
INSERT INTO Users (UserName,UserEmail,UserPassword,ContactNumber,ContactMobile,AreaOfCountry) VALUES (#UserName,#UserEmail,#UserPassword,#ContactNumber,#ContactMobile,#AreaOfCountry)
SELECT #UserId = SCOPE_IDENTITY()
SET #AllreadyReg = 0
END
however when I use it using c# and asp.net its not returning anything, however when I just execute it it does have a results #UserId and #AllreadyReg but the return value is 0 and a single field.
my c# code is below but it never has any rows
using (SqlConnection con = new SqlConnection(connectionString))
{
Response.Write("Line 61");
using (SqlCommand cmd = new SqlCommand("spR_Register", con))
{
Response.Write("line 64");
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#UserName", TxtUsername.Text.Trim());
cmd.Parameters.AddWithValue("#UserEmail", TxtEmail.Text.Trim());
cmd.Parameters.AddWithValue("#UserPassword", TxtPassword.Text.Trim());
cmd.Parameters.AddWithValue("#ContactNumber", TxtPhone.Text);
cmd.Parameters.AddWithValue("#ContactMobile", TxtMobile.Text);
cmd.Parameters.AddWithValue("#AreaOfCountry", TxtAreaOfCountry.SelectedValue);
cmd.Parameters.AddWithValue("#UserId", ParameterDirection.Output);
cmd.Parameters.AddWithValue("#AllreadyReg", ParameterDirection.Output);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
Response.Write("line 78");
etc etc
can anyone help
thanks
With the edit: the mistake is using ExecuteReader on a command that doesn't select a data grid - that should be done with ExecuteNonQuery.
The important thing here is how the parameter is added. For example:
var alreadyReg = cmd.CreateParameter();
alreadyReg.Direction = System.Data.ParameterDirection.Output;
alreadyReg.ParameterName = "AllreadyReg";
alreadyReg.DbType = DbType.Int32;
cmd.Parameters.Add(alreadyReg);
//...
cmd.ExecuteNonQuery();
//...
int val = (int)alreadyReg.Value;
Depending on the type of DbCommand object, there may be an overload that accepts all of these in one line - the above assumes just DbCommand. With SqlCommand, you can simplify a bit:
var alreadyReg = cmd.Parameters.Add("AllreadyReg", SqlDbType.Int);
alreadyReg.Direction = ParameterDirection.Output;
//...
cmd.ExecuteNonQuery();
//...
int val = (int)alreadyReg.Value
You might have already handled it, but just in case, make sure to specify direction of parameter in c# code.
Here
cmd.Parameters.AddWithValue("#UserId", ParameterDirection.Output);
wrong usage of AddWithValue. The second parameter is parsed as parameter value, not direction type. Use proper parameter contructor and the add the result to collection.

Retrieving SQL Server output variables in c#

I have a stored procedure:
ALTER PROCEDURE [dbo].[pr_Tbl_Test_Insert]
#guidid uniqueidentifier output,
#sname nvarchar(50)
AS
-- INSERT a new row in the table.
INSERT [dbo].[Tbl_Test]
(
[id],
[name]
)
VALUES
(
ISNULl(#guidid, (newid())),
#sname
)
I need the id in C# and put it output in c#:
cmd.Parameters.AddWithValue("#guidid",_id);//_id is SqlGuid
cmd.Parameters.AddWithValue("#sname", "mehdi");
cmd.ExecuteNonQuery();
MessageBox.Show(_id.ToString());
but messagebox show the null value!!
How can I return the id?
I changed it to:
ALTER PROCEDURE [dbo].[pr_Tbl_Test_Insert]
#guidid uniqueidentifier output,
#sname nvarchar(50)
AS
DECLARE #NewID UNIQUEIDENTIFIER
SET #NewID = newid();
-- INSERT a new row in the table.
INSERT [dbo].[Tbl_Test]([id], [name]) VALUES(#NewID, #sname);
SET #guidid = #NewID
and C#
SqlParameter outparam = cmd.Parameters.Add("#guidid",SqlDbType.UniqueIdentifier);
outparam.Direction = ParameterDirection.Output;
cmd.Parameters.AddWithValue("#sname", "mehdi");
cmd.ExecuteNonQuery();
MessageBox.Show(_id.Value.ToString());
but it doesn't return anything
First of all - if it's an OUTPUT parameter, you cannot use .AddWithValue in C# - you need to use:
SqlParameter outParam = cmd.Parameters.Add("#guidid", SqlDbType.Uniqueidentifier);
outParam.Direction = ParameterDirection.Output;
and also, in your T-SQL code, you need to assign the new value to the output parameter!
ALTER PROCEDURE [dbo].[pr_Tbl_Test_Insert]
#guidid uniqueidentifier output,
#sname nvarchar(50)
AS
DECLARE #NewID UNIQUEIDENTIFIER
SET #NewID = newid();
-- INSERT a new row in the table.
INSERT [dbo].[Tbl_Test]([id], [name]) VALUES(#NewID, #sname);
SET #guidid = #NewID
Update: if you run this in your SQL Server Mgmt Studio - does it show anything??
DECLARE #insertedID UNIQUEIDENTIFIER
EXEC dbo.pr_Tbl_Test_Insert #guidid = #insertedID OUTPUT,
#sname = N'TestUser' -- nvarchar(50)
SELECT #insertedID
and in your C# - you have to read out the value of the output parameter after calling ExecuteNonQuery!
SqlParameter outparam = cmd.Parameters.Add("#guidid",SqlDbType.UniqueIdentifier);
outparam.Direction = ParameterDirection.Output;
cmd.Parameters.AddWithValue("#sname", "mehdi");
cmd.ExecuteNonQuery();
Guid newlyInsertedID = new Guid(cmd.Parameters["#guidid"].Value);
MessageBox.Show(newlyInsertedID.ToString());
Before you execute the query you need to specify the direction of the parameter, in this case output. e.g.:
cmd.Parameters.AddWithValue("#guidid",_id);//_id is SqlGuid
cmd.Parameters.AddWithValue("#sname", "mehdi");
cmd.Parameters["#guidid"].Direction = ParameterDirection.Output
cmd.ExecuteNonQuery();
MessageBox.Show(cmd.Parameters["#guidid"].Value.ToString());
You need to construct a SqlParameter using one of the constructors that lets you specify a ParameterDirection, such as this one. Alternatively, construct your parameter and then set the direction using the Direction property.
Check this link on MSDN for more information.
Why are you setting the #guidid uniqueidentifier output as an output parameter? It means it will override it once you execute the stored procedure. If that's your intention, then you need to add a statement after the insert statement to set the output parameter to the value you want. something like this: select #guidid = #generatedID. Yeah look at marc_s code, that's the way you are supposed to do it.
I also found this very frustrating and I could not understand the issue. Although many answers are correct, there was one simple line that was often overlooked by me and others, namely the command needs to be store procedure not just any sql with parameters, so I hope this helps:
cmd.CommandType = CommandType.StoredProcedure;
cmd.Txt should look like this:
#"my_stored_proct "
NOT
#"my_stored_proct #p1, #p2, #p3 out"
So putting it all together. You might want to separate it into several methods. and add TimeOuts etc. However these are what I think are the critical parts that differ from other commands witout output Parameters.
using (SqlCommand cmd= new SqlCommand())
{
cmd.Text= ...;
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter outParam = cmd.Parameters.Add("#guidid", SqlDbType.Uniqueidentifier);
outParam.Direction = ParameterDirection.Output;
using (var connection = new SqlConnection(this.myConnectionString))
{
connection.Open();
cmd.Connection = connection;
try
{
cmd.ExecuteNonQuery();
}
catch
{
// put your sql catches etc. here..
throw;
}
}
var outValue = outParam.Value;
//query outValue e.g. ToString()
}

Categories

Resources