2016-04-12 23 views
3

Ich habe eine SQL-Anweisung, die ich in C# ausführen muss und müssen Parameter von C# -Code erhalten. Ich weiß, dass gespeicherte Prozeduren bevorzugt werden, um SQL-Injection zu vermeiden, aber ich versuche nur, dies in C# zu tun.C# temporäre gespeicherte Prozedur ausgeführt

Ich übersetze diese SQL in C#, aber ich habe einen Fehler gefunden, obwohl die Abfrage in SQL Server Management Studio funktioniert. Es nutzt temporär gespeicherte Prozedur und temporäre Tabelle unten:

-- 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:

nun diesen in C# ich versuche, einen Fehler auf, wenn ich versuche, die #AddCriteriaTable Prozedur auszuführen. Wenn ich versuche, die ExecuteQuery auf der zweiten bis zur letzten Zeile laufen wirft:

Ausnahme: System.Data.SqlClient.SqlException, falsche Syntax nahe dem Schlüsselwort ‚PROC‘.

Warum funktioniert es in SQL Server, aber nicht in C# -Code? Gibt es eine andere Möglichkeit, dies in C# zu tun? Lassen Sie mich wissen, ob es C# Richtlinien gibt, denen ich folgen sollte, während ich noch diese C# - db Arbeit lerne.

enter image description here

EDIT: Ich weiß, dass ich dies als eine normale gespeicherte Prozedur tun konnte, und in einem Datatable passieren aber es gibt Team Fragen, die ich nicht sagen kann, und es zwingt mich, die sp als Text zu verwenden.

+0

Im haben erraten seiner mehr, wie Sie die C# Anrufe, das ist die Frage zu tun. alle Zeilen vor der letzten ExeC#computebasedoncritieria würden excutenonquery, Zeilen sein, die letzte müsste eine normale Abfrage sein, um die Daten zu erhalten - können Sie Ihren C# Code zeigen – BugFinder

+0

Ich habe das Bild eingefügt, das meinen C# Code enthält. Ich habe die #computebasedoncritieria noch nicht codiert; Das Ausführen der #AddCriteriaTable löst einen Fehler aus. –

+1

Schielen auf Ihren Code Ich erwarte nicht, dass Sie das Verfahren wie Sie haben, wie Sie es nennen, wie Sie es machen, ich erwarte, dass Sie es mit einer anderen Execnoquery machen, dann führen Sie es aus .. es scheint eine Mischung aus beidem zu haben in diesem letzten Satz von Befehlen – BugFinder

Antwort

3

Der Grund, dass es versagt ist, dass Sie Parameter an die CREATE PROC Abschnitt hier sind vorbei:

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(); 

Es ist nicht sinnvoll, die Werte macht hier zu passieren, da die Prozedur einfach erstellen, brauchen Sie nur um sie beim Ausführen der Prozedur zu übergeben.

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' 

, die die gleichen falschen Syntax-Fehler werfen, wenn sie in SSMS ausführen: Wenn Sie eine Spur laufen Sie so etwas wie dies auf dem Server ausgeführt wird, sehen. Alles was Sie brauchen ist:

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

So in C# müssten Sie: über töten

//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(); 

Ich glaube, Sie sind über alles zu komplizieren, scheint eine temporär gespeicherte Prozedur Daten in eine temporäre Tabelle hinzuzufügen. Wenn Sie aus Code ausführen, scheint es wahrscheinlich, dass Sie alles wiederverwenden müssen, also warum nicht einfach eine permanente Prozedur für Ihre Berechnung haben, und dann einen definierten Typ verwenden, um Instanzen der Ausführung zu verwalten.

So erstellen Sie zuerst Ihre Art:

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

Dann wird Ihr procdure erstellen:

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 

Dann führen schließlich zu:

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

EXECUTE dbo.ComputeBasedOnCriteria @CriteriaTable = @Criteria; 

Sie können sogar die Kriterientabelle in C# bevöl und übergeben Sie dies einfach von C# an die Prozedur.

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

Eigentlich ist das Wort 'PROC'. Jemand in SO hat es auf "PROCEDURE" bearbeitet. Ich gab es jetzt zurück. Der Fehler des Screenshots basiert auf dem dritten Befehlstext, den ExecuteReader ausführt. Es ist mir immer noch nicht klar, warum das scheitert. Ich werde deinen Code überprüfen, danke! –

+0

Ich schätze wirklich die harte Arbeit, die du getan hast, den Code zeigend. Es ist nur so, dass ich zu diesem Zeitpunkt keinen SP-Ansatz verwenden konnte (siehe EDIT). Ich habe es ursprünglich entworfen, ähnlich zu dem, das Sie vorschlugen, aber es endete, ein Text-SP sein zu müssen. Die Temp-Tabelle ist so, dass zwei SPs die Daten verwenden können. –

+0

Ich habe es herausgefunden, ich habe es in meinem Edit besser erklärt, aber das Wesentliche davon ist, dass Sie Parameterwerte an die Anweisung 'CREATE PROC' übergeben, die ist nicht nötig. – GarethD

1

Wenn Sie SQL ausführen eine gespeicherte Prozedur über C# erstellen, dann könnten Sie auch nur Ihre SQL über C# ausführen und über die Vorgehensweise vergessen.

Der Punkt der Verwendung einer gespeicherten Prozedur, um SQL Injection zu vermeiden, gilt nur, wenn die gespeicherte Prozedur bereits auf dem Server vorhanden ist und Sie nicht über den Code erstellen.

Sie können die SQL-Injektion hier vermeiden, indem Sie eine parametrisierte Abfrage verwenden. Parameter verhindern die SQL-Injektion durch Validierung des Datentyps. Wenn Sie also eine Ganzzahl in Ihren Code einfügen, kann eine Person, die versucht, eine Injektion durchzuführen, keine Zeichenfolge mit Sonderzeichen angeben, die das erwartete Ergebnis ändert.

ABER abgesehen von all das, bist du einen Fehler bekommen, weil Sie CREATE PROC in Ihrem SQL in C# statt CREATE PROCEDURE

Verwandte Themen