Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Artikel wird beschrieben, wie Sie eine Anwendung migrieren, die .NET Remoting verwendet, um Windows Communication Foundation (WCF) zu verwenden. Es vergleicht ähnliche Konzepte zwischen diesen Produkten und beschreibt dann, wie mehrere gängige Remotingszenarien in WCF durchgeführt werden.
.NET Remoting ist ein Legacyprodukt, das nur aus Gründen der Abwärtskompatibilität unterstützt wird. Es ist nicht sicher in gemischten Umgebungen, da sie die separaten Vertrauensstufen zwischen Client und Server nicht verwalten kann. Beispielsweise sollten Sie niemals einen .NET Remoting-Endpunkt für das Internet oder für nicht vertrauenswürdige Clients verfügbar machen. Es wird empfohlen, vorhandene Remotinganwendungen zu neueren und sichereren Technologien zu migrieren. Wenn das Design der Anwendung nur HTTP verwendet und RESTful ist, empfehlen wir ASP.NET Web-API. Weitere Informationen finden Sie unter ASP.NET Web-API. Wenn die Anwendung auf SOAP basiert oder nicht http-Protokolle wie TCP erfordert, empfehlen wir WCF.
Vergleich von .NET Remoting mit WCF
In diesem Abschnitt werden die grundlegenden Bausteine von .NET Remoting mit ihren WCF-Entsprechungen verglichen. Wir verwenden diese Bausteine später, um einige gängige Clientserverszenarien in WCF zu erstellen. Das folgende Diagramm fasst die Wichtigsten Ähnlichkeiten und Unterschiede zwischen .NET Remoting und WCF zusammen.
| .NET-Remotezugriff | WCF | |
|---|---|---|
| Servertyp | Unterklasse MarshalByRefObject |
Mit dem Attribut [ServiceContract] markieren |
| Dienstvorgänge | Öffentliche Methoden des Servertyps | Mit dem Attribut [OperationContract] markieren |
| Serialisierung |
ISerializable oder [Serializable] |
DataContractSerializer oder XmlSerializer |
| Übergebene Objekte | Als Wert oder Verweis | Nur als Wert |
| Fehler/Ausnahmen | Jede serialisierbare Ausnahme | FaultContract<TDetail> |
| Clientproxyobjekte | Streng typisierte transparente Proxys werden automatisch aus MarshalByRefObjects generiert. | Stark typisierte Proxys werden bei Bedarf über „ChannelFactory<TChannel>“ generiert. |
| Plattform erforderlich | Sowohl Client als auch Server müssen Microsoft OS und .NET verwenden | Plattformübergreifend |
| Nachrichtenformat | Privat | Branchenstandards (z. B. SOAP und WS-*) |
Vergleich der Serverimplementierung
Erstellen eines Servers in .NET Remoting
.NET Remoting-Servertypen müssen von MarshalByRefObject abgeleitet werden und Methoden definieren, die der Client aufrufen kann, wie die folgenden:
public class RemotingServer : MarshalByRefObject
{
public Customer GetCustomer(int customerId) { … }
}
Die öffentlichen Methoden dieses Servertyps werden zum öffentlichen Vertrag, der Klienten zur Verfügung steht. Es gibt keine Trennung zwischen der öffentlichen Schnittstelle des Servers und deren Implementierung – ein Typ behandelt beide.
Nachdem der Servertyp definiert wurde, kann er clients wie im folgenden Beispiel zur Verfügung gestellt werden:
TcpChannel channel = new TcpChannel(8080);
ChannelServices.RegisterChannel(channel, ensureSecurity : true);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(RemotingServer),
"RemotingServer",
WellKnownObjectMode.Singleton);
Console.WriteLine("RemotingServer is running. Press ENTER to terminate...");
Console.ReadLine();
Es gibt viele Möglichkeiten, den Remotingtyp als Server verfügbar zu machen, einschließlich der Verwendung von Konfigurationsdateien. Dies ist nur ein Beispiel.
Erstellen eines Servers in WCF
Der entsprechende Schritt in WCF umfasst das Erstellen von zwei Typen – den öffentlichen "Dienstvertrag" und die konkrete Implementierung. Der erste wird als Schnittstelle deklariert, die mit [ServiceContract] gekennzeichnet ist. Für Clients verfügbare Methoden werden mit [OperationContract] gekennzeichnet:
[ServiceContract]
public interface IWCFServer
{
[OperationContract]
Customer GetCustomer(int customerId);
}
Die Implementierung des Servers wird in einer separaten konkreten Klasse definiert, wie im folgenden Beispiel:
public class WCFServer : IWCFServer
{
public Customer GetCustomer(int customerId) { … }
}
Nachdem diese Typen definiert wurden, kann der WCF-Server clients zur Verfügung gestellt werden, wie im folgenden Beispiel:
NetTcpBinding binding = new NetTcpBinding();
Uri baseAddress = new Uri("net.tcp://localhost:8000/wcfserver");
using (ServiceHost serviceHost = new ServiceHost(typeof(WCFServer), baseAddress))
{
serviceHost.AddServiceEndpoint(typeof(IWCFServer), binding, baseAddress);
serviceHost.Open();
Console.WriteLine($"The WCF server is ready at {baseAddress}.");
Console.WriteLine("Press <ENTER> to terminate service...");
Console.WriteLine();
Console.ReadLine();
}
Hinweis
TCP wird in beiden Beispielen verwendet, um sie so ähnlich wie möglich zu halten. Beispiele für die Nutzung von HTTP finden Sie in den Szenario-Durchläufen weiter unten in diesem Thema.
Es gibt viele Möglichkeiten zum Konfigurieren und Hosten von WCF-Diensten. Dies ist nur ein Beispiel, das als "selbst gehostet" bezeichnet wird. Weitere Informationen finden Sie in den folgenden Themen:
Clientimplementierung im Vergleich
Erstellen eines Clients in .NET Remoting
Sobald ein .NET Remoting-Serverobjekt verfügbar gemacht wurde, kann es von Clients genutzt werden, wie im folgenden Beispiel:
TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel, ensureSecurity : true);
RemotingServer server = (RemotingServer)Activator.GetObject(
typeof(RemotingServer),
"tcp://localhost:8080/RemotingServer");
RemotingCustomer customer = server.GetCustomer(42);
Console.WriteLine($"Customer {customer.FirstName} {customer.LastName} received.");
Die von Activator.GetObject() zurückgegebene RemotingServer-Instanz wird als "transparenter Proxy" bezeichnet. Es implementiert die öffentliche API für den RemotingServer-Typ auf dem Client, aber alle Methoden rufen das Serverobjekt auf, das in einem anderen Prozess oder Computer ausgeführt wird.
Erstellen eines Clients in WCF
Der entsprechende Schritt in WCF umfasst die Verwendung einer Kanalfactory zur expliziten Erstellung des Proxys. Wie Remoting kann das Proxyobjekt verwendet werden, um Vorgänge auf dem Server aufzurufen, wie im folgenden Beispiel:
NetTcpBinding binding = new NetTcpBinding();
String url = "net.tcp://localhost:8000/wcfserver";
EndpointAddress address = new EndpointAddress(url);
ChannelFactory<IWCFServer> channelFactory =
new ChannelFactory<IWCFServer>(binding, address);
IWCFServer server = channelFactory.CreateChannel();
Customer customer = server.GetCustomer(42);
Console.WriteLine($" Customer {customer.FirstName} {customer.LastName} received.");
Dieses Beispiel zeigt die Programmierung auf Kanalebene, da sie dem Remoting-Beispiel am ähnlichsten ist. Außerdem ist der Ansatz "Dienstreferenz hinzufügen" in Visual Studio verfügbar, der Code generiert, um die Clientprogrammierung zu vereinfachen. Weitere Informationen finden Sie in den folgenden Themen:
Serialisierungsverwendung
Sowohl .NET Remoting als auch WCF verwenden serialisierung zum Senden von Objekten zwischen Client und Server, unterscheiden sich jedoch auf folgende wichtige Weise:
Sie verwenden verschiedene Serialisierer und Konventionen, um anzugeben, was serialisiert werden soll.
.NET Remoting unterstützt die Serialisierung "nach Referenz", die den Methoden- oder Eigenschaftenzugriff auf eine Ebene zum Ausführen von Code auf der anderen Ebene ermöglicht, was über Sicherheitsgrenzen hinweg erfolgt. Diese Funktion macht Sicherheitsrisiken verfügbar und ist einer der Hauptgründe dafür, dass Remoting-Endpunkte nie für nicht vertrauenswürdige Clients verfügbar gemacht werden sollten.
Die von Remoting verwendete Serialisierung ist opt-out (man schließt explizit aus, was nicht serialisiert werden soll), und die WCF-Serialisierung ist opt-in (man markiert explizit, welche Mitglieder serialisiert werden sollen).
Serialisierung in .NET Remoting
.NET Remoting unterstützt zwei Möglichkeiten zum Serialisieren und Deserialisieren von Objekten zwischen dem Client und dem Server:
Nach Wert – die Werte des Objekts werden über Ebenengrenzen serialisiert, und eine neue Instanz dieses Objekts wird auf der anderen Ebene erstellt. Alle Aufrufe von Methoden oder Eigenschaften dieser neuen Instanz werden nur lokal ausgeführt und wirken sich nicht auf das ursprüngliche Objekt oder die ursprüngliche Ebene aus.
Durch Verweis: Ein spezieller Objektverweis wird über Ebenengrenzen hinweg serialisiert. Wenn eine Ebene mit Methoden oder Eigenschaften dieses Objekts interagiert, kommuniziert sie wieder mit dem ursprünglichen Objekt auf der ursprünglichen Ebene. Als-Verweis-Objekte können in beide Richtungen übertragen werden – vom Server an den Client oder vom Client an den Server.
Als-Wert-Typen werden in Remoting mit dem [Serializable]-Attribut gekennzeichnet oder implementieren "ISerializable", wie im folgenden Beispiel gezeigt:
[Serializable]
public class RemotingCustomer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int CustomerId { get; set; }
}
Nachverweistypen werden von der MarshalByRefObject-Klasse abgeleitet, wie im folgenden Beispiel:
public class RemotingCustomerReference : MarshalByRefObject
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int CustomerId { get; set; }
}
Es ist äußerst wichtig, die Auswirkungen der By-Reference-Objekte von Remoting zu verstehen. Wenn eine Ebene (Client oder Server) ein By-Reference-Objekt an die andere Ebene sendet, werden alle Methodenaufrufe wieder auf der Ebene ausgeführt, die das Objekt besitzt. Beispielsweise wird Code auf dem Server ausgeführt, wenn ein Client Methoden auf einem vom Server zurückgegebenen By-Reference-Objekt aufruft. Ebenso führt ein Server, der Methoden für ein vom Client bereitgestelltes By-Reference-Objekt aufruft, Code wieder auf dem Client aus. Aus diesem Grund wird die Verwendung von .NET Remoting nur in voll vertrauenswürdigen Umgebungen empfohlen. Wenn Sie einen öffentlichen .NET Remoting-Endpunkt für nicht vertrauenswürdige Clients verfügbar machen, wird ein Remotingserver anfällig für Angriffe.
Serialisierung in WCF
WCF unterstützt nur die Serialisierung nach Wert. Die am häufigsten verwendete Methode zum Definieren eines Typs, der zwischen Client und Server ausgetauscht werden soll, ist wie im folgenden Beispiel:
[DataContract]
public class WCFCustomer
{
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
[DataMember]
public int CustomerId { get; set; }
}
Das Attribut [DataContract] identifiziert diesen Typ als einen, der serialisiert und zwischen Client und Server deserialisiert werden kann. Das Attribut [DataMember] identifiziert die einzelnen Eigenschaften oder Felder, die serialisiert werden sollen.
Wenn WCF ein Objekt über Ebenen sendet, serialisiert es nur die Werte und erstellt eine neue Instanz des Objekts auf der anderen Ebene. Alle Interaktionen mit den Werten des Objekts treten nur lokal auf – sie kommunizieren nicht mit der anderen Ebene, wie .NET Remoting by-Reference-Objekte. Weitere Informationen finden Sie unter Serialisierung und Deserialisierung.
Funktionen für die Ausnahmebehandlung
Ausnahmen in .NET Remoting
Ausnahmen, die von einem Remotingserver ausgelöst werden, werden serialisiert, an den Client gesendet und lokal auf dem Client ausgelöst, wie jede andere Ausnahme. Benutzerdefinierte Ausnahmen können durch das Erstellen von Unterklassen des Exception-Typs erstellt und mit [Serializable] gekennzeichnet werden. Die meisten Framework-Ausnahmen sind bereits auf diese Weise markiert, sodass die meisten vom Server ausgelöst, serialisiert und erneut auf dem Client ausgelöst werden können. Obwohl dieses Design während der Entwicklung praktisch ist, können serverseitige Informationen versehentlich dem Client offengelegt werden. Dies ist einer von vielen Gründen, warum Remoting nur in voll vertrauenswürdigen Umgebungen verwendet werden sollte.
Ausnahmen und Fehler in WCF
WCF lässt nicht zu, dass beliebige Ausnahmetypen vom Server an den Client zurückgegeben werden, da sie zu versehentlicher Offenlegung von Informationen führen könnten. Wenn ein Dienstvorgang eine unerwartete Ausnahme ausgelöst wird, führt dies dazu, dass auf dem Client eine allgemeine FaultException ausgelöst wird. Diese Ausnahme enthält keine Informationen darüber, warum oder wo das Problem aufgetreten ist, und für einige Anwendungen ist dies ausreichend. Anwendungen, die umfassendere Fehlerinformationen an den Client übermitteln müssen, führen dazu einen Fehlervertrag aus.
Erstellen Sie dazu zuerst einen [DataContract]-Typ, um die Fehlerinformationen zu übermitteln.
[DataContract]
public class CustomerServiceFault
{
[DataMember]
public string ErrorMessage { get; set; }
[DataMember]
public int CustomerId {get;set;}
}
Geben Sie den Fehlervertrag an, der für jeden Dienstvorgang verwendet werden soll.
[ServiceContract]
public interface IWCFServer
{
[OperationContract]
[FaultContract(typeof(CustomerServiceFault))]
Customer GetCustomer(int customerId);
}
Der Server meldet Fehlerbedingungen durch Auslösen einer FaultException.
throw new FaultException<CustomerServiceFault>(
new CustomerServiceFault() {
CustomerId = customerId,
ErrorMessage = "Illegal customer Id"
});
Und wenn der Client eine Anforderung an den Server sendet, kann er Fehler als normale Ausnahmen erfassen.
try
{
Customer customer = server.GetCustomer(-1);
}
catch (FaultException<CustomerServiceFault> fault)
{
Console.WriteLine($"Fault received: {fault.Detail.ErrorMessage}");
}
Weitere Informationen zu Fehlverträgen finden Sie unter FaultException.
Sicherheitsüberlegungen
Sicherheit in .NET Remoting
Einige .NET Remoting-Kanäle unterstützen Sicherheitsfeatures wie Authentifizierung und Verschlüsselung auf kanalebene (IPC und TCP). Der HTTP-Kanal basiert auf Internetinformationsdienste (IIS) sowohl für die Authentifizierung als auch für die Verschlüsselung. Trotz dieser Unterstützung sollten Sie .NET Remoting für ein unsicheres Kommunikationsprotokoll in Betracht ziehen und es nur in voll vertrauenswürdigen Umgebungen verwenden. Machen Sie niemals einen öffentlichen Remoting-Endpunkt für das Internet oder nicht vertrauenswürdige Clients verfügbar.
Sicherheit in WCF
WCF wurde unter Berücksichtigung der Sicherheit entwickelt, teilweise um die Arten von Sicherheitsrisiken zu beheben, die in .NET Remoting gefunden wurden. WCF bietet Sicherheit auf Transport- und Nachrichtenebene und bietet viele Optionen für Authentifizierung, Autorisierung, Verschlüsselung usw. Weitere Informationen finden Sie in den folgenden Themen:
Migrieren zu WCF
Warum von Remoting zu WCF migrieren?
.NET Remoting ist ein Legacyprodukt. Wie in .NET Remoting beschrieben, wird es als Legacyprodukt betrachtet und wird für die neue Entwicklung nicht empfohlen. WCF- oder ASP.NET-Web-API wird für neue und vorhandene Anwendungen empfohlen.
WCF verwendet plattformübergreifende Standards. WCF wurde unter Berücksichtigung der plattformübergreifenden Interoperabilität entwickelt und unterstützt viele Branchenstandards (SOAP, WS-Security, WS-Trust usw.). Ein WCF-Dienst kann mit Clients zusammenarbeiten, die auf anderen Betriebssystemen als Windows ausgeführt werden. Remoting wurde hauptsächlich für Umgebungen entwickelt, in denen sowohl die Server- als auch die Clientanwendungen mit .NET Framework auf einem Windows-Betriebssystem ausgeführt werden.
WCF verfügt über integrierte Sicherheit. WCF wurde unter Berücksichtigung der Sicherheit entwickelt und bietet viele Optionen für Authentifizierung, Sicherheit auf Transportebene, Sicherheit auf Nachrichtenebene usw. Remoting wurde entwickelt, um die Interoperabilität von Anwendungen zu vereinfachen, aber nicht so konzipiert, dass sie in nicht vertrauenswürdigen Umgebungen sicher sind. WCF wurde für die Arbeit in vertrauenswürdigen und nicht vertrauenswürdigen Umgebungen entwickelt.
Migrationsempfehlungen
Es folgen die empfohlenen Schritte zum Migrieren von .NET Remoting zu WCF:
Erstellen Sie den Servicevertrag. Definieren Sie die Dienstschnittstellentypen, und markieren Sie sie durch das Attribut "[ServiceContract]". Markieren Sie alle Methoden, die Clients mit [OperationContract] aufrufen dürfen.
Erstellen Sie den Datenvertrag. Definieren Sie die Datentypen, die zwischen Server und Client ausgetauscht werden, und markieren Sie sie mit dem Attribut [DataContract]. Markieren Sie alle Felder und Eigenschaften, die der Client mit [DataMember] verwenden darf.
Erstellen Sie den Fehlervertrag (optional). Erstellen Sie die Typen, die zwischen Server und Client ausgetauscht werden, wenn Fehler auftreten. Markieren Sie diese Typen mit [DataContract] und [DataMember], um sie serialisierbar zu machen. Für alle Dienstvorgänge, die Sie mit [OperationContract] markiert haben, markieren Sie sie auch mit [FaultContract], um anzugeben, welche Fehler sie zurückgeben können.
Konfigurieren und Hosten des Diensts. Nachdem der Dienstvertrag erstellt wurde, besteht der nächste Schritt darin, eine Bindung zu konfigurieren, um den Dienst an einem Endpunkt verfügbar zu machen. Weitere Informationen finden Sie unter Endpunkte: Adressen, Bindungen und Verträge.
Nachdem eine Remoting-Anwendung zu WCF migriert wurde, ist es dennoch wichtig, Abhängigkeiten von .NET Remoting zu entfernen. Dadurch wird sichergestellt, dass alle Remoting-Sicherheitsrisiken aus der Anwendung entfernt werden. Diese Schritte umfassen Folgendes:
Die Verwendung von MarshalByRefObject wird eingestellt. Der MarshalByRefObject-Typ ist nur für Remoting vorhanden und wird nicht von WCF verwendet. Alle Anwendungstypen, die die Unterklasse MarshalByRefObject verwenden, sollten entfernt oder geändert werden.
Beenden Sie die Verwendung von [Serializable] und ISerializable. Das [Serializable]-Attribut und die ISerializable-Schnittstelle wurden ursprünglich für die Serialisierung von Typen in vertrauenswürdigen Umgebungen entwickelt, und sie werden von Remoting verwendet. Die WCF-Serialisierung basiert auf Typen, die mit [DataContract] und [DataMember] gekennzeichnet werden. Von einer Anwendung verwendete Datentypen sollten so geändert werden, dass [DataContract] genutzt wird und ISerializable oder [Serializable] nicht verwendet werden.
Migrationsszenarien
Lassen Sie uns nun betrachten, wie Sie die folgenden allgemeinen Remotingszenarien in WCF umsetzen können.
Server gibt ein Objekt als Wert an den Client zurück
Der Server gibt ein Objekt als Referenz an den Client zurück.
Client sendet ein Objekt als Wert an den Server
Hinweis
Das Senden eines Objekts nach Verweis vom Client an den Server ist in WCF nicht zulässig.
Gehen Sie beim Lesen dieser Szenarien von unseren Basisschnittstellen für .NET Remoting wie im folgenden Beispiel aus. Die .NET Remoting-Implementierung ist hier nicht wichtig, da wir nur veranschaulichen möchten, wie WCF zum Implementieren entsprechender Funktionen verwendet wird.
public class RemotingServer : MarshalByRefObject
{
// Demonstrates server returning object by-value
public Customer GetCustomer(int customerId) {…}
// Demonstrates server returning object by-reference
public CustomerReference GetCustomerReference(int customerId) {…}
// Demonstrates client passing object to server by-value
public bool UpdateCustomer(Customer customer) {…}
}
Szenario 1: Der Dienst gibt ein Objekt nach Wert zurück.
In diesem Szenario wird ein Server veranschaulicht, der ein Objekt nach Wert an den Client zurückgibt. WCF gibt immer Objekte vom Server nach Wert zurück, daher beschreiben die folgenden Schritte einfach, wie ein normaler WCF-Dienst erstellt wird.
Definieren Sie zunächst eine öffentliche Schnittstelle für den WCF-Dienst, und markieren Sie sie mit dem [ServiceContract]-Attribut. [OperationContract] wird verwendet, um die serverseitigen Methoden zu identifizieren, die unser Client aufruft.
[ServiceContract] public interface ICustomerService { [OperationContract] Customer GetCustomer(int customerId); [OperationContract] bool UpdateCustomer(Customer customer); }Der nächste Schritt besteht darin, den Datenvertrag für diesen Dienst zu erstellen. Dazu erstellen wir Klassen (keine Schnittstellen), die mit dem [DataContract]-Attribut gekennzeichnet sind. Die einzelnen Eigenschaften oder Felder, die für Client und Server sichtbar sein sollen, sind mit [DataMember] gekennzeichnet. Wenn abgeleitete Typen zulässig sein sollen, müssen wir das [KnownType]-Attribut verwenden, um sie zu identifizieren. Die einzigen Typen, die WCF für die Serialisierung oder Deserialisierung dieses Dienstes zulässt, sind diejenigen in der Dienstschnittstelle und die sogenannten „Known Types“. Der Versuch, einen anderen Typ auszutauschen, der nicht in dieser Liste enthalten ist, wird abgelehnt.
[DataContract] [KnownType(typeof(PremiumCustomer))] public class Customer { [DataMember] public string FirstName { get; set; } [DataMember] public string LastName { get; set; } [DataMember] public int CustomerId { get; set; } } [DataContract] public class PremiumCustomer : Customer { [DataMember] public int AccountId { get; set; } }Als Nächstes stellen wir die Implementierung für die Dienstschnittstelle bereit.
public class CustomerService : ICustomerService { public Customer GetCustomer(int customerId) { // read from database } public bool UpdateCustomer(Customer customer) { // write to database } }Zum Ausführen des WCF-Diensts müssen wir einen Endpunkt deklarieren, der diese Dienstschnittstelle unter Verwendung einer bestimmten WCF-Bindung an einer bestimmten URL verfügbar macht. Dies geschieht in der Regel durch Hinzufügen der folgenden Abschnitte zur web.config Datei des Serverprojekts.
<configuration> <system.serviceModel> <services> <service name="Server.CustomerService"> <endpoint address="http://localhost:8083/CustomerService" binding="basicHttpBinding" contract="Shared.ICustomerService" /> </service> </services> </system.serviceModel> </configuration>Der WCF-Dienst kann dann mit dem folgenden Code gestartet werden:
ServiceHost customerServiceHost = new ServiceHost(typeof(CustomerService)); customerServiceHost.Open();Wenn dieser ServiceHost gestartet wird, wird die web.config Datei verwendet, um den richtigen Vertrag, die Bindung und den Endpunkt einzurichten. Weitere Informationen zu Konfigurationsdateien finden Sie unter Konfigurieren von Diensten mithilfe von Konfigurationsdateien. Diese Art des Startens des Servers wird als Selbsthosting bezeichnet. Weitere Informationen zu anderen Auswahlmöglichkeiten für das Hosting von WCF-Diensten finden Sie unter Hostingdienste.
Die Datei „app.config“ des Clientprojekts muss übereinstimmende Bindungsinformationen für den Dienstendpunkt deklarieren. Die einfachste Möglichkeit hierzu in Visual Studio ist die Verwendung von "Dienstverweis hinzufügen", wodurch die app.config Datei automatisch aktualisiert wird. Alternativ können diese Änderungen manuell hinzugefügt werden.
<configuration> <system.serviceModel> <client> <endpoint name="customerservice" address="http://localhost:8083/CustomerService" binding="basicHttpBinding" contract="Shared.ICustomerService"/> </client> </system.serviceModel> </configuration>Weitere Informationen zur Verwendung von Add Service Reference finden Sie unter How to: Add, Update, or Remove a Service Reference.
Jetzt können wir den WCF-Dienst vom Client aufrufen. Dazu erstellen wir eine Kanalfactory für diesen Dienst, fragen ihn nach einem Kanal und rufen die gewünschte Methode in diesem Kanal direkt auf. Dies ist möglich, da der Kanal die Schnittstelle des Diensts implementiert und die zugrunde liegende Anforderungs-/Antwortlogik für uns verarbeitet. Der Rückgabewert dieses Methodenaufrufs ist die deserialisierte Kopie der Antwort des Servers.
ChannelFactory<ICustomerService> factory = new ChannelFactory<ICustomerService>("customerservice"); ICustomerService service = factory.CreateChannel(); Customer customer = service.GetCustomer(42); Console.WriteLine($" Customer {customer.FirstName} {customer.LastName} received.");
Objekte, die WCF vom Server an den Client zurückgibt, werden immer als Werte übermittelt. Die Objekte sind deserialisierte Kopien der vom Server gesendeten Daten. Der Client kann Methoden für diese lokalen Kopien aufrufen, ohne dass der Servercode durch Rückrufe aufgerufen wird.
Szenario 2: Server gibt ein Objekt nach Verweis zurück.
In diesem Szenario wird der Server veranschaulicht, der dem Client ein Objekt anhand eines Verweises bereitstellt. In .NET Remoting wird dies automatisch für jeden Typ gehandhabt, der von MarshalByRefObject abgeleitet ist und welcher durch Verweis serialisiert wird. Ein Beispiel für dieses Szenario besteht darin, mehreren Clients zu gestatten, unabhängige, sitzungsbasierte, serverseitige Objekte zu verwalten. Wie bereits erwähnt, sind objekte, die von einem WCF-Dienst zurückgegeben werden, immer nach Wert, daher gibt es keine direkte Entsprechung eines By-Reference-Objekts, aber es ist möglich, etwas ähnliches wie die By-Reference-Semantik mithilfe eines EndpointAddress10 Objekts zu erreichen. Es handelt sich um ein serialisierbares Per-Wert-Objekt, das vom Client dazu verwendet werden kann, ein sitzungsbasiertes Per-Verweis-Objekt auf dem Server abzurufen. Dadurch wird das Szenario ermöglicht, über mehrere Clients mit unabhängigen, sitzungsbasierten, serverseitigen Objekten zu verfügen.
Zunächst müssen wir einen WCF-Dienstvertrag definieren, der dem Sitzungsobjekt selbst entspricht.
[ServiceContract(SessionMode = SessionMode.Allowed)] public interface ISessionBoundObject { [OperationContract] string GetCurrentValue(); [OperationContract] void SetCurrentValue(string value); }Tipp
Beachten Sie, dass das sitzungsbasierte Objekt mit [ServiceContract] markiert ist, es handelt sich also um eine normale WCF-Dienstschnittstelle. Durch Festlegen der SessionMode-Eigenschaft wird angegeben, dass es sich um einen sitzungsbasierten Dienst handelt. In WCF ist eine Sitzung eine Methode zum Korrelieren mehrerer Nachrichten, die zwischen zwei Endpunkten gesendet werden. Dies bedeutet, dass eine Sitzung zwischen dem Client und dem Server hergestellt wird, sobald ein Client eine Verbindung mit diesem Dienst abruft. Der Client verwendet eine einzelne eindeutige Instanz des serverseitigen Objekts für alle Interaktionen innerhalb dieser einzelnen Sitzung.
Als Nächstes müssen wir die Implementierung dieser Dienstschnittstelle bereitstellen. Indem sie mit [ServiceBehavior] gekennzeichnet und die InstanzContextMode festgelegt wird, teilen wir WCF mit, dass für jede Sitzung eine eindeutige Instanz dieses Typs verwendet werden soll.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] public class MySessionBoundObject : ISessionBoundObject { private string _value; public string GetCurrentValue() { return _value; } public void SetCurrentValue(string val) { _value = val; } }Nun benötigen wir eine Möglichkeit, eine Instanz dieses sitzungsbasierten Objekts abzurufen. Dazu erstellen wir eine weitere WCF-Dienstschnittstelle, die ein EndpointAddress10-Objekt zurückgibt. Dies ist eine serialisierbare Form eines Endpunkts, die vom Server dazu verwendet werden kann, ein sitzungsbasiertes Objekt zu erstellen.
[ServiceContract] public interface ISessionBoundFactory { [OperationContract] EndpointAddress10 GetInstanceAddress(); }Und wir implementieren diesen WCF-Dienst:
public class SessionBoundFactory : ISessionBoundFactory { public static ChannelFactory<ISessionBoundObject> _factory = new ChannelFactory<ISessionBoundObject>("sessionbound"); public SessionBoundFactory() { } public EndpointAddress10 GetInstanceAddress() { IClientChannel channel = (IClientChannel)_factory.CreateChannel(); return EndpointAddress10.FromEndpointAddress(channel.RemoteAddress); } }Diese Implementierung verwaltet eine Singleton-Kanalfactory, um sitzungsbasierte Objekte zu erstellen. Wenn GetInstanceAddress() aufgerufen wird, wird ein Kanal erstellt und ein EndpointAddress10 -Objekt erstellt, das effektiv auf die Remoteadresse verweist, die diesem Kanal zugeordnet ist. EndpointAddress10 ist einfach ein Datentyp, der nach Wert an den Client zurückgegeben werden kann.
Wir müssen die Konfigurationsdatei des Servers ändern, indem wir die folgenden beiden Schritte ausführen, wie im folgenden Beispiel gezeigt:
Deklarieren Sie einen <client>-Abschnitt, der den Endpunkt für das sitzungsbasierte Objekt beschreibt. Dies ist erforderlich, da der Server auch in dieser Situation als Client fungiert.
Deklarieren Sie Endpunkte für die Factory und das sitzungsbasierte Objekt. Dies ist erforderlich, damit der Client mit den Dienstendpunkten kommunizieren kann, um EndpointAddress10 abzurufen und den sitzungsbasierten Kanal zu erstellen.
<configuration> <system.serviceModel> <client> <endpoint name="sessionbound" address="net.tcp://localhost:8081/SessionBoundObject" binding="netTcpBinding" contract="Shared.ISessionBoundObject"/> </client> <services> <service name="Server.CustomerService"> <endpoint address="http://localhost:8083/CustomerService" binding="basicHttpBinding" contract="Shared.ICustomerService" /> </service> <service name="Server.MySessionBoundObject"> <endpoint address="net.tcp://localhost:8081/SessionBoundObject" binding="netTcpBinding" contract="Shared.ISessionBoundObject" /> </service> <service name="Server.SessionBoundFactory"> <endpoint address="net.tcp://localhost:8081/SessionBoundFactory" binding="netTcpBinding" contract="Shared.ISessionBoundFactory" /> </service> </services> </system.serviceModel> </configuration>Und dann können wir diese Dienste starten:
ServiceHost factoryHost = new ServiceHost(typeof(SessionBoundFactory)); factoryHost.Open(); ServiceHost sessionHost = new ServiceHost(typeof(MySessionBoundObject)); sessionHost.Open();Wir konfigurieren den Client, indem wir dieselben Endpunkte in der app.config-Datei des Projekts deklarieren.
<configuration> <system.serviceModel> <client> <endpoint name="customerservice" address="http://localhost:8083/CustomerService" binding="basicHttpBinding" contract="Shared.ICustomerService"/> <endpoint name="sessionbound" address="net.tcp://localhost:8081/SessionBoundObject" binding="netTcpBinding" contract="Shared.ISessionBoundObject"/> <endpoint name="factory" address="net.tcp://localhost:8081/SessionBoundFactory" binding="netTcpBinding" contract="Shared.ISessionBoundFactory"/> </client> </system.serviceModel> </configuration>Zum Erstellen und Nutzen dieses sitzungsbasierten Objekts muss der Client die folgenden Schritte ausführen:
Erstellen Sie einen Kanal zum ISessionBoundFactory-Dienst.
Verwenden Sie diesen Kanal, um diesen Dienst aufzurufen, um eine EndpointAddress10 abzurufen.
Verwenden Sie EndpointAddress10, um einen Kanal zu erstellen, mit dem Sie ein objekt mit Sitzung abrufen können.
Interaktion mit dem sitzungsbasierten Objekt, um zu veranschaulichen, dass auch bei mehreren Aufrufen dieselbe Instanz verwendet wird.
ChannelFactory<ISessionBoundFactory> channelFactory = new ChannelFactory<ISessionBoundFactory>("factory"); ISessionBoundFactory sessionFactory = channelFactory.CreateChannel(); EndpointAddress10 address1 = sessionFactory.GetInstanceAddress(); EndpointAddress10 address2 = sessionFactory.GetInstanceAddress(); ChannelFactory<ISessionBoundObject> sessionObjectFactory1 = new ChannelFactory<ISessionBoundObject>(new NetTcpBinding(), address1.ToEndpointAddress()); ChannelFactory<ISessionBoundObject> sessionObjectFactory2 = new ChannelFactory<ISessionBoundObject>(new NetTcpBinding(), address2.ToEndpointAddress()); ISessionBoundObject sessionInstance1 = sessionObjectFactory1.CreateChannel(); ISessionBoundObject sessionInstance2 = sessionObjectFactory2.CreateChannel(); sessionInstance1.SetCurrentValue("Hello"); sessionInstance2.SetCurrentValue("World"); if (sessionInstance1.GetCurrentValue() == "Hello" && sessionInstance2.GetCurrentValue() == "World") { Console.WriteLine("sessionful server object works as expected"); }
WCF gibt immer Objekte nach Wert zurück, aber es ist möglich, das Äquivalent von By-Reference-Semantik mithilfe von EndpointAddress10 zu unterstützen. Dies ermöglicht dem Client, eine sitzungsbasierte WCF-Dienstinstanz anzufordern, um anschließend mit dieser wie mit jedem anderen WCF-Dienst zu interagieren.
Szenario 3: Client sendet Server eine By-Value Instanz
In diesem Szenario wird veranschaulicht, dass der Client eine nicht primitive Objektinstanz nach Wert an den Server sendet. Da WCF nur Objekte nach Wert sendet, veranschaulicht dieses Szenario die normale WCF-Verwendung.
Verwenden Sie denselben WCF-Dienst aus Szenario 1.
Verwenden Sie den Client, um ein neues Nachwertobjekt (Customer) zu erstellen, einen Kanal für die Kommunikation mit dem ICustomerService-Dienst zu erstellen und das Objekt an das Objekt zu senden.
ChannelFactory<ICustomerService> factory = new ChannelFactory<ICustomerService>("customerservice"); ICustomerService service = factory.CreateChannel(); PremiumCustomer customer = new PremiumCustomer { FirstName = "Bob", LastName = "Jones", CustomerId = 43, AccountId = 99}; bool success = service.UpdateCustomer(customer); Console.WriteLine($" Server returned {success}.");Das Kundenobjekt wird serialisiert und an den Server gesendet, auf dem es in eine neue Kopie dieses Objekts deserialisiert wird.
Hinweis
Dieser Code veranschaulicht auch das Senden eines abgeleiteten Typs (PremiumCustomer). Die Dienstschnittstelle erwartet ein Customer-Objekt, aber das [KnownType]-Attribut der Customer-Klasse hat angegeben, dass PremiumCustomer ebenfalls zulässig war. WCF wird jeden Versuch, einen anderen Typ über diese Dienstschnittstelle zu serialisieren oder zu deserialisieren, fehlschlagen lassen.
Der normale WCF-Datenaustausch erfolgt nach Wert. Dadurch wird sichergestellt, dass das Aufrufen von Methoden für eines dieser Datenobjekte nur lokal ausgeführt wird – code wird nicht auf der anderen Ebene aufgerufen. Es ist zwar möglich, Objekte vom Typ „Durch Verweis“ vom Server zurückzugeben, der Client kann jedoch kein Objekt vom Typ „Durch Verweis“ an den Server übergeben. Ein Szenario, das eine Unterhaltung zwischen Client und Server erfordert, kann in WCF mithilfe eines Duplexdiensts erreicht werden. Weitere Informationen finden Sie unter Duplexdienste.
Zusammenfassung
.NET Remoting ist ein Kommunikationsframework, das nur in voll vertrauenswürdigen Umgebungen verwendet werden soll. Es handelt sich um ein Legacyprodukt, das nur aus Gründen der Abwärtskompatibilität unterstützt wird. Es sollte nicht zum Erstellen neuer Anwendungen verwendet werden. Umgekehrt wurde WCF unter Berücksichtigung der Sicherheit entwickelt und wird für neue und vorhandene Anwendungen empfohlen. Microsoft empfiehlt, vorhandene Remotinganwendungen stattdessen zur Verwendung von WCF oder ASP.NET Web-API zu migrieren.