Laden...

Dapper Parameter funktionieren nicht mit DynamicParameters()

Erstellt von Olii vor 5 Jahren Letzter Beitrag vor 5 Jahren 2.943 Views
O
Olii Themenstarter:in
76 Beiträge seit 2017
vor 5 Jahren
Dapper Parameter funktionieren nicht mit DynamicParameters()

verwendetes Datenbanksystem: <PostgreSQL>

Hallo liebe Forum User,

ich versuche gerade aufgrund von SQL-Injection meine SQL-Funktion umzubauen.

Ich verwende Dapper als MicroORM und die Datenbank PostgrSQL.

Ich habe es nach diesem Beispiel gemacht und mir weitere angesehen:

Dapper Parameters

Aber egal ob ich im SQL String meinen Parameter mit :uuid oder @uuid angebe, bekomme ich nur die Fehlermeldung

Fehlermeldung:
Operator existiert nicht: uuid = text

weil er den Parameter nicht auflösen kann.

Wenn ich das ganze ohne Parameter mache funktioniert es:

return _dBContext._connection.QuerySingleOrDefault<TEntity>("SELECT * FROM applicationuser where IDUser = 'dff6a50b-3a4e-427d-a7b8-f0a5abc170ff'")

ich versuche das seit Stunden hin zu bekommen, werde aber nicht schlauer.

Das hier ist der Code den ich jetzt als letztes versucht habe:

public TEntity GetSingel<TEntity>()
        {
            _dBContext._connection.Open();
            DynamicParameters parameters = new DynamicParameters();
            parameters.Add("uuid", "'dff6a50b-3a4e-427d-a7b8-f0a5abc170ff'");
            return _dBContext._connection.Query<TEntity>("SELECT * FROM applicationuser where iduser = :uuid", parameters).SingleOrDefault(); 
        }

Ich hoffe jemand hat eine Idee, ich bin gerade am verzweifeln.
Liebe Grüße
Olli

16.825 Beiträge seit 2008
vor 5 Jahren

Dapper Parameter funktionieren mit @
Siehe ein 2-Sekunden-Blick in das Tutorial: https://dapper-tutorial.net/parameter-dynamic

O
Olii Themenstarter:in
76 Beiträge seit 2017
vor 5 Jahren

Ich habe ja geschrieben das es weder mit : noch mit @ geht. Selbe Fehlermeldung das der Parameter nicht aufgelöst wurde.

T
2.221 Beiträge seit 2008
vor 5 Jahren

In deinem Beispiel fehlt aber das : oder @ beim Add
Entsprechend solltest du das noch hinzufügen, wie es auch in der Doku steht.
Dann sollte es dein Problem lösen.


parameters.Add(":uuid", "'dff6a50b-3a4e-427d-a7b8-f0a5abc170ff'");

Nachtrag:
Ich finde zwar nicht die passende Beschreibung dazu, aber die Meldung dürfte genau der Hinweis darauf sein, dass du eben den Operator : nicht angegeben hast.
Hier ist die Fehlermeldung scheinbar korrekt aber nicht ganz verständlich auf den ersten Blick.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.825 Beiträge seit 2008
vor 5 Jahren

Du machst nicht das, was das Tutorial zeigt.
Dir fehlt die Zuweisung des @ beim DynamicParameter. Daher mein Hinweis.

O
Olii Themenstarter:in
76 Beiträge seit 2017
vor 5 Jahren

Das habe ich gerade auch mal ausprobiert aber auch nicht.

Ich habe auch das hier probiert:

return _dBContext._connection.Query<TEntity>("SELECT * FROM applicationuser where iduser = @uuid", new {@uuid ="'dff6a50b-3a4e-427d-a7b8-f0a5abc170ff'"}).SingleOrDefault(); 

und

return _dBContext._connection.Query<TEntity>("SELECT * FROM applicationuser where iduser = @uuid", new {@uuid ="dff6a50b-3a4e-427d-a7b8-f0a5abc170ff"}).SingleOrDefault(); 

und

return _dBContext._connection.Query<TEntity>("SELECT * FROM applicationuser where iduser = '@uuid'", new {@uuid ="dff6a50b-3a4e-427d-a7b8-f0a5abc170ff"}).SingleOrDefault();

und auch mit Typangabe

DynamicParameters parameters = new DynamicParameters();
            parameters.Add("@uuid", "dff6a50b-3a4e-427d-a7b8-f0a5abc170ff", dbType: DbType.Guid);

            return _dBContext._connection.Query<TEntity>("SELECT * FROM applicationuser where iduser = @uuid", parameters).SingleOrDefault();

ich weiß nicht was ich noch ausprobieren soll.

Ich mache sicher etwas falsch aber mir wird nicht klar was.

T
2.221 Beiträge seit 2008
vor 5 Jahren

Wird dort immer der gleiche Fehler geworfen?
Dein Code sollte eigentlich so funktionieren.


public TEntity GetSingel<TEntity>()
        {
            _dBContext._connection.Open();
            DynamicParameters parameters = new DynamicParameters();
            parameters.Add("@uuid", "dff6a50b-3a4e-427d-a7b8-f0a5abc170ff", DbType.Guid, ParameterDirection.Input);
            return _dBContext._connection.Query<TEntity>("SELECT * FROM applicationuser where iduser = @uuid", parameters).SingleOrDefault();
        }

@Abt
Ich habe mal bei Github geschaut, Laut der Clean Methode in DynamicParameter sind @, : sowie ? erlaubt für Parameter.
Oder gibt es irgendwo eine fixe Beschränkung?

Nachtrag:
@Olii
In deinem Startbeitrag hast du die Guid nochmal in extra Anführungzeichen gesetzt, diese würden später auch in der DB landen.
Habe ich bei mir korrigiert und auch gleich der DB den richtigen Datentyp per DbType sowie über den ParameterDirection.Input auch gleich klar mitgegeben, dass der Parameter für die Abfrage ist.
Damit sollt es klappen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

O
Olii Themenstarter:in
76 Beiträge seit 2017
vor 5 Jahren

Wenn ich das so ausführe dann kommt von Postgres die Meldung:

PostgresException: 42883: Operator existiert nicht: uuid = text
Npgsql.NpgsqlConnector+<>c__DisplayClass161_0+<<ReadMessage>g__ReadMessageLong|0>d.MoveNext()
Npgsql.NpgsqlConnector+<>c__DisplayClass161_0+<<ReadMessage>g__ReadMessageLong|0>d.MoveNext() in NpgsqlConnector.cs
Npgsql.NpgsqlDataReader.NextResult(bool async, bool isConsuming) in NpgsqlDataReader.cs
Npgsql.NpgsqlDataReader.NextResult() in NpgsqlDataReader.cs
Npgsql.NpgsqlCommand.ExecuteDbDataReader(CommandBehavior behavior, bool async, CancellationToken cancellationToken) in NpgsqlCommand.cs
Npgsql.NpgsqlCommand.ExecuteDbDataReader(CommandBehavior behavior) in NpgsqlCommand.cs
System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader(CommandBehavior behavior)
Dapper.SqlMapper.ExecuteReaderWithFlagsFallback(IDbCommand cmd, bool wasClosed, CommandBehavior behavior) in SqlMapper.cs
Dapper.SqlMapper.QueryImpl<T>(IDbConnection cnn, CommandDefinition command, Type effectiveType)+MoveNext() in SqlMapper.cs
System.Collections.Generic.List<T>.AddEnumerable(IEnumerable<T> enumerable)
System.Linq.Enumerable.ToList<TSource>(IEnumerable<TSource> source)
Dapper.SqlMapper.Query<T>(IDbConnection cnn, string sql, object param, IDbTransaction transaction, bool buffered, Nullable<int> commandTimeout, Nullable<CommandType> commandType) in SqlMapper.cs
ApiPeepConnect.Domain.Database.BaseRepository.BaseQueryDBRepository.GetSingel<TEntity>(string columns, string table, string condition) in BaseDBRepository.cs
+
            return _dBContext._connection.Query<TEntity>("SELECT * FROM applicationuser where iduser = @uuid", parameters).SingleOrDefault();
QueryHandler.Handle(QueryUserProfile query, CancellationToken cancellationToken) in QueryHandler.cs
+
        return _baseQueryRepository.GetSingel<ResponseUserProfile>("iduser, username, displayname, email, description", "applicationuser", string.Format("IDUser = '{0}'", query.id.ToString()));
MediatR.Pipeline.RequestPostProcessorBehavior<TRequest, TResponse>.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
MediatR.Pipeline.RequestPreProcessorBehavior<TRequest, TResponse>.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
ApiPeepConnect.Controllers.ValuesController.Create() in ValuesController.cs
+
            return await _mediator.Send(user);
lambda_method(Closure , object )
Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable+Awaiter.GetResult()
Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor+AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)
System.Threading.Tasks.ValueTask<TResult>.get_Result()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Er erwartet in dem SQL Statement die entsprechende ID aber der Parameter @uuid wird wohl nicht aufgelöst. oder liege ich da falsch?

16.825 Beiträge seit 2008
vor 5 Jahren

T-Virus, wie bereits geschrieben ging es nicht um das @ per se, sondern bei Add.

Ich glaube der Fehler kommt nicht von dem Parameter.
Wo ist diese Stelle hier?

string.Format("IDUser = '{0}'", query.id.ToString()
das riecht fischig.

O
Olii Themenstarter:in
76 Beiträge seit 2017
vor 5 Jahren

Oh den Schreibfehler habe ich garnicht gesehen, aber der sollte keinen Unterschied machen.

Das ganze ist so: Ich habe die Funktion erstellt GetSingle, dort gebe ich Parameter rein. Diese werden aber noch NICHT verwendet. Deswegen habe ich alles in der Funktion gehardcoded um erstmal die Funktionalität zu testen. Das heißt die Parameter columns, table, condition etc. werden momentan alle nicht verwendet. Ich rufe lediglich diese Methode auf. Ich verwende gerade nur den fest geschriebenen Code, ohne Parameter ohne alles. Nur das SQL Statement mit der GUID.

iduser ist ein guid bzw heißen die glaube ich in der Datenbank uuid.

16.825 Beiträge seit 2008
vor 5 Jahren

Übergib dem Parameter mal keinen String, sondern ein Guid.
Ansonsten vergleichst Du auf DB Ebene zwei verschiedene Typen.

O
Olii Themenstarter:in
76 Beiträge seit 2017
vor 5 Jahren

ich hab den Fehler gefunden. War ein dummer Denkfehler.

Für die die es interessiert:

In dieser zeile habe ich natürlich mein GUID String angegeben mit dem DBType GUID, WEIL ich dachte das dieser den String den ich angegeben habe dann in einen GUID umwandelt. Ich dachte mir: "der DbType gibt an was für ein Typ der Value ist und wandelt den vermutlich um". Das war falsch von mir.

parameters.Add("@uuid", "dff6a50b-3a4e-427d-a7b8-f0a5abc170ff", DbType.Guid, ParameterDirection.Input);

So hätte ich es nämlich machen müssen:

parameters.Add("@uuid", new Guid("dff6a50b-3a4e-427d-a7b8-f0a5abc170ff"), DbType.Guid, ParameterDirection.Input);

Ich danke euch für eure Hilfe. Entschuldigt meine Dummheit aber ich lerne noch ._. und versuche wirklich mein bestes.

16.825 Beiträge seit 2008
vor 5 Jahren

Hint: prinzipiell sollte man immer die Parse-Methoden verwende, wenn man von String auf den jeweiligen Typ wechseln will - oder TryParse wenn man über den Inhalt unsicher ist.
Nur im Falle von Guid macht es kaum ein Unterschied, ob man new Guid(string) verwenden, oder Guid.Parse(string) - die Implementierungen sind nahezu identisch.

PS: die Exception hat den Operator (also dem Vergleich) bemängelt; nicht den Parameter.

T
2.221 Beiträge seit 2008
vor 5 Jahren

Das ist natürlich Trickie.
Aber gut zu wissen.
Da ich die Tage auch mal mit Dapper etwas rumspielen will, habe ich dann wenigstens gleich einen Fallstrick gefunden auf den ich achten muss.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.825 Beiträge seit 2008
vor 5 Jahren

Das ist bei ADO.NET nicht anders.

T
2.221 Beiträge seit 2008
vor 5 Jahren

Bei ADO .NET habe ich diesen Fall bisher nie gehabt, da ich eben immer bei (X)SqlParameter ein Object mit dem richtigen Typen übergeben musste.
Dort gibt es auch kein DynamicParameters Konstruktor, da jeder Parameter als eigenes Objekt definiert ist, was diesen Fehlerfall auch besser abfängt bzw. wegen den nicht vorhandenen Add Methoden gar nicht erst zulässt.
Hier wäre es aus meiner Sicht sinnvoller gewesen wenn Dapper die DynamicParameters als Container für eine eigene Klasse definiert hätte, wie es eben auch ADO .NET mit der (X)SqlParameter Klasse macht.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.825 Beiträge seit 2008
vor 5 Jahren

Hi T-Virus, hier geht es nicht um die Container-Klasse des Parameters. Es geht immer noch um den Typvergleich (für den nicht der Parameter verantwortlich ist).
Nimm Dir einfach mal kurz die Zeit das selbst auszuprobieren, die Du auch für das Schreiben des Beitrags verwendet hast und schau Dir an wie SQL Parameter funktionieren - dann siehst es selbst 😃

Hint: es liegt an der Art und Weise wie der SQL Server Parameter verarbeitet (Sonderrolle) - nicht direkt an der SqlParameter Klasse.
Ändert aber an der Sache nichts, dass es bei ADO.NET nicht anders ist.