Benutzer mit den meisten Antworten
WCF Dienst mit SqlCommand Parameter Methode

Frage
-
Hallo.
Habe eine weitere Frage zu WCF Diensten.
Und zwar funktioniert die Methode
[OperationContract] void executeCommand(SqlCommand cmd);
nicht. Liegt glaube ich an dem Parameter SqlCommand, da dieser nicht serialisiert werden kann.
Da aber mit diesem SqlCommand einige Parameter verknüpft sind, will ich ihn nicht unbedingt als string übergeben.
Ist es doch irgendwie möglich einen SqlCommand an eine Methode zu übergeben?
Freitag, 1. Oktober 2010 10:43
Antworten
-
Hallo Christoph,
Deine Vermutung ist korrekt. SqlCommand ist eben nicht als serialisierbar gekennzeichnet (selbst die binäre Serialisierung schlägt fehl).
Eine einfache und praktikable Lösung besteht darin, eine eigene serialisierbare Klasse zu schreiben und mit einem Datenvertrag zu versehen (man kann sich dabei z.B. bei IDbCommand und IDataParameter inspirieren).
Aber für gewöhnlich verwendet man mit WCF eigene, konkrete Request-Klassen, z.B. FindCustomerRequest. Diese Klassen sind ebenfalls mit DataContract markiert und sehr einfach und effizient (enthalten z.B. DataMember-Felder wie CustomerID, CustomerName usw.)Gruß
Marcel- Als Antwort markiert Robert BreitenhoferModerator Donnerstag, 21. Oktober 2010 06:37
Freitag, 1. Oktober 2010 19:56 -
Hallo Christoph,
Ich kenne Deine Anwendungsfälle nicht, also nimmt bitte dieses Beispiel nur als eine sehr allgemeine Anleitung:
using (SimpleServiceClient client = new SimpleServiceClient()) { CustomerInsertRequest[] request = new[] { new CustomerInsertRequest { CustomerID="123", CustomerName="Alfred's Futterkiste AG", CustomerAddress=new CustomerAddress { Street="Teststr. 12", POB="9999", City="Musterhausen" } } }; client.Open(); CustomerInsertResponse response = client.InsertCustomers(request); client.Close(); }
Wie Du siehst, übergibt der Code beim Aufruf von client.InsertCustomers() nicht einfach einen String sondern ein Array von CustomerInsertRequest-Instanzen. Diese werden entsprechend in eine Nachricht serialisiert und an den Dienst übertragen. Der Dienst führt die Abfragen aus und gibt das Ergebnis der Abfrage an den Client zurück, auch nicht als string, sondern schön verpackt als CustomerInsertResponse. Das hat in diesem Fall nichts mit Objektorientierung zu tun, sondern eher mit der Nachrichten- bzw. SOAP-Orientierung von WCF.
Gruß
Marcel- Als Antwort markiert Robert BreitenhoferModerator Donnerstag, 21. Oktober 2010 06:38
Montag, 4. Oktober 2010 08:35 -
Hallo Christoph,
Dass ich in meinem Beispiel nur Strings verwende, ist purer Zufall. Genauso gut täten es andere serialisierbare Typen. Was die Serialisierung angeht, eine kurze Antwort vorab: Man kann nur jene Member übertragen, die auch serialisierbar sind (d.h. Typen, die mit dem Serializable-Attribut markiert wurden).
WCF verwendet standardmäßig dafür den DataContractSerializer. Primitive Typen wie string oder int werden implizit serialisiert, d.h. ohne DataMember direkt angeben zu müssen. Aber man muss verstehen, dass das DataMember-Attribut eine sehr wichtige Funktion hat: Anders als in der klassischen Serialisierung, wo man eine Klasse nur "am Stück" serialisieren konnte, d.h. nur wenn alle ihre Member serialisierbar waren (oder mit NonSerialized markiert waren), bietet WCF einen praktischen opt-in-Mechanismus an. Dieser erlaubt es dem Entwickler genau zu steuern, was er serialisieren und über den Draht schicken möchte. Die mit DataContract gekennzeichnete Klasse kann freilich auch weitere Member enthalten, die nicht serialisierbar sind und auch nicht über den Draht geschickt werden (was manchmal für Initialisierungszwecke verwendet wird). Man muß aber sehr aufpassen, wenn man solche nicht-serialisierbare Typen verwendet, um sich nicht selbst ins Bein zu schießen. In WCF dreht sich alles um Nachrichten/Messages. Klassen bzw. Objekte sind nur eine notwendige und nützliche Verpackung.
Serialisierbare Typen:
http://msdn.microsoft.com/de-de/library/cc656732.aspxVom Datenvertragsserialisierer unterstützte Typen:
http://msdn.microsoft.com/de-de/library/ms731923.aspxBekannte Typen in Datenverträgen:
http://msdn.microsoft.com/de-de/library/ms730167.aspxGruß
Marcel- Als Antwort markiert Robert BreitenhoferModerator Donnerstag, 21. Oktober 2010 06:38
Mittwoch, 6. Oktober 2010 08:19
Alle Antworten
-
Hallo Christoph,
Deine Vermutung ist korrekt. SqlCommand ist eben nicht als serialisierbar gekennzeichnet (selbst die binäre Serialisierung schlägt fehl).
Eine einfache und praktikable Lösung besteht darin, eine eigene serialisierbare Klasse zu schreiben und mit einem Datenvertrag zu versehen (man kann sich dabei z.B. bei IDbCommand und IDataParameter inspirieren).
Aber für gewöhnlich verwendet man mit WCF eigene, konkrete Request-Klassen, z.B. FindCustomerRequest. Diese Klassen sind ebenfalls mit DataContract markiert und sehr einfach und effizient (enthalten z.B. DataMember-Felder wie CustomerID, CustomerName usw.)Gruß
Marcel- Als Antwort markiert Robert BreitenhoferModerator Donnerstag, 21. Oktober 2010 06:37
Freitag, 1. Oktober 2010 19:56 -
Hallo Marcel,
vielen Dank erstmal für deine Antwort. Könntest du mir vielleicht ein ganz kleines Beispiel geben wie ich dann zum Beispiel einen insert Befehl im Dienst
ausführen kann, wenn ich diesem mehrere Parameter mit übergeben will? Bei select Abfragen habe ich ja keine Probleme, da ich den Befehl als string übergeben
kann. Oder soll ich z.B. alle Parameter als string in einer Liste an den Dienst übergeben?
Montag, 4. Oktober 2010 07:23 -
Hallo Christoph,
Ich kenne Deine Anwendungsfälle nicht, also nimmt bitte dieses Beispiel nur als eine sehr allgemeine Anleitung:
using (SimpleServiceClient client = new SimpleServiceClient()) { CustomerInsertRequest[] request = new[] { new CustomerInsertRequest { CustomerID="123", CustomerName="Alfred's Futterkiste AG", CustomerAddress=new CustomerAddress { Street="Teststr. 12", POB="9999", City="Musterhausen" } } }; client.Open(); CustomerInsertResponse response = client.InsertCustomers(request); client.Close(); }
Wie Du siehst, übergibt der Code beim Aufruf von client.InsertCustomers() nicht einfach einen String sondern ein Array von CustomerInsertRequest-Instanzen. Diese werden entsprechend in eine Nachricht serialisiert und an den Dienst übertragen. Der Dienst führt die Abfragen aus und gibt das Ergebnis der Abfrage an den Client zurück, auch nicht als string, sondern schön verpackt als CustomerInsertResponse. Das hat in diesem Fall nichts mit Objektorientierung zu tun, sondern eher mit der Nachrichten- bzw. SOAP-Orientierung von WCF.
Gruß
Marcel- Als Antwort markiert Robert BreitenhoferModerator Donnerstag, 21. Oktober 2010 06:38
Montag, 4. Oktober 2010 08:35 -
Hi Marcel,
danke für deine ausführliche Antwort. Habe noch eine weitere Frage. In deiner DataContract - Klasse werden ja z.b. nur strings verwendet. Ist es aber
möglich in einem DataContract auch nicht serilisierbare Objekte zu benutzen? Und gibt es irgendwo eine Übersicht, über die Objekte, die serilisierbar sind?
MFG,
Christoph
Mittwoch, 6. Oktober 2010 06:48 -
Hallo Christoph,
Dass ich in meinem Beispiel nur Strings verwende, ist purer Zufall. Genauso gut täten es andere serialisierbare Typen. Was die Serialisierung angeht, eine kurze Antwort vorab: Man kann nur jene Member übertragen, die auch serialisierbar sind (d.h. Typen, die mit dem Serializable-Attribut markiert wurden).
WCF verwendet standardmäßig dafür den DataContractSerializer. Primitive Typen wie string oder int werden implizit serialisiert, d.h. ohne DataMember direkt angeben zu müssen. Aber man muss verstehen, dass das DataMember-Attribut eine sehr wichtige Funktion hat: Anders als in der klassischen Serialisierung, wo man eine Klasse nur "am Stück" serialisieren konnte, d.h. nur wenn alle ihre Member serialisierbar waren (oder mit NonSerialized markiert waren), bietet WCF einen praktischen opt-in-Mechanismus an. Dieser erlaubt es dem Entwickler genau zu steuern, was er serialisieren und über den Draht schicken möchte. Die mit DataContract gekennzeichnete Klasse kann freilich auch weitere Member enthalten, die nicht serialisierbar sind und auch nicht über den Draht geschickt werden (was manchmal für Initialisierungszwecke verwendet wird). Man muß aber sehr aufpassen, wenn man solche nicht-serialisierbare Typen verwendet, um sich nicht selbst ins Bein zu schießen. In WCF dreht sich alles um Nachrichten/Messages. Klassen bzw. Objekte sind nur eine notwendige und nützliche Verpackung.
Serialisierbare Typen:
http://msdn.microsoft.com/de-de/library/cc656732.aspxVom Datenvertragsserialisierer unterstützte Typen:
http://msdn.microsoft.com/de-de/library/ms731923.aspxBekannte Typen in Datenverträgen:
http://msdn.microsoft.com/de-de/library/ms730167.aspxGruß
Marcel- Als Antwort markiert Robert BreitenhoferModerator Donnerstag, 21. Oktober 2010 06:38
Mittwoch, 6. Oktober 2010 08:19