C# 在单独的类中使用SQLCommand时使用参数化sql查询

C# 在单独的类中使用SQLCommand时使用参数化sql查询,c#,asp.net,sql-injection,code-reuse,C#,Asp.net,Sql Injection,Code Reuse,我对在ASP.net应用程序中添加参数化sql查询很感兴趣。我看过一些关于避免SQL注入的好文章 string sql = string.Format("INSERT INTO [UserData] (Username, Password, Role, Membership, DateOfReg) VALUES (@Username, @Password, @Role, @Membership, @DateOfReg)"); SqlCommand cmd = new SqlCom

我对在ASP.net应用程序中添加参数化sql查询很感兴趣。我看过一些关于避免SQL注入的好文章

string sql = string.Format("INSERT INTO [UserData] (Username, Password, Role, Membership, DateOfReg) VALUES (@Username, @Password, @Role, @Membership, @DateOfReg)");
        SqlCommand cmd = new SqlCommand(sql, conn);
        try
        {
        cmd.Parameters.AddWithValue("Username", usernameTB.Text);
        cmd.Parameters.AddWithValue("Password", passwordTB.Text);
        cmd.Parameters.AddWithValue("Role", roleTB.Text);
        cmd.Parameters.AddWithValue("Membership", membershipTB.Text);
        cmd.Parameters.AddWithValue("DateOfReg", dorTB.Text);

        conn.Open();
        cmd.ExecuteNonQuery();
        conn.Close();

然而,这种方法对我没有用处,因为我将DB连接耦合到单独的类,因为我已经重用了它

public class DBconnection{     
    public int insertQuery(String query) {



            int affectedRowCount = 0;
            SqlConnection conn = null;
            try{

                conn = new SqlConnection("Server=localhost;Database=master;UID=sa;PWD=sa;");
                SqlCommand cmd = new SqlCommand( query, conn );
                cmd.CommandType = CommandType.Text;

                conn.Open(  );
                affectedRowCount = cmd.ExecuteNonQuery(  );
                conn.Close(  );         

            } catch ( Exception e ){

                       String error = e.Message;

            }

            return affectedRowCount;
    }
}
因此,我只使用下面的代码部分来调用上面的类并向DB插入值

 String SQLQuery1 = insert into Article values('" + Txtname.Text + "','" + TxtNo.Text + "','" + Txtdescription.Text + "' ,0)");
DBconnection dbConn = new DBconnection();
        SqlDataReader Dr = dbConn.insertQuery(SQLQuery1);
请帮助我使用参数化sqlString以避免Sql注入。
在不使用文本框输入的情况下使用@name、@No和@description。

如何代替通用的InsertQuery()方法编写特定的InsertQuery方法

例如:

public void AddNewUser(User u)
{
   var query = "insert Users (name, password) values (@0, @1)";
   SqlCommand cmd = new SqlCommand(query, conn);
        try
        {
        cmd.Parameters.AddWithValue("@0", u.UserName);
        cmd.Parameters.AddWithValue("@1", u.Password);
        }
}
这样做的好处是,所有SQL逻辑都位于另一个类中,而调用类需要知道如何构造查询等

它还使您的代码更具可读性,因为您可以在方法调用中看到
AddUser
UpdateUser
ChangePassword
,而不必在此时读取SQL来尝试猜测程序中发生了什么

然而如果你要做这样的事情,你应该去看看一些MicroORMs,我个人最喜欢的是(或)

PetaPoco和其他像Massive和Dapper这样的公司会让你做如下事情:

database.Insert(u);

其中u是映射到数据库表的用户对象。它使用ADO.NET并确保使用SQL参数。

我建议使用LINQ to SQL,这是一个很好的例子

如何保护LINQ到SQL免受SQL注入攻击

答:SQL注入对于通过连接用户输入形成的传统SQL查询来说是一个重大风险。LINQtoSQL通过在查询中使用SqlParameter避免了这种注入。用户输入将转换为参数值。此方法可防止从客户输入中使用恶意命令

您可以使用
DataContext
(右键单击项目以添加新项并添加
LINQ to SQL class
模板,然后使用服务器资源管理器向其添加对象)以简单的方式从SQL数据库中删除数据

我已经有一段时间没有使用它了,但我相信您的代码会有点像这样:

UserData user = new UserData();

user.Username = ...;
user.Password = ...;
user.Role = ...;
user.Membership = ...;
user.DateOfReg = ...;

db.UserDatas.InsertOnSubmit(user);
db.SubmitChanges();
当您调用SubmitChanges时,LINQtoSQL自动生成并执行SQL命令,它必须将您的更改传输回数据库

Edit1:

作为补充说明,要从数据库检索现有项,可以执行以下操作:

var user = (from i in db.UserDatas
            where i.UserName == "devan"
            select i).Single();

哦,这是我回答关于数据库登录信息的问题时的标准策略,我必须恳求你,看在上帝的份上,以及所有神圣的事情上。

这样做是完全合理的,但是让你的类回调(lambda/委托)来获取参数。这是由各种重载实例方法调用的类中的静态方法:

private static int SqlExec(string ConnectionString, string StoredProcName, Action<SqlCommand> AddParameters, Action<SqlCommand> PostExec)
        {
            int ret;
            using (var cn = new SqlConnection(ConnectionString))
            using (var cmd = new SqlCommand(StoredProcName, cn))
            {
                cn.Open();
                cmd.CommandType = CommandType.StoredProcedure;

                if (AddParameters != null)
                {
                    AddParameters(cmd);
                }

                ret = cmd.ExecuteNonQuery();

                if (PostExec != null)
                {
                    PostExec(cmd);
                }
            }
            return ret;
        }
对于非存储过程调用也可以这样做

在您的情况下,它看起来像:

DBconnection.InsertQuery(
    "INSERT INTO [UserData]
        (Username, Password, Role, Membership, DateOfReg)
        VALUES (@Username, @Password, @Role, @Membership, @DateOfReg)"
    ,cmd => {
                cmd.Parameters.AddWithValue("Username", usernameTB.Text);
                cmd.Parameters.AddWithValue("Password", passwordTB.Text);
                cmd.Parameters.AddWithValue("Role", roleTB.Text);
                cmd.Parameters.AddWithValue("Membership", membershipTB.Text);
                cmd.Parameters.AddWithValue("DateOfReg", dorTB.Text);
            }
);

这将按照您希望的方式将所有数据库内容放在一起,并使数据库连接保持其内部隔离。

谢谢。这是我的工作,这是我在寻找的。:)
DBconnection.InsertQuery(
    "INSERT INTO [UserData]
        (Username, Password, Role, Membership, DateOfReg)
        VALUES (@Username, @Password, @Role, @Membership, @DateOfReg)"
    ,cmd => {
                cmd.Parameters.AddWithValue("Username", usernameTB.Text);
                cmd.Parameters.AddWithValue("Password", passwordTB.Text);
                cmd.Parameters.AddWithValue("Role", roleTB.Text);
                cmd.Parameters.AddWithValue("Membership", membershipTB.Text);
                cmd.Parameters.AddWithValue("DateOfReg", dorTB.Text);
            }
);