Transport: UDP

Das Beispiel zum UDB-Transport veranschaulicht, wie UDP-Unicast und -Multicast als benutzerdefinierter WCF-Transport implementiert werden können. In dem Beispiel wird die empfohlene Vorgehensweise zum Erstellen eines benutzerdefinierten Transports in WCF anhand des Kanalframeworks und der empfohlenen Vorgehensweisen für WCF beschrieben. Die Schritte zum Erstellen eines benutzerdefinierten Transports lauten wie folgt:

  1. Legen Sie fest, welche Nachrichtenaustauschmuster für den Kanal (IOutputChannel, IInputChannel, IDuplexChannel, IRequestChannel oder IReplyChannel) von ChannelFactory und ChannelListener unterstützt werden sollen. Dann entscheiden Sie sich, ob Sie die sitzungsbasierten Variationen dieser Schnittstellen unterstützen.

  2. Erstellen Sie eine Kanalfactory und einen Kanallistener, die Ihr Nachrichtenaustauschmuster unterstützen.

  3. Stellen Sie sicher, dass alle netzwerkspezifischen Ausnahmen zu der entsprechenden abgeleiteten Klasse von CommunicationException normalisiert werden.

  4. Fügen Sie ein Element vom Typ <binding> hinzu, das den benutzerdefinierten Transport einem Kanalstapel hinzufügt. Weitere Informationen finden Sie unter Hinzufügen eines Bindungselements.

  5. Fügen Sie einen Bindungselementerweiterungs-Abschnitt hinzu, um das neue Bindungselement für das Konfigurationssystem verfügbar zu machen.

  6. Fügen Sie Metadatenerweiterungen hinzu, um anderen Endpunkten Funktionen mitzuteilen.

  7. Fügen Sie eine Bindung hinzu, die einen Stapel mit Bindungselementen entsprechend einem genau definierten Profil vorkonfiguriert. Weitere Informationen finden Sie unter Hinzufügen einer Standardbindung.

  8. Fügen Sie einen Bindungsabschnitt und ein Bindungskonfigurationselement hinzu, um die Bindung für das Konfigurationssystem verfügbar zu machen. Weitere Informationen finden Sie unter Hinzufügen von Konfigurationsunterstützung.

Nachrichtenaustauschmuster

Der erste Schritt beim Schreiben eines benutzerdefinierten Transports besteht darin zu entscheiden, welche Nachrichtenaustauschmuster für den Transport erforderlich sind. Es stehen drei Nachrichtenaustauschmuster zur Auswahl:

  • Datagramm (IInputChannel/IOutputChannel)

    Bei Verwendung eines Datagramm-Nachrichtenaustauschmusters sendet ein Client eine Nachricht mit einem "fire and forget"-Austausch. Ein "fire and forget"-Austausch erfordert eine Out-of-Band-Bestätigung für die erfolgreiche Zustellung. Die Nachricht könnte unterwegs verloren gehen und den Dienst nicht erreichen. Wenn der Sendevorgang auf der Clientseite erfolgreich abgeschlossen wird, stellt dies keine Garantie dar, dass der Remoteendpunkt die Nachricht erhalten hat. Das Datagramm ist ein wesentlicher Baustein für den Nachrichtenaustausch, da Sie eigene Protokolle damit erstellen können, einschließlich zuverlässiger Protokolle und sicherer Protokolle. Clientdatagrammkanäle implementieren die IOutputChannel-Schnittstelle, und Dienstdatagrammkanäle implementieren die IInputChannel-Schnittstelle.

  • Anforderung-Antwort (IRequestChannel/IReplyChannel)

    In diesem Nachrichtenaustauschmuster wird eine Nachricht gesendet, und eine Antwort wird empfangen. Das Muster besteht aus Anforderungs-Antwort-Paaren. Beispiele für Anforderungs-Antwort-Aufrufe sind Remoteprozeduraufrufe (RPC) und Browser-GET-Anforderungen. Dieses Muster wird auch als Halbduplex bezeichnet. In diesem Nachrichtenaustauschmuster implementieren Clientkanäle IRequestChannel, und Dienstkanäle implementieren IReplyChannel.

  • Duplex (IDuplexChannel)

    Das Duplex-Nachrichtenaustauschmuster ermöglicht, dass eine willkürliche Anzahl von Nachrichten von einem Client gesendet und in beliebiger Reihenfolge empfangen wird. Das Duplex-Nachrichtenaustauschmuster ist mit einem Telefongespräch vergleichbar, bei dem jedes gesprochene Wort einer Nachricht entspricht. Da beide Teilnehmer in diesem Nachrichtenaustauschmuster senden und empfangen können, ist die vom Client und von den Dienstkanälen implementierte Schnittstelle IDuplexChannel.

Jedes dieser Nachrichtenaustauschmuster kann außerdem Sitzungen unterstützen. Die neue Funktion von sitzungsfähigen Kanälen besteht darin, dass alle in einem Kanal gesendeten und empfangenen Nachrichten korreliert werden. Das Anforderungs-Antwort-Muster ist eine eigenständige, aus zwei Nachrichten bestehende Sitzung, da die Anforderung und die Antwort korreliert werden. Demgegenüber impliziert das Anforderungs-Antwort-Muster, das Sitzungen unterstützt, dass alle Anforderungs-/Antwort-Paare in diesem Kanal miteinander korreliert werden. Dadurch ergeben sich sechs Nachrichtenaustauschmuster zur Auswahl: Datagramm, Anforderung-Antwort, Duplex, Datagramm mit Sitzungen, Anforderung-Antwort mit Sitzungen und Duplex mit Sitzungen.

Hinweis

Für den UDP-Transport wird nur das Nachrichtenaustauschmuster Datagramm unterstützt, da UDP grundsätzlich ein "fire and forget"-Protokoll ist.

Der ICommunicationObject- und der WCF-Objektlebenszyklus

WCF hat einen allgemeinen Zustandsautomaten, der zum Verwalten des Legenszyklus von Objekten wie IChannel, IChannelFactory und IChannelListener verwendet wird, die der Kommunikation dienen. Es gibt fünf Zustände, in denen diese Kommunikationsobjekte vorhanden sein können. Die Zustände werden durch die CommunicationState-Enumeration dargestellt und lauten wie folgt:

  • Created: Dies ist der Zustand eines ICommunicationObject, wenn es zuerst instanziiert wird. In diesem Zustand tritt keine Eingabe/Ausgabe (E/A) auf.

  • Opening: Das Objekt geht zu diesem Zustand über, wenn Open aufgerufen wird. An diesem Punkt werden Eigenschaften unveränderlich gemacht, und Eingabe/Ausgabe kann beginnen. Dieser Übergang ist nur vom Created-Zustand aus gültig.

  • Opened: Das Objekt geht zu diesem Zustand über, wenn der geöffnete Prozess abgeschlossen wird. Dieser Übergang ist nur vom Opening-Zustand aus gültig. An diesem Punkt ist das Objekt für die Übertragung voll verwendbar.

  • Closing: Das Objekt geht zu diesem Zustand über, wenn Close für ein ordnungsgemäßes Herunterfahren aufgerufen wird. Dieser Übergang ist nur vom Opened-Zustand aus gültig.

  • Closed: Objekte im Closed-Zustand sind nicht mehr verwendbar. Im Allgemeinen steht der größte Teil der Konfiguration noch zur Ansicht bereit, es kann aber keine Kommunikation auftreten. Dieser Zustand ist mit "Verworfen" vergleichbar.

  • Faulted: Auf Objekte im Faulted-Zustand kann für die Inspektion zugegriffen werden, sie sind aber nicht mehr verwendbar. Wenn ein nicht behebbarer Fehler auftritt, geht das Objekt in diesen Zustand über. Von diesem Zustand ist nur der Übergang in den Closed-Zustand gültig.

Es gibt Ereignisse, die für jeden Zustandsübergang ausgelöst werden. Die Abort-Methode kann jederzeit aufgerufen werden und sorgt dafür, dass das Objekt sofort vom aktuellen Zustand in den Closed-Zustand übergeht. Beim Aufrufen von Abort wird nicht abgeschlossene Arbeit beendet.

Kanalfactory und Kanallistener

Der nächste Schritt beim Schreiben eines benutzerdefinierten Transports besteht im Erstellen einer Implementierung von IChannelFactory für Clientkanäle und von IChannelListener für Dienstkanäle. Die Kanalebene verwendet ein Factorymuster zum Erstellen von Kanälen. WCF stellt Basisklassenhilfen für diesen Prozess bereit.

In diesem Beispiel ist die Factoryimplementierung in "UdpChannelFactory.cs" enthalten, und die Listenerimplementierung ist in "UdpChannelListener.cs" enthalten. Die IChannel-Implementierungen sind in "UdpOutputChannel.cs" und "UdpInputChannel.cs" enthalten.

Die UDP-Kanalfactory

Die UdpChannelFactory wird von ChannelFactoryBase abgeleitet. Das Beispiel überschreibt GetProperty, um Zugriff auf die Nachrichtenversion des Nachrichtenencoders zu gewähren. Das Beispiel überschreibt auch OnClose, um beim Übergang des Zustandsautomaten die Instanz von BufferManager zu beenden.

Der UDP-Ausgabekanal

Der UdpOutputChannel implementiert IOutputChannel. Der Konstruktor überprüft die Argumente und erstellt ein Ziel-EndPoint-Objekt, das auf der übergebenen EndpointAddress basiert.

this.socket = new Socket(this.remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);

Der Kanal kann ordnungsgemäß oder nicht ordnungsgemäß geschlossen werden. Bei ordnungsgemäßer Schließung wird der Socket geschlossen, und die OnClose-Methode der Basisklasse wird aufgerufen. Wenn dadurch eine Ausnahme ausgelöst wird, ruft die Infrastruktur Abort auf, um sicherzustellen, dass der Kanal bereinigt wird.

this.socket.Close(0);

Implementieren Sie anschließend Send() und BeginSend()/EndSend(). Dieser Vorgang ist in zwei Hauptabschnitte unterteilt. Serialisieren Sie zuerst die Nachricht in ein Bytearray:

ArraySegment<byte> messageBuffer = EncodeMessage(message);

Senden Sie anschließend die resultierenden Daten:

this.socket.SendTo(messageBuffer.Array, messageBuffer.Offset, messageBuffer.Count, SocketFlags.None, this.remoteEndPoint);

Der UdpChannelListener

Die UdpChannelListener-Implementierung im Beispiel wird von der ChannelListenerBase-Klasse abgeleitet. Er verwendet einen einzelnen UDP-Socket, um Datagramme zu empfangen. Die OnOpen-Methode empfängt Daten mit dem UDP-Socket in einer asynchronen Schleife. Die Daten werden dann mit dem Nachrichtencodierungsframework in Nachrichten konvertiert:

message = MessageEncoderFactory.Encoder.ReadMessage(new ArraySegment<byte>(buffer, 0, count), bufferManager);

Da derselbe Datagrammkanal Nachrichten darstellt, die aus einer Reihe von Quellen eintreffen, ist der UdpChannelListener ein Singletonlistener. Es gibt höchstens einen aktiven IChannel, der diesem Listener gleichzeitig zugeordnet ist. In diesem Beispiel wird nur dann ein weiterer generiert, wenn ein Kanal, der mit der AcceptChannel-Methode zurückgegeben wird, anschließend freigegeben wird. Wenn eine Nachricht empfangen wird, wird sie in diesem Singletonkanal in die Warteschlange eingereiht.

UdpInputChannel

Die UdpInputChannel-Klasse implementiert IInputChannel. Sie besteht aus einer Warteschlange mit eingehenden Nachrichten, die vom UdpChannelListener-Socket gefüllt wird. Diese Nachrichten werden mit der IInputChannel.Receive-Methode aus der Warteschlange entfernt.

Hinzufügen eines Bindungselements

Nachdem nun die Factorys und Kanäle erstellt sind, müssen sie der ServiceModel-Laufzeit über eine Bindung verfügbar gemacht werden. Eine Bindung ist eine Auflistung von Bindungselementen, die den mit einer Dienstadresse verknüpften Kommunikationsstapel darstellt. Jedes Element im Stapel wird durch ein Element vom Typ <binding> dargestellt.

Im Beispiel ist das Bindungselement UdpTransportBindingElement, das von TransportBindingElement abgeleitet wird. Es überschreibt die folgenden Methoden zum Erstellen der der Bindung zugeordneten Factorys.

public IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
{
    return (IChannelFactory<TChannel>)(object)new UdpChannelFactory(this, context);
}

public IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
{
    return (IChannelListener<TChannel>)(object)new UdpChannelListener(this, context);
}

Es enthält auch Member zum Klonen des BindingElement und Zurückgeben unseres Schemas (soap.udp).

Hinzufügen von Metadatenunterstützung für ein Transportbindungselement

Um den Transport in ein Metadatensystem zu integrieren, muss dieser sowohl den Import als auch den Export von Richtlinien unterstützen. Dies ermöglicht uns das Generieren von Clients unserer Bindung über das ServiceModel Metadata Utility-Tool (Svcutil.exe).

Hinzufügen von WSDL-Unterstützung

Das Transportbindungselement in einer Bindung ist für den Export und Import von Adressierungsinformationen in/zu Metadaten verantwortlich. Bei der Nutzung einer SOAP-Bindung sollte das Transportbindungselement ebenfalls einen korrekten Transport-URI in die Metadaten exportieren.

WSDL-Export

Um Adressierungsinformationen zu exportieren, implementiert das UdpTransportBindingElement die IWsdlExportExtension-Schnittstelle. Die ExportEndpoint-Methode fügt dem WSDL-Port die richtigen Adressierungsinformationen hinzu.

if (context.WsdlPort != null)
{
    AddAddressToWsdlPort(context.WsdlPort, context.Endpoint.Address, encodingBindingElement.MessageVersion.Addressing);
}

Die UdpTransportBindingElement-Implementierung der ExportEndpoint-Methode exportiert ebenfalls einen Transport-URI, wenn der Endpunkt eine SOAP-Bindung verwendet.

WsdlNS.SoapBinding soapBinding = GetSoapBinding(context, exporter);
if (soapBinding != null)
{
    soapBinding.Transport = UdpPolicyStrings.UdpNamespace;
}

WSDL-Import

Um das WSDL-Importsystem auf die Handhabung des Imports von Adressen zu erweitern, fügen Sie die folgende Konfiguration zur Konfigurationsdatei für "Svcutil.exe" hinzu (wie in der Datei "Svcutil.exe.config" gezeigt):

<configuration>
  <system.serviceModel>
    <client>
      <metadata>
        <policyImporters>
          <extension type=" Microsoft.ServiceModel.Samples.UdpBindingElementImporter, UdpTransport" />
        </policyImporters>
      </metadata>
    </client>
  </system.serviceModel>
</configuration>

Bei der Ausführung von "Svcutil.exe" gibt es zwei Optionen, um "Svcutil.exe" dazu zu bewegen, die WSDL-Importerweiterungen zu laden:

  1. Verweisen Sie „Svcutil.exe“ mithilfe der <Datei> „/SvcutilConfig:“ auf die Konfigurationsdatei.

  2. Fügen Sie den Konfigurationsabschnitt zu Svcutil.exe.config im gleichen Verzeichnis wie Svcutil.exe hinzu.

Der UdpBindingElementImporter-Typ implementiert die IWsdlImportExtension-Schnittstelle. Die ImportEndpoint-Methode importiert die Adresse vom WSDL-Port.

BindingElementCollection bindingElements = context.Endpoint.Binding.CreateBindingElements();
TransportBindingElement transportBindingElement = bindingElements.Find<TransportBindingElement>();
if (transportBindingElement is UdpTransportBindingElement)
{
    ImportAddress(context);
}

Hinzufügen von Richtlinienunterstützung

Das benutzerdefinierte Bindungselement kann Richtlinienassertionen in die WSDL-Bindung für einen Dienstendpunkt exportieren, um die Funktionen dieses Bindungselements auszudrücken.

Richtlinienexport

Der UdpTransportBindingElement-Typ implementiert IPolicyExportExtension, um den Export von Richtlinien zu unterstützen. Als Ergebnis schließt System.ServiceModel.MetadataExporterUdpTransportBindingElement in die Generierung der Richtlinie für eine Bindung ein, die dieses enthält.

Fügen Sie in IPolicyExportExtension.ExportPolicy eine Assertion für UDP und eine weitere Assertion ein, wenn Sie sich im Multicastmodus befinden. Grund hierfür ist, dass der Multicastmodus Einfluss auf die Art und Weise hat, in der der Kommunikationsstapel erstellt wird, weshalb eine Koordinierung zwischen beiden Seiten stattfinden muss.

ICollection<XmlElement> bindingAssertions = context.GetBindingAssertions();
XmlDocument xmlDocument = new XmlDocument();
bindingAssertions.Add(xmlDocument.CreateElement(
UdpPolicyStrings.Prefix, UdpPolicyStrings.TransportAssertion, UdpPolicyStrings.UdpNamespace));
if (Multicast)
{
    bindingAssertions.Add(xmlDocument.CreateElement(
        UdpPolicyStrings.Prefix,
        UdpPolicyStrings.MulticastAssertion,
        UdpPolicyStrings.UdpNamespace));
}

Da benutzerdefinierte Transportbindungselemente für die Handhabung der Adressierung verantwortlich sind, muss die IPolicyExportExtension-Implementierung auf dem UdpTransportBindingElement auch den Export der geeigneten WS-Adressierungsrichtlinienassertionen handhaben, um die Version der verwendeten WS-Adressierung anzugeben.

AddWSAddressingAssertion(context, encodingBindingElement.MessageVersion.Addressing);

Richtlinienimport

Um das Richtlinienimportsystem zu erweitern, fügen Sie die folgende Konfiguration zur Konfigurationsdatei für "Svcutil.exe" hinzu (wie in der Datei "Svcutil.exe.config" gezeigt):

<configuration>
  <system.serviceModel>
    <client>
      <metadata>
        <policyImporters>
          <extension type=" Microsoft.ServiceModel.Samples.UdpBindingElementImporter, UdpTransport" />
        </policyImporters>
      </metadata>
    </client>
  </system.serviceModel>
</configuration>

Dann implementieren Sie IPolicyImporterExtension aus der registrierten Klasse (UdpBindingElementImporter). Prüfen Sie in ImportPolicy() die Assertionen im entsprechenden Namespace, verarbeiten Sie sie für die Generierung des Transports, und prüfen Sie, ob Multicast vorliegt. Entfernen Sie darüber hinaus die gehandhabten Assertionen aus der Liste der Bindungsassertionen. Erneut stehen bei der Ausführung von "Svcutil.exe" zwei Optionen für die Integration zur Verfügung:

  1. Verweisen Sie „Svcutil.exe“ mit „/SvcutilConfig:<Datei>“ auf unsere Konfigurationsdatei.

  2. Fügen Sie den Konfigurationsabschnitt zu Svcutil.exe.config im gleichen Verzeichnis wie Svcutil.exe hinzu.

Hinzufügen einer Standardbindung

Das Bindungselement kann auf die beiden folgenden Arten verwendet werden:

  • Über eine benutzerdefinierte Bindung: Benutzerdefinierte Bindungen erlauben Benutzern, basierend auf einer beliebigen Gruppe von Bindungselementen, eigene Bindungen zu definieren.

  • Über eine vom System bereitgestellte Bindung, die das Bindungselement enthält. WCF enthält verschiedene vom System definierte Bindungen, z. B. BasicHttpBinding, NetTcpBinding und WsHttpBinding. Jede dieser Bindungen wird einem genau definierten Profil zugeordnet.

Das Beispiel implementiert eine Profilbindung in SampleProfileUdpBinding, die von Binding abgeleitet wurde. SampleProfileUdpBinding enthält bis zu vier Bindungselemente: UdpTransportBindingElement, TextMessageEncodingBindingElement CompositeDuplexBindingElement und ReliableSessionBindingElement.

public override BindingElementCollection CreateBindingElements()
{
    BindingElementCollection bindingElements = new BindingElementCollection();
    if (ReliableSessionEnabled)
    {
        bindingElements.Add(session);
        bindingElements.Add(compositeDuplex);
    }
    bindingElements.Add(encoding);
    bindingElements.Add(transport);
    return bindingElements.Clone();
}

Hinzufügen eines benutzerdefinierten Standardbindungsimportprogramms

„Svcutil.exe“ und der WsdlImporter-Typ erkennen und importieren vom System definierte Bindungen standardmäßig. Andernfalls wird die Bindung als CustomBinding-Instanz importiert. Zur Aktivierung des Imports der WsdlImporter für „Svcutil.exe“ und den SampleProfileUdpBinding, fungiert der UdpBindingElementImporter auch als benutzerdefiniertes Importprogramm für Standardbindungen.

Ein benutzerdefiniertes Standardbindungsimportprogramm implementiert die ImportEndpoint-Methode auf der IWsdlImportExtension-Schnittstelle, um zu prüfen, ob die aus den Metadaten importierte CustomBinding-Instanz von einer spezifischen Standardbindung hätte generiert werden können.

if (context.Endpoint.Binding is CustomBinding)
{
    Binding binding;
    if (transportBindingElement is UdpTransportBindingElement)
    {
        //if TryCreate is true, the CustomBinding will be replace by a SampleProfileUdpBinding in the
        //generated config file for better typed generation.
        if (SampleProfileUdpBinding.TryCreate(bindingElements, out binding))
        {
            binding.Name = context.Endpoint.Binding.Name;
            binding.Namespace = context.Endpoint.Binding.Namespace;
            context.Endpoint.Binding = binding;
        }
    }
}

Allgemein beinhaltet die Implementierung eines benutzerdefinierten Importprogramms für Standardbindungen die Überprüfung der Eigenschaften der importierten Bindungen, um zu bestätigen, dass sich nur Eigenschaften geändert haben, die von der Standardbindung hätten festgelegt werden können, und es sich bei allen anderen Eigenschaften um die Standardwerte handelt. Eine grundlegende Strategie für die Implementierung eines Importprogramms für Standardbindungen ist die Erstellung einer Standardbindung, die Weitergabe der Eigenschaften von den Bindungselementen an die von der Standardbindung unterstützte Standardbindungsinstanz und der Vergleich der Bindungselemente der Standardbindung mit den importierten Bindungselementen.

Hinzufügen von Konfigurationsunterstützung

Um unseren Transport durch Konfiguration verfügbar zu machen, müssen Sie zwei Konfigurationsabschnitte implementieren. Der erste ist ein BindingElementExtensionElement für UdpTransportBindingElement. Auf diese Weise können CustomBinding-Implementierungen auf das im Beispiel erstellte Bindungselement verweisen. Der zweite ist eine Configuration für SampleProfileUdpBinding.

Element für Bindungselementerweiterungen

Der Abschnitt UdpTransportElement ist ein BindingElementExtensionElement, das die UdpTransportBindingElement für das Konfigurationssystem verfügbar macht. Mit wenigen grundlegenden Überschreibungen definiert das Beispiel den Konfigurationsabschnittsnamen, den Typ des Bindungselements und wie das Bindungselement erstellt wird. Benutzer können dann wie im folgenden Code den Erweiterungsabschnitt in einer Konfigurationsdatei registrieren.

<configuration>
  <system.serviceModel>
    <extensions>
      <bindingElementExtensions>
        <add name="udpTransport" type="Microsoft.ServiceModel.Samples.UdpTransportElement, UdpTransport" />
      </bindingElementExtensions>
    </extensions>
  </system.serviceModel>
</configuration>

Auf die Erweiterung kann von benutzerdefinierten Bindungen verwiesen werden, um UDP als Transport zu nutzen.

<configuration>
  <system.serviceModel>
    <bindings>
      <customBinding>
       <binding configurationName="UdpCustomBinding">
         <udpTransport/>
       </binding>
      </customBinding>
    </bindings>
  </system.serviceModel>
</configuration>

Bindungsabschnitt

Der Abschnitt SampleProfileUdpBindingCollectionElement ist ein StandardBindingCollectionElement, das die SampleProfileUdpBinding für das Konfigurationssystem verfügbar macht. Dem SampleProfileUdpBindingConfigurationElement, das sich von StandardBindingElement herleitet, wird der Großteil der Implementierung übertragen. SampleProfileUdpBindingConfigurationElement verfügt über Eigenschaften, die den SampleProfileUdpBinding-Eigenschaften entsprechen, sowie über Funktionen für die Zuordnung aus der ConfigurationElement-Bindung. Schließlich wird die OnApplyConfiguration-Methode in der SampleProfileUdpBinding überschrieben. Dies wird im folgenden Beispielcode veranschaulicht.

protected override void OnApplyConfiguration(string configurationName)
{
    if (binding == null)
        throw new ArgumentNullException("binding");

    if (binding.GetType() != typeof(SampleProfileUdpBinding))
    {
        throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
            "Invalid type for binding. Expected type: {0}. Type passed in: {1}.",
            typeof(SampleProfileUdpBinding).AssemblyQualifiedName,
            binding.GetType().AssemblyQualifiedName));
    }
    SampleProfileUdpBinding udpBinding = (SampleProfileUdpBinding)binding;

    udpBinding.OrderedSession = this.OrderedSession;
    udpBinding.ReliableSessionEnabled = this.ReliableSessionEnabled;
    udpBinding.SessionInactivityTimeout = this.SessionInactivityTimeout;
    if (this.ClientBaseAddress != null)
        udpBinding.ClientBaseAddress = ClientBaseAddress;
}

Um diesen Handler mit dem Konfigurationssystem zu registrieren, fügen Sie der relevanten Konfigurationsdatei den folgenden Abschnitt hinzu.

<configuration>
  <configSections>
     <sectionGroup name="system.serviceModel">
        <sectionGroup name="bindings">
          <section name="sampleProfileUdpBinding" type="Microsoft.ServiceModel.Samples.SampleProfileUdpBindingCollectionElement, UdpTransport" />
        </sectionGroup>
     </sectionGroup>
  </configSections>
</configuration>

Darauf kann dann vom serviceModel-Konfigurationsabschnitt verwiesen werden.

<configuration>
  <system.serviceModel>
    <client>
      <endpoint configurationName="calculator"
                address="soap.udp://localhost:8001/"
                bindingConfiguration="CalculatorServer"
                binding="sampleProfileUdpBinding"
                contract= "Microsoft.ServiceModel.Samples.ICalculatorContract">
      </endpoint>
    </client>
  </system.serviceModel>
</configuration>

Der UDP-Testdienst und der Client

Testcode für die Verwendung dieses Beispieltransports ist in den UdpTestService- und UdpTestClient-Verzeichnissen verfügbar. Der Dienstcode besteht aus zwei Tests: Ein Test richtet die Bindungen und Endpunkte über den Code ein und der andere über die Konfiguration. Beide Tests verwenden zwei Endpunkte. Ein Endpunkt verwendet SampleUdpProfileBinding mit der Festlegung von <reliableSession> auf true. Der andere Endpunkt verwendet eine benutzerdefinierte Bindung mit UdpTransportBindingElement. Dies entspricht der Verwendung von SampleUdpProfileBinding mit der Festlegung von <reliableSession> auf false. Beide Tests erstellen einen Dienst, fügen einen Endpunkt für jede Bindung hinzu, öffnen den Dienst und warten anschließend darauf, dass der Benutzer die EINGABETASTE drückt, bevor der Dienst beendet wird.

Wenn Sie die Testanwendung für den Dienst starten, sollte folgende Ausgabe angezeigt werden:

Testing Udp From Code.
Service is started from code...
Press <ENTER> to terminate the service and start service from config...

Sie können dann die Testclientanwendung für die veröffentlichten Endpunkte ausführen. Die Clienttestanwendung erstellt für jeden Endpunkt einen Client und sendet fünf Nachrichten an jeden Endpunkt. Im Folgenden finden Sie die Ausgabe auf dem Client:

Testing Udp From Imported Files Generated By SvcUtil.
0
3
6
9
12
Press <ENTER> to complete test.

Im Folgenden finden Sie die vollständige Ausgabe auf dem Dienst:

Service is started from code...
Press <ENTER> to terminate the service and start service from config...
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
   adding 0 + 0
   adding 1 + 2
   adding 2 + 4
   adding 3 + 6
   adding 4 + 8

Um die Clientanwendung für Endpunkte auszuführen, die mithilfe einer Konfiguration veröffentlicht wurden, drücken Sie die EINGABETASTE im Dienst, und führen Sie den Testclient erneut aus. Auf dem Dienst sollten Sie die folgende Ausgabe erhalten:

Testing Udp From Config.
Service is started from config...
Press <ENTER> to terminate the service and exit...

Durch das erneute Ausführen des Clients werden die gleichen Ergebnisse erzielt wie zuvor.

Um den Clientcode und die Konfiguration mithilfe von "Svcutil.exe" neu zu generieren, starten Sie die Dienstanwendung, und führen Sie dann "Svcutil.exe" wie folgt aus dem Stammverzeichnis des Beispiels aus:

svcutil http://localhost:8000/udpsample/ /reference:UdpTransport\bin\UdpTransport.dll /svcutilConfig:svcutil.exe.config

Beachten Sie, dass "Svcutil.exe" nicht die Bindungserweiterungskonfiguration für SampleProfileUdpBinding generiert. Sie müssen diese daher manuell hinzufügen.

<configuration>
  <system.serviceModel>
    <extensions>
      <!-- This was added manually because svcutil.exe does not add this extension to the file -->
      <bindingExtensions>
        <add name="sampleProfileUdpBinding" type="Microsoft.ServiceModel.Samples.SampleProfileUdpBindingCollectionElement, UdpTransport" />
      </bindingExtensions>
    </extensions>
  </system.serviceModel>
</configuration>

So können Sie das Beispiel einrichten, erstellen und ausführen

  1. Befolgen Sie zum Erstellen der Projektmappe die Anweisungen unter Erstellen der Windows Communication Foundation-Beispiele.

  2. Wenn Sie das Beispiel in einer Konfiguration mit einem Computer oder über Computer hinweg ausführen möchten, folgen Sie den Anweisungen unter Durchführen der Windows Communication Foundation-Beispiele.

  3. Informationen finden Sie im vorhergehenden Abschnitt "Der UDP-Testdienst und der Client".