how to use c# variables in sql commands - c#

This is what I want to use;
string insertQuery = #"insert into userinfo (UserName, FirstName, LastName,
E-mail, Password, Country)
values ( '" + uname + "', '" + fname +
"','" + lname + "', '" + email + "')";
where every one of the variables in between the + are string variables with values in them. but when I run this command, I get some incorrect syntax error.
This is the new error i get;
errorSystem.Data.SqlClient.SqlException (0x80131904): String or binary
data would be truncated. The statement has been terminated. at
System.Data.SqlClient.SqlConnection.OnError(SqlException exception,
Boolean breakConnection, Action1 wrapCloseInAction) at
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException
exception, Boolean breakConnection, Action1 wrapCloseInAction) at
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject
stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at
System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior,
SqlCommand cmdHandler, SqlDataReader dataStream,
BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject
stateObj, Boolean& dataReady) at
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds,
RunBehavior runBehavior, String resetOptionsString) at
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior
cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean
async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader
ds) at
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior
cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String
method, TaskCompletionSource1 completion, Int32 timeout, Task& task,
Boolean asyncWrite) at
System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1
completion, String methodName, Boolean sendToPipe, Int32 timeout,
Boolean asyncWrite) at
System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at
Registration.RegistrationPage.Button1_Click1(Object sender, EventArgs
e) in c:\Users\kristhnen.jagambrum\Documents\Visual Studio
2012\Projects\Registration\Registration\RegistrationPage.aspx.cs:line
50 ClientConnectionId:6d959e49-5b62-43be-b202-76f7eb1fbd2c

It's very good that you asked - the code that you show is a perfect illustration of two security issues in a single line:
The table structure is an illustration of what lets hackers steal user passwords.
The C# code is what makes SQL injection attacks possible.
Fixing the first problem is hard: you need to learn about password hashing and how to store user info in DB. Here is a Q&A that will help: Best way to store passwords in DB
The second problem is easier - all you need is replacing the injected values with parameter names, and then adding the values for each parameter name:
... // Create SQL command, then set its text
command.CommandTest = #"INSERT INTO userinfo (
UserName, FirstName, LastName, E-mail, Password_hash, Password_salt, Country
) VALUES ( #uname, #fname, #lname, #email, #pwd_hash, #pwd_salt, #country)";
// Bind the parameters
command.Parameters.Add(new SqlParameter("#uname", uname));
command.Parameters.Add(new SqlParameter("#fname", fname));
... // ...and so on
command.ExecuteNonQuery();

The answer is you don't, because it is a bad idea. You should be using SQlCommand instead
Check This out,and there are plenty of examples of how to use it. Appending variables in the way you doing is considered to be the mistake number 3 in the list of 25 most dangerous programming mistakes.

Try something like this, and not use direct parameter in sql command
public const string InsertStmtUsersTable = "insert into userinfo (UserName, FirstName, LastName,
[E-mail], Password, Country) values (#UserName, #FirstName, #LastName,
#[E-mail], #Password, #Country) "
using(SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
using (SqlCommand command = new SqlCommand(InsertStmtUsersTable, conn))
{
command.CommandType = CommandType.Text;
command.Parameters.Add(new SqlParameter("username", userNameString));
command.Parameters.Add(new SqlParameter("FirstName", FirstNameString));
// Rest of your Parameters here
command.ExecuteNonQuery();
}
}

Related

Getting error for HierarchyId while fetching the data from another server and inserting it into my server c#

Error is
The type of column 'MemberHId' is not supported. The type is 'SqlHierarchyId'.
In both the server the datatype is same "HierarchyId".
I am just using the ADO.Net.
The assembly is Microsoft.SqlServer.ManagedDTS version- 13.0.0.0
We are using Azure Sql.
Tried with different versions of sql assemblies
DataTable dt = new DataTable();
dt.Columns.Add("Code", typeof(string));
dt.Columns.Add("Description", typeof(string));
dt.Columns.Add("NodeId", typeof(int));
dt.Columns.Add("MemberHId", typeof(SqlHierarchyId));
dt.Columns.Add("Level", typeof(int));
//Getting the data from serverAPI which is returning the data in the columns without null records.
dt=apicall();
SqlParameter returnParameter = cmd.Parameters.Add("RetVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = spName;
cmd.Parameters.AddWithValue("#MemberH", dt);
cmd.CommandTimeout = 0;
cmd.Connection.Open();
cmd.ExecuteNonQuery();// Its failing here
My Sp consists of table type param #MemberHType and the procedure returns rows with these columns:
Name | Type
------------+----------
Code | varchar
Description | varchar
NodeID | smallint
MemberHId | hierarchyid
Level | smallint
This is the procedure:
alter PROCEDURE [dbo].[InsertHierarchyData]
(
#MemberHType MemberH READONLY
)
AS
truncate table test
BEGIN TRY
insert into test values ('start select')
--create table test (errormessage varchar(1000))
IF EXISTS (SELECT TOP 1 1 FROM #MemberHType)
BEGIN
insert into test values ('Inside first Insert start')
INSERT INTO HierarchyStaging
(
Code
,[Description]
,NodeID
,MemberhHId
,[Level]
)
SELECT
Code
,[Description]
,NodeId
,MemberhHId
,[Level]
FROM #MemberHType
insert into test values ('Inside first Insert end')
END
END TRY
BEGIN CATCH
SELECT #comment = ERROR_MESSAGE()
,#Status = 'Error'
SET #comment = CONVERT(NVARCHAR(3000),#Comment) + ' Error Severity: ' + CAST(ERROR_SEVERITY() AS varchar(25)) + ' Error state: 30'
GOTO ErrorHandler
END CATCH
The Column in c# is SqlHierarchyId.
Stack-trace:
at System.Data.SqlClient.TdsParser.TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc, Boolean sync, TaskCompletionSource`1 completion, Int32 startRpc, Int32 startParam)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
If I understand the documentation correctly, you can't use SqlHierarchyId as the data type of a DataColumn.
It doesn't appear in the System.Data.SqlTypes Namespace, and it also doesn't appear in the SQL Server Data Type Mappings table, which means there's no documented built in conversion between SQL Server's HierarchyId and a built in type in the .Net framework. (of course, undocumented features have been known to exist in SQL Server, but I wouldn't recommend relying on that).
What you can do, however, is to convert the HierarchyId to nvarchar using a simple cast in T-SQL when you read it into your c# application (which internally is calling the ToString() method):
CAST(MemberhHId AS nvarchar(4000)) as MemberHId
and convert it back using cast when you insert the data (which internally is calling the Parse() method):
CAST(MemberHId AS hierarchyid)

TSQL create a stored procedure using c#

I am trying to create a procedure(drop a procedure and remake it with new data) in my .net project. When I run the same query in Database "Create New Query" it works fine, but when I try to run it in c#, it gives me an error.
private void makeprocedure()
{
string sqlProcedureCreate = #"
IF(OBJECT_ID('usp_HourData') IS NOT NULL)
DROP PROCEDURE IF EXISTS usp_HourData;
GO
CREATE PROCEDURE usp_HourData
AS
BEGIN
SELECT Employee.[First Name] + ' ' + Employee.[Last Name] AS 'Name',
sum(Time.[Total Hours]) AS 'Total Hours'
, FORMAT(Time.[Time in], 'd', 'en-gb') AS 'Worked On'
FROM Employee
inner join Time on
Employee.ID ='" + getID() + "' and Time.EmployeeIdFK = '" + getID()
+ "' WHERE Time.[Time in] between '" + CalendarStart.SelectedDate + "' and '" + CalendarEnd.SelectedDate
+ #"'GROUP BY FORMAT(Time.[Time in], 'd', 'en-gb') ,Employee.[First Name] + ' ' +Employee.[Last Name];
END
";
using (SqlCommand command = new SqlCommand(sqlProcedureCreate, con))
{
command.CommandType = CommandType.Text; //I tried command.CommandType = CommandType.StoredProcedure;
con.Open();
command.ExecuteNonQuery(); //Compiler says error is on this line
con.Close();
}
}
The error is near "GO" and "CREATE/ALTER PROCEDURE" must go first.
System.Data.SqlClient.SqlException was unhandled by user code
Class=15
ErrorCode=-2146232060
HResult=-2146232060
LineNumber=4
Message=Incorrect syntax near 'GO'.
'CREATE/ALTER PROCEDURE' must be the first statement in a query batch.
Number=102
Procedure=""
Server=(LocalDB)\MSSQLLocalDB
Source=.Net SqlClient Data Provider
State=1
StackTrace:
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at WebApplication2.Manager.makeprocedure() in D:\Users\Albin\MyClockIn\WebApplication2\WebApplication2\Manager.aspx.cs:line 209
at WebApplication2.Manager.ButtonSearch_Click(Object sender, EventArgs e) in D:\Users\Albin\MyClockIn\WebApplication2\WebApplication2\Manager.aspx.cs:line 161
at System.Web.UI.WebControls.Button.OnClick(EventArgs e)
at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument)
at System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument)
at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument)
at System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData)
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
InnerException:
How would I go about this error?
This may not be the answer to your question but just an advice about your programming style. These are bad things in your code:
You are concatenating query string. You should use parameters.
You are creating a procedure where query contains data not the parameters. Stored procedure should contain query with parameters and you should pass data to it.
Stored procedures are not supposed to be dropped and recreated each time you access them. I can clearly see you can achieve the same result by just using the select statement. If you are creating stored procedures there must be some data to pass otherwise there is no point in making a stored procedure.
Enough theory, Let's see things in action:
Here is your MakeProcedure (please rename this) Function:
//Rename this function to some useful name
private void makeprocedure()
{
string query = #" SELECT Employee.[First Name] + ' ' + Employee.[Last Name] AS 'Name',
sum(Time.[Total Hours]) AS 'Total Hours'
, FORMAT(Time.[Time in], 'd', 'en-gb') AS 'Worked On'
FROM Employee
inner join Time on
Employee.ID = #EmpId and Time.EmployeeIdFK = #EmpId WHERE Time.[Time in]
between #StartDate and #EndDate GROUP BY FORMAT(Time.[Time in], 'd', 'en-gb'),
Employee.[First Name] + ' ' +Employee.[Last Name];";
using (SqlCommand command = new SqlCommand(query, con))
{
command.CommandType = CommandType.Text;
command.Parameters.AddWithValue("#EmpId", getID());
command.Parameters.AddWithValue("#StartDate", CalendarStart.SelectedDate);
command.Parameters.AddWithValue("#EndDate", CalendarEnd.SelectedDate);
con.Open();
var reader = command.ExecuteReader();
//do something with data in the reader.
con.Close();
}
}

Error in Inserting data in SQL table

I am trying to insert data in a table (say feedback) with columns from(int) and Message(Varchar(MAX)) via c# code but it is continuously annoying me with errors. Please help, I am desperate.
Table description:
From int,Message Varchar(max)
Code I'm using:
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["SampleConnectionString"].ConnectionString);
con.open;
string query="insert into Feedback (From,Message) values(#frm,#msg)";
SqlCommand comm = new SqlCommand(query, con);
comm.Parameters.AddWithValue("#frm", Convert.ToInt32(TextBoxid.Text));
comm.Parameters.AddWithValue("#msg",TextBoxFeedBack.text);
comm.ExecuteNonQuery();
con.Close();
The Error I'm getting is
System.Data.SqlClient.SqlException (0x80131904): Incorrect syntax near
the keyword 'From'. at
System.Data.SqlClient.SqlConnection.OnError(SqlException exception,
Boolean breakConnection) at
System.Data.SqlClient.SqlInternalConnection.OnError(SqlException
exception, Boolean breakConnection) at
System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning() at
System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior,
SqlCommand cmdHandler, SqlDataReader dataStream,
BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject
stateObj) at
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds,
RunBehavior runBehavior, String resetOptionsString) at
System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior
cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean
async) at
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior
cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String
method, DbAsyncResult result) at
System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult
result, String methodName, Boolean sendToPipe) at
System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at
_Default.Button1_Click(Object sender, EventArgs e) in c:\Users\Ajaz\Documents\Visual Studio
2010\WebSites\WebSite26\Default.aspx.cs:line 29
I'm guessing there's error related to data mismatch. Please help.
Thanks
FROM is a reserved keyword in TSQL. You should use it with square brackets like [FROM]
string query="insert into Feedback ([From],Message) values(#frm,#msg)";
As a general recomendation, don't use reserved keywords for your identifiers and object names in your database.
Also use using statement to dispose your SqlConnection like;
string query = "insert into Feedback ([From],Message) values(#frm,#msg)";
using(SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["SampleConnectionString"].ConnectionString))
{
SqlCommand comm = new SqlCommand(query, con);
comm.Parameters.AddWithValue("#frm", Convert.ToInt32(TextBoxid.Text));
comm.Parameters.AddWithValue("#msg",TextBoxFeedBack.text);
con.Open();
comm.ExecuteNonQuery();
con.Close();
}
"From" is the reserved word. Surround it by square brackets:
string query="insert into Feedback ([From],Message) values(#frm,#msg)";
Well, the word FROM is a well known keyword in any SQL language existing in the world. If you want to use it (very bad move) then you need to encapsulate it in square brackets
string query="insert into Feedback ([From],Message) values(#frm,#msg)";
Again, don't do that, change the name of the column before having to much code to change.
Otherwise you will have this problem for the lifetime of your app.

Create webservice to get SQL data

I created a web server to retrieve data from my sql database. For this case I wanted to retrieve all "Reds" from my table where there are Reds, Greens and yellows.
Here is an example of my PRODUCTS table:
So from this table I may have a query to get all the REDS from PRODUCT2, and my sql query would be:
SELECT PRODUCT2 from PRODUCTS where Type = 'Stop';
Here is my stack trace:
System.InvalidOperationException: ExecuteReader: Connection property has not been initialized.
at System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader()
And this query works but when I create my web service and datahelper I get the error that my input string was incorrect and that my value is a string instead of of an int (which it should be)
Here is my web service code:
[WebMethod]
public int GetRed(int Type)
{
return DataHelper.GetRed(Type);
}
Datahelper Code:
public static int GetRed(int Type)
{
int PRODUCT1 = 0;
var con = new SqlConnection(#"Data Source=TestComp\SQLEXPRESS; initial catalog=Database; integrated security=true;");
var cmd = new SqlCommand("Select PRODUCT1 from PRODUCTS where Type = 'Stop'");
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while(dr.Read())
{
PRODUCT1 = (int)dr["PRODUCT1"];
}
dr.Close();
con.Close();
return PRODUCT1;
}
I tested the query in SQL Server and it works fine so not sure what I am doing wrong here when trying to retrieve those values. Any help is appreciated.
Thanks
A lot of time wasted, with your stacktrace, I know the issue: You're not giving your command a connection.
You need this:
cmd.Connection = con;
Before
SqlDataReader dr = cmd.ExecuteReader();

C# Entity Framework Commit Error

I have a weird error when trying to call .SaveChanges() in Entity Framework.
I'm trying to save an Order like this
public void SaveOrder(UserDTO user, ArticleDTO article, PriceDTO price, decimal amount)
{
//Get the order with type cart. If no order exist create a new order with type cart.
var order = _orderRepository.GetCartOrderForCustomer(user.Customer.CustomerREFID);
if (order == null)
{
order = new Order()
{
CustomerREFID = user.Customer.CustomerREFID,
CreateDate = DateTime.Now,
OrderType = OrderType.Cart
};
_orderRepository.Add(order);
_orderRepository.UnitOfWork.Commit();
}
}
Sure its working fine when I'm only calling this method. But when I'm calling another method before this method then I get errors.
The before method just fetch articles and prices.
public IEnumerable<Article> GetArticlesByCategory(int categorySection, int headCategory, string customerREFID)
{
var currentUnitOfWork = this.UnitOfWork as MainBCUnitOfWork;
//Linq query without keys.
var result = (from a in currentUnitOfWork.Articles
join cat in currentUnitOfWork.Categories on a.CategoryID equals cat.CategoryID
join cf in currentUnitOfWork.CategoryReferences on cat.ID equals cf.CategoryID
join c in currentUnitOfWork.Customers on a.Lagstalle equals c.LagStalle
where cf.RefID == categorySection && cat.HuvudKat == headCategory && c.CustomerREFID == customerREFID
select a).ToList();
var artnumbers = result.Select(a => a.Number).ToList();
var prices = currentUnitOfWork.Prices.Where(p => artnumbers.Contains(p.ArtNr) && p.FtgNr == customerREFID).ToList();
Parallel.ForEach(result, a =>
{
a.Prices = prices.Where(p => p.ArtNr == a.Number).ToList();
});
return result.ToList();
}
So when calling SaveOrder I get this error :
{System.Data.SqlClient.SqlException (0x80131904): Violation of PRIMARY KEY constraint 'PK_dbo.PriceArticles'. Cannot insert duplicate key in object 'dbo.PriceArticles'. The duplicate key value is (6653, 1).
The statement has been terminated.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action1 wrapCloseInAction)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at System.Data.Mapping.Update.Internal.DynamicUpdateCommand.Execute(UpdateTranslator translator, EntityConnection connection, Dictionary2 identifierValues, List1 generatedValues)
at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
ClientConnectionId:dfc62e28-3751-4a54-89f4-5fa8195cab2a}
This table and get has nothing to do with Order table ? Why does Entity Framework commit other tables when I only add a new Order ?
How do I work around this ?

Categories

Resources