WCF Routing-Service

Das Prinzip hinter Routing ist es, ankommende Pakete entgegen zunehmen und diese abzulehnen oder an eine entsprechende Stelle weiterzuleiten. Routing wird oft benutzt um einzelne Netzwerke zu koppeln oder zu trennen. Dadurch lassen sich Netzwerke flexibler verwalten und die Sicherheit wird erhöht. Zudem ist es möglich Netzwerke, die unterschiedliche "Sprachen" verwenden, miteinander kommunizieren zu lassen. Solange der Routing-Dienst beide Sprachen versteht ist das kein Problem.

Während es in früheren Versionen von WCF noch nötig war dieses Verhalten selber zu implementieren kann seit Version 4 auf den integrierten Routing-Service zugegriffen werden. Der Routing-Service darf nicht mit einem gewöhnlichen Router verglichen werden, wie man ihn in der Schicht 3 im Osi-Modell findet. Software Routing setzt viel weiter "oben" an.
Der WCF Routing-Service besitzt viele Möglichkeiten das gesamte Routing den eigenen Vorstellungen anzupassen. Beginnen wir jedoch simpel. In unserem ersten Beispiel leiten wir eine Anfrage an einen Zielrechner weiter. Der Host hört dabei auf Port 9500. Der Client versucht den Host jedoch auf Port 8500 zu erreichen. Die Aufgabe des Routing-Service ist es nun die Anfrage entgegen zunehmen und an den richtigen Port weiterzuleiten. Dabei bleibt es jedem selbst überlassen welches Protokoll er verwenden möchte. Auch eine Mischung aus mehreren Protokollen ist möglich. So kann beispielsweise bis zum Router HTTP und anschließend TCP verwendet werden. Ich habe mich für reines TCP entschieden.
sdafadsf
Der Code für den Router ist nicht viel. Wir müssen jedoch einen Verweis auf System.ServiceModel und System.ServiceModel.Routing zu unserem Projekt hinzufügen.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Routing;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

namespace RouterService
{
class Programm
{
public static void Main()
{
ServiceHost MyService = new ServiceHost(typeof(RoutingService));
ConfigService(MyService);

Console.WriteLine("Starte Router...");
MyService.Open();
Console.WriteLine("Router gestartet. Zum Beenden Enter drücken.");

Console.ReadLine();
}

public static void ConfigService(ServiceHost service)
{
Binding inputBindnig = new NetTcpBinding();
Binding outputBinding = new NetTcpBinding();

// Eingehende Verbindung
service.AddServiceEndpoint(typeof(IRequestReplyRouter),
inputBindnig,
"net.tcp://localhost:8500/MyService");

// Ausgehende Verbindung
ContractDescription contract = ContractDescription.GetContract(typeof(IRequestReplyRouter));

ServiceEndpoint outputEndpoint = new ServiceEndpoint(contract,
outputBinding,
new EndpointAddress("net.tcp://localhost:9500/MyService"));

// Routerconfig
RoutingConfiguration rc = new RoutingConfiguration();

// Liste mit allen ausgehenden Verbindungen anlegen
List<serviceendpoint> endpointList = new List<serviceendpoint>();
endpointList.Add(outputEndpoint);

// Filter für Weiterleitung festlegen.
// Liste zur Routerconfig hinzufügen.
rc.FilterTable.Add(new MatchAllMessageFilter(), endpointList);

// Routerconfig zum Service hinzufügen
service.Description.Behaviors.Add(new RoutingBehavior(rc));
}
}
}

Zuerst erstellen wir einen Service-Host vom Typ RoutingService. Das geschieht über new ServiceHost(typeof(RoutingService)). Um den Service zu konfigurieren übergeben wir ihn der Methode ConfigService(...).
In dieser Methode werden zuerst einmal die Bindungen für die eingehende und ausgehende Verbindung erstellt. Mit service.AddServiceEndpoint(...) erstellen wir den Endpunkt an den der Router auf Anfragen wartet.
Der Endpunkt an den der Router die Anfragen weiterleitet wird mit new ServiceEndpoint() erstellt. Dabei ist zu beachten, dass dieser Endpunkt einen Contract übergeben bekommt, der mit dem Interface IRequestReplyRouter erstellt wurde.

Anschließend benötigt unser Service noch eine Konfiguration. Diese erstellen wir über den Standardkonstruktor new RoutingConfiguration().
Wir erstellen zusätzlich noch eine Liste mit allen unseren ausgehenden Verbindungen. Wir haben in unserem Beispiel nur einen, es können jedoch auch mehrere hinzugefügt werden. Das ist nützlich falls ein Dienst ausfällt und ein anderer Host die Aufgabe übernehmen soll. WCF erkennt eine ausgefallene Verbindung automatisch und leitet die Anfrage an der Ersatz weiter. Wir müssen hierfür lediglich einen weiteren Endpunkt in die Liste aufnehmen.

Die Liste fügen wir nun unserer Konfiguration hinzu. Dabei benutzen wir den Filter MatchAllMessageFilter(). Dieser Filter leitet ausnahmslos alle passenden Anfragen weiter. Die Konfiguration muss zum Schluss noch unserem Service hinzugefügt werden und wir sind fertig.

Wir können unsere Einstellungen, die wir in ConfigService(...) gemacht haben, auch in die App.config schreiben. Ich finde es persönlich zwar unübersichtlicher, eine veränderbare Textdatei ist manchmal jedoch Gold wert. Damit der Service auch über die App.config erstellt wird muss die Methode ConfigService(...) auskommentiert oder ganz entfernt werden.
...
ServiceHost MyService = new ServiceHost(typeof(RoutingService));
// ConfigService(MyService);

Console.WriteLine("Starte Router...");
...


Das hier ist die entsprechende App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="routingData" name="System.ServiceModel.Routing.RoutingService">
<endpoint address="" binding="netTcpBinding" name="reqReplyEndpoint"
contract="System.ServiceModel.Routing.IRequestReplyRouter" />
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8500/MyService" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="routingData">
<routing filterTableName="FilterTable1" />
<serviceMetadata httpGetEnabled="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<client>
<endpoint address="net.tcp://localhost:9500/MyService" binding="netTcpBinding"
contract="*" name="OutputEndpoint" />
</client>
<routing>
<filters>
<filter name="MyFilter" filterType="MatchAll" />
</filters>
<filterTables>
<filterTable name="FilterTable1">
<add filterName="MyFilter" endpointName="OutputEndpoint" />
</filterTable>
</filterTables>
</routing>
</system.serviceModel>
</configuration>
Bookmark and Share

0 Kommentare:

Kommentar veröffentlichen