2016-04-12 23 views
3

C# 'da çalışmam gereken ve C# kodundan parametre almam gereken bir SQL deyim var. SQL enjeksiyonunu önlemek için saklı yordamların tercih edildiğini biliyorum ancak bunu C# 'da yapmak istiyorum.C# geçici saklı yordamını çalıştırıyor

Bu SQL'i C# ye çeviriyorum ancak SQL Server Management Studio'da sorgu çalışmasına rağmen bir hatayla karşılaştım. Ben #AddCriteriaTable yordamı çalıştırmayı denediğinizde

-- 1.) Declare a criteria table which can be any number of rows 
BEGIN TRY 
    DROP TABLE #CriteriaTable 
END TRY 
BEGIN CATCH 
END CATCH 

CREATE TABLE #CriteriaTable (ParameterCode VARCHAR(64), Value VARCHAR(64)) 

-- 2.) Declare a procedure to add criteria table 
BEGIN TRY 
    DROP PROCEDURE #AddCriteriaTable 
END TRY 
BEGIN CATCH 
END CATCH 
go 

CREATE PROCEDURE #AddCriteriaTable 
    (@ParameterCode VARCHAR(64), @Value VARCHAR(64)) 
AS 
    INSERT #CriteriaTable 
    VALUES(@ParameterCode, @Value) 
GO 

-- 3.) Do a computation which accesses the criteria 
BEGIN TRY 
    DROP PROCEDURE #ComputeBasedOnCriteria 
END TRY 
BEGIN CATCH 
END CATCH 
go 

CREATE PROCEDURE #ComputeBasedOnCriteria 
    (@product VARCHAR(36) = 'ABC', 
     @currency VARCHAR(3) = 'USD', 
     @zScore FLOAT = .845) 
AS 
    -- Code inside this procedure is largely dynamic sql. 
    -- This is just a quick mock up 
    SELECT 
     @Product ProductCode, 
     @currency Currency, 
     950 ExpectedRevenue, 
     * 
    FROM 
     #CriteriaTable c 
    PIVOT 
     (min (Value) FOR ParameterCode IN 
      ([MyParam1], MyParam2, MyParam3) 
     ) AS pvt 
    GO 

    --End of code for Configuration table 

-- Samples: Execute this to add criteria to the temporary table that will be used by #ComputeBasedOnCriteria 
EXEC#AddCriteriaTable 'MyParam1', 'MyValue1' 
EXEC#AddCriteriaTable 'MyParam2', 'MyValue3' 
EXEC#AddCriteriaTable 'MyParam3', 'MyValue3' 

--Execute the procedure that will return the results for the screen 
EXEC#ComputeBasedOnCriteria 

Result is:

Şimdi bir hatayla karşılaşırsanız bu C# çalışıyorum: Geçici saklı yordam ve aşağıdaki geçici tablosu kullanır.

İstisna: System.Data.SqlClient.SqlException, anahtar kelime 'PROC' yakınında yanlış sözdizimi bunu atar son satırına ikinci üzerindeki ExecuteQuery çalıştırmayı denediğinizde.

Neden SQL Server'da çalışıyor, ancak C# kodunda çalışmıyor? Bunu C# yapmanın başka bir yolu var mı? Bu C# - db çalışmasını hala öğrenirken takip etmem gereken kurallar varsa bana bildirin.

enter image description here

DÜZENLEME: Ben normal bir saklı yordam olarak bunu yapmak ve ancak diyemeyiz takım sorunları vardır bir DataTable geçebileceği biliyorum ve bir metin olarak sp kullanmak beni zorlar. Bu anlamda sadece prosedürü oluştururken beri, sadece ihtiyaç buraya değerler geçirmek için yapmaz

cmd.CommandText = @"CREATE PROC#AddCriteriaTable (@ParameterCode VARCHAR(64), @Value VARCHAR(64)) AS INSERT #CriteriaTable VALUES (@ParameterCode, @Value)"; 
cmd.Parameters.AddWithValue("@ParameterCode", request.Criteria.First().Key; 
cmd.Parameters.AddWithValue("@Value", request.Criteria.First().Value; 
var reader2 = cmd.ExecuteReader(); 

:

+0

tahmin Im daki SQL CREATE PROC çünkü

AMA tüm bu ayrı, bir hata alıyorsanız onun daha Sorunla şu C# arama yapmak nasıl. son exeC#computebasedoncritieria önce tüm satırları executenonquery olurdu, satırlar, son veri almak için normal bir sorgu olması gerekir - C# kodunuzu gösterebilir miyim – BugFinder

+0

Ben C# kod içeren görüntü yapıştırılır. Henüz #computebasedoncritieria kodlamadım; #AddCriteriaTable yürütülmesi bir hata atar. –

+1

Kodunuzda daraltma Yaptığınız gibi, yaptığınız gibi bir işlem yapmak için beklemediğiniz gibi, bir başka execnoquery ile yapmasını beklersiniz, daha sonra çalıştırırsınız. Bu son komut kümesinde – BugFinder

cevap

3

başarısız olduğunun sebebi burada CREATE PROC bölüme parametreleri geçiyoruz olduğunu prosedürü yürütürken bunları geçmek için. Bir izlemesi çalıştırırsanız bu sunucuda yürütülmektedir gibi bir şey göreceksiniz: SSMS çalıştırdığınızda aynı yanlış sözdizimi hatası atar

EXEC sp_executesql 
     N'CREATE PROC#AddCriteriaTable (@ParameterCode VARCHAR(64), @Value VARCHAR(64)) AS INSERT #CriteriaTable VALUES (@ParameterCode, @Value)', 
     N'@ParameterCode VARCHAR(64),@Value VARCHAR(64)', 
     @ParameterCode = 'MyParam1', 
     @Value = 'MyValue1' 

. Tek ihtiyacınız olan:

EXEC sp_executesql 
    N'CREATE PROC#AddCriteriaTable (@ParameterCode VARCHAR(64), @Value VARCHAR(64)) AS INSERT #CriteriaTable VALUES (@ParameterCode, @Value)'; 

Yani C# ihtiyacınız olacaktır:

//First Create the procedure 
cmd.CommandText = @"CREATE PROC#AddCriteriaTable (@ParameterCode VARCHAR(64), @Value VARCHAR(64)) AS INSERT #CriteriaTable VALUES (@ParameterCode, @Value)"; 
cmd.ExecuteNoneQuery(); 

//Update the command text to execute it, then add parameters 
cmd.CommandText = "EXECUTE #AddCriteriaTable @ParameterCode, @Value;"; 
cmd.Parameters.AddWithValue("@ParameterCode", request.Criteria.First().Key; 
cmd.Parameters.AddWithValue("@Value", request.Criteria.First().Value; 
var reader2 = cmd.ExecuteReader(); 

Sana geçici tabloya veri eklemek için her şeyi, geçici saklı yordam karmaşık hale bitti kill görünüyor düşünüyorum. Koddan çalıştırıyorsanız, her şeyi yeniden kullanmanız olası gibi görünüyor, bu nedenle neden hesaplamanız için numaralı yordamın kalıcı bir prosedürüne sahip değilsiniz ve ardından yürütme örneklerini yönetmek için tanımlı bir tür kullanın.

Yani öncelikle türünü oluşturmak:

CREATE TYPE dbo.CriteriaTableType AS TABLE (ParameterCode VARCHAR(64), Value VARCHAR(64)); 

Sonra procdure oluşturun: çalıştırmak için nihayet Sonra

CREATE PROC dbo.ComputeBasedOnCriteria 
(
    @product  VARCHAR(36)='ABC', 
    @currency  VARCHAR(3)='USD', 
    @zScore   FLOAT = .845, 
    @CriteriaTable dbo.CriteriaTableType READONLY 
) 
AS 
--Code inside this proc is largely dynamic sql. This is just a quick mock up 
SELECT 
     @Product ProductCode 
     ,@currency Currency 
     ,950 ExpectedRevenue 
     ,* 
FROM @CriteriaTable c 
     PIVOT (MIN (Value) FOR ParameterCode IN (MyParam1, MyParam2,MyParam3)) AS pvt; 
GO 

:

DECLARE @Criteria dbo.CriteriaTableType; 
INSERT @Criteria 
VALUES 
    ('MyParam1', 'MyValue1'), 
    ('MyParam2', 'MyValue2'), 
    ('MyParam3', 'MyValue3'); 

EXECUTE dbo.ComputeBasedOnCriteria @CriteriaTable = @Criteria; 

Hatta C# kriter tablosu doldurabilirsiniz ve sadece bunu C# 'dan prosedüre geçirin.

var table = new DataTable(); 
    table.Columns.Add("ParameterCode", typeof(string)).MaxLength = 64; 
    table.Columns.Add("Value", typeof(string)).MaxLength = 64; 

    foreach (var criterion in request.Criteria) 
    { 
     var newRow = table.NewRow(); 
     newRow[0] = criterion.Key; 
     newRow[1] = criterion.Value; 
     table.Rows.Add(newRow); 
    } 
    using (var connection = new SqlConnection("connectionString")) 
    using (var command = new SqlCommand("dbo.ComputeBasedOnCriteria", connection)) 
    { 
     var tvp = command.Parameters.Add("@CriteriaTable", SqlDbType.Structured); 
     tvp.TypeName = "dbo.CriteriaTableType"; 
     tvp.Value = table; 

     using (var reader = command.ExecuteReader()) 
     { 
      while (reader.Read()) 
      { 
       //Do Something with your results 
      } 
     } 
    } 
+0

Aslında sözcük 'PROC'dir. SO'daki bir kişi bunu 'PROCEDURE' olarak düzenledi. Şimdi geri gönderdim. Ekran görüntüsünden gelen hata, ExecuteReader'ın yaptığı üçüncü komut metnine dayanmaktadır. Bana bunun neden başarısız olduğu hala net değil. Kodunuzu kontrol edeceğim, teşekkürler! –

+0

Kodu gösterdiğiniz çalışmayı gerçekten takdir ediyorum. Sadece şu anda bir SP yaklaşımı kullanamadım (bkz. EDIT). İlk başta önerdiğinize benzer şekilde tasarladım ama bir metin sp olması gerekiyordu. Temp tablosu, iki SP'nin veriyi kullanabilmesi için ... –

+0

Bunu çözdüm, düzenlememde daha iyi açıkladım, ama bunun özü, parametre değerlerini "CREATE PROC" deyimine iletmenizdir. gerekli değil. – GarethD

1

Eğer o zaman sen de sadece C# üzerinden SQL yürütmek ve Usul unutabiliriz C# yoluyla saklı yordam oluşturmak için SQL yürütme yapıyorsanız.

SQL Enjeksiyonunu önlemek için saklı yordamın kullanılma noktası yalnızca, saklı yordamın sunucuda zaten var olması ve kodu kullanarak oluşturmamanız durumunda geçerlidir.

Burada Parametrelenmiş bir sorgu kullanarak SQL enjeksiyonunu önleyebilirsiniz. Parametreler, veri tipini doğrulayarak sql enjeksiyonunu engeller. Bu nedenle, kodunuza bir tamsayı eklerseniz, enjeksiyon yapmaya çalışan biri, beklenen sonucu değiştiren özel karakterler içeren bir dize sağlayamaz. Eğer C# yerine CREATE PROCEDURE