Ich habe einen WCF-Dienst in IIS gehostet. Die Absicht ist, dass Clients einen Anruf tätigen und eine benutzerdefinierte Klasse empfangen, die in einem anderen Projekt/einer anderen DLL definiert ist. Ich habe einen Dienst-Client mit der svcutil.exe generiert. Das Problem ist, dass dieser automatisch generierte Client eine neue Teil-/Proxydefinition für die Klasse enthält, die ich vom Dienst zurückgeben möchte. Jetzt wird beim Kompilieren ein Konvertierungsfehler zwischen meiner ursprünglichen benutzerdefinierten Klasse und der neuen partiellen Definition ausgelöst. Wie können Sie also benutzerdefinierte Typen von einem WCF-Dienst zurückgeben? Ratschläge sind willkommen.
Antworten
Zu viele Anzeigen?Wenn der Typ, den Sie von Ihrem Dienstaufruf zurückgeben möchten, nicht als DataContract
dann können Sie sie nicht von WCF zurückgeben, ohne Ihrer Client-Anwendung eine Kopie der gleichen Assembly zur Verfügung zu stellen.
using System;
using System.ServiceModel;
[ServiceContract]
interface IService
{
[OperationContract]
TimeSpan GetTimeSpan();
}
class Service : IService
{
public TimeSpan GetTimeSpan() { return DateTime.Now.TimeOfDay; }
}
Warum funktioniert dann der vorherige Code? Er funktioniert, weil beide Seiten des Dienstaufrufs über System.dll
damit sie beide über die System.TimeSpan
Typ, der der Rückgabetyp des OperationContracts ist GetTimeSpan()
.
Hier ist ein Beispiel mit einer DataContract
:
using System;
using System.ServiceModel;
using System.Runtime.Serialization;
[ServiceContract]
interface IService
{
[OperationContract]
Contract GetContract();
}
[DataContract]
class Contract
{
[DataMember]
public String MyProperty { get; set; }
}
class Service : IService
{
public Contract GetContract() { return new Contract(); }
}
Jetzt haben Sie einer von Ihnen definierten Klasse Serialisierungsattribute zugewiesen ( Contract
) - dies ermöglicht Ihnen die Verwendung von svcutil.exe
um Proxy-Klassen in Ihrer Client-Anwendung zu erstellen, die serialisiert und an den WCF-Dienst gesendet werden.
Wenn Sie nun einen Typ zurückgeben wollen, der nicht ein DataContract
müssen Sie eine Kopie der Baugruppe, die diesen Typ enthält, für Ihre Client-Anwendung bereitstellen.
Unter anderem muss der Benutzer die Dienstreferenz so konfigurieren, dass sie Ihre Typen aus der DLL verwendet und nicht die vom Proxy definierte Klasse - http://msdn.microsoft.com/en-us/library/bb628653.aspx
Wir haben diesen Weg bereits in der Vergangenheit beschritten, und das Problem ist in der Tat, dass es sich um zwei verschiedene Klassen handelt, so dass Sie dem von @Rich Reuter angegebenen Link folgen müssen;
Wir haben jedoch auf die harte Tour gelernt, warum dies eine schlechte Praxis ist, da es gegen den dritten Grundsatz der SOA verstößt - "Dienste teilen Schema und Vertrag, nicht Klasse".
Natürlich besteht das Problem nicht nur darin, dass man sich nicht an eine "Regel" hält, die irgendwann einmal von jemandem aufgestellt wurde, sondern auch darin, dass es gute Gründe dafür gab, dies vorzuschlagen - wir haben gelernt, dass der Preis einer solch engen Kopplung zwischen dem Dienst und dem Client bedeutet, dass es sehr schwer ist, einen von beiden freizugeben - wenn der Dienst ein weiteres Feld zu dieser Klasse hinzufügen muss, um einen anderen Client zu bedienen, könnte der erste Client davon betroffen sein; wenn der Dienst dann etwas an der Klassendefinition ändern muss (um einen anderen Client zu bedienen), wird wieder der erste Client betroffen sein und umgekehrt - der Client kann den Lebenszyklus des Dienstes beeinflussen.
Bei großen Projekten wird dies schnell zu einem enormen Wartungsaufwand.
Nur zum Zweiten Yossi / Reich Gedanken:
- ja, Sie können einen Verweis auf die gemeinsam genutzte DLL hinzufügen (anstatt die generierte Proxyklasse zu verwenden)
- ja, es macht einen Großteil der Absicht von Datenverträgen zunichte, und wenn irgendeine Art von benutzerdefinierter Serialisierung stattfindet, können Sie Probleme haben, Ihren Dienst zu erweitern
Ich habe diesen Weg schon einmal beschritten und wünschte in gewisser Weise, ich hätte es nicht getan. Re Erweiterbarkeit / benutzerdefinierte Serialisierung - Sie haben zu sein sehr vorsichtig. Etwas einfacher ist es, wenn Sie einen vorgerollten Serialisierer verwenden, z. B. protobuf-net (die direkt in WCF integriert werden kann und auf Erweiterbarkeit ausgelegt ist), aber nicht einfach.
Tatsächlich ist eine Vorteil der gemeinsamen Nutzung der Klassen ist, dass sie das Testen ein wenig einfacher macht: da man die gleichen IFoo
überall kann man sich darüber lustig machen, dass IFoo
mit guten Erfolgsaussichten. Es ist schwieriger zu spotten, wenn der Proxy involviert ist (da Sie mehr bewegliche Teile zwischen dem Testcode und dem Produktionscode ändern).