Freigeben über


Schritt 8: Implementieren des synchronen Eingangshandlers für den Echo-Adapter

Schritt 8 von 9

Dauer: 45 Minuten

In diesem Schritt implementieren Sie die eingehende Funktion des Echoadapters. Diese Funktion ermöglicht es dem Adapter, auf Daten oder Ereignisse aus dem Zielsystem zu lauschen. Gemäß dem WCF LOB Adapter SDK müssen Sie die Microsoft.ServiceModel.Channels.Common.IInboundHandler Schnittstelle nur implementieren, wenn ihr Adapter eingehende Funktionen unterstützt. Der Adapterentwicklungs-Assistent generiert automatisch die abgeleitete Klasse mit dem Namen EchoAdpterInboundHandler für Sie.

Im folgenden Abschnitt aktualisieren Sie die EchoAdpterInboundHandler-Klasse, um ein besseres Verständnis für die Implementierung dieser Schnittstelle zu erhalten. Wenn Sie diesen Schritt ausführen, verfügen Sie über einen funktionierenden eingehenden Handler für den Echoadapter.

Voraussetzungen

Bevor Sie mit diesem Schritt beginnen, müssen Sie Schritt 7: Implementieren des synchronen ausgehenden Handlers für den Echoadapter erfolgreich abgeschlossen haben. Eine grundlegende Vertrautheit mit Microsoft.ServiceModel.Channels.Common.IInboundHandler ist ebenfalls hilfreich.

Die IInboundHandler-Schnittstelle

Microsoft.ServiceModel.Channels.Common.IInboundHandler ist wie folgt definiert:

public interface IInboundHandler : IConnectionHandler, IDisposable  
{  
          void StartListener(string[] actions, TimeSpan timeout);  
          void StopListener(TimeSpan timeout);  
          bool TryReceive(TimeSpan timeout, out Message message, out IInboundReply reply);  
          bool WaitForMessage(TimeSpan timeout);  
}  

Die Methodenbeschreibungen sind:

Methode BESCHREIBUNG
StartListener Beginnt mit dem Lauschen auf Nachrichten mit dem bereitgestellten WS-Addressing Actions. Wenn keine angegeben ist, werden alle oder die Standardaktionen überwacht.
StopListener Hört auf zu lauschen.
TryReceive Versucht, eine eingehende Nachricht vom Zielsystem zu empfangen.
WaitForMessage Wartet auf eine eingehende WCF-Nachricht vom Zielsystem.

Weitere Informationen zur Beschreibung der einzelnen Methodenparameter finden Sie in der Dokumentation auf der Microsoft.ServiceModel.Channels.Common.IInboundHandler Schnittstelle.

Implementieren von EchoAdpterInboundHandler

Der Echoadapter verwendet den System.IO.FileSystemWatcher , um das Zielsystem zu simulieren. Im Folgenden implementieren Sie jede Methode innerhalb der Microsoft.ServiceModel.Channels.Common.IInboundHandler Schnittstelle, StartListener, StopListener, TryReceive und WaitForMessage.

So implementieren Sie die IInboundHandler-Schnittstelle in der EchoAdpterInboundHandler-Klasse

  1. Doppelklicken Sie in Projektmappen-Explorer auf die Datei EchoAdapterInboundHandler.cs.

  2. Fügen Sie im Visual Studio-Editor die folgenden Zeilen dem vorhandenen Satz von using-Anweisungen hinzu.

    using System.IO;  
    using System.ServiceModel.Channels;  
    using System.Xml;  
    using System.Diagnostics;  
    
  3. Fügen Sie nun der EchoAdapterInboundHandler-Klasse Variablen auf Klassenebene hinzu. Diese Variablen werden verwendet, um das Dateisystem auf Dateiaktivitäten zu überwachen. Kopieren Sie die folgenden Deklarationen in die -Klasse vor dem Konstruktor.

    private Queue<Message> inboundQueue;  
    private FileSystemWatcher inboundWatcher;  
    private Object inboundQueueSynchronizationLock;  
    private string path;  
    private string filter;  
    
  4. Fügen Sie in der EchoAdapterInboundHandler-Konstruktormethode den folgenden Code hinzu, um die Dateiüberwachungsinfrastruktur zu initialisieren und den Überwachungspfad und filter zu erfassen.

    inboundWatcher = null;  
    inboundQueueSynchronizationLock = new Object();  
    path = connection.ConnectionFactory.Adapter.InboundFileSystemWatcherFolder;  
    filter = connection.ConnectionFactory.Adapter.InboundFileFilter;  
    
  5. Fügen Sie nun der StartListener-Methode den folgenden Code hinzu. Der Code implementiert Logik, um Parameter zu überprüfen und die Überwachung der Dateiaktivität zu starten.

    // if no actions are provided, log an error in the trace log  
    // and throw an exception  
    if (actions.Length == 0)  
    {  
        EchoAdapterUtilities.Trace.Trace(TraceEventType.Error, "http://echoadapterv2/startlistener/noactions", "No operation actions were received for listener to do specific processing.", this);  
        throw new AdapterException("Unable to receive any actions for inbound handler to start listening.");  
    }  
    
    inboundQueue = new Queue<Message>();  
    foreach (string action in actions)  
    {  
        // for the OnReceiveEcho action listen for a new file created event  
        if ("Echo/OnReceiveEcho".Equals(action))  
        {  
            if (inboundWatcher == null)  
            {  
                inboundWatcher = new FileSystemWatcher(path);  
                inboundWatcher.Filter = filter;  
                // Begin monitoring  
                inboundWatcher.EnableRaisingEvents = true;  
            }  
            inboundWatcher.Created += new FileSystemEventHandler(FileMonitor_Created);  
            EchoAdapterUtilities.Trace.Trace(TraceEventType.Information, "http://echoadapterv2/startlistener", "Listening for file created event for " + filter + " in path " + path, this);  
        }  
    }  
    
  6. Fahren Sie fort, indem Sie eine Implementierung für die StopListener-Methode hinzufügen.

    if (inboundWatcher != null)  
    {  
        // End monitoring  
        inboundWatcher.EnableRaisingEvents = false;  
        inboundWatcher = null;  
    }  
    lock (inboundQueueSynchronizationLock)  
    {  
        inboundQueue.Clear();  
        inboundQueue = null;  
    }  
    
  7. Stellen Sie nun eine Implementierung für die TryReveive-Methode bereit. Diese Methode ruft die neueste Datei-Empfangsnachricht aus der internen Warteschlange ab, sofern eine verfügbar ist.

    reply = new EchoAdapterInboundReply();  
    message = null;  
    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);  
    while (true)  
    {  
        lock (inboundQueueSynchronizationLock)  
        {  
            if (inboundQueue == null)  
            {  
                //listener has been closed  
                return false;  
            }  
            if (inboundQueue.Count != 0)  
            {  
                message = inboundQueue.Dequeue();  
                if (message != null)  
                {  
                    return true;  
                }  
            }  
        }  
        if (timeoutHelper.IsExpired)  
        {  
            return false;  
        }  
        //wait for sometime, and check again  
        System.Threading.Thread.Sleep(500);  
    }  
    
  8. Fahren Sie fort, indem Sie eine Implementierung für die WaitForMessage-Methode hinzufügen.

    while (inboundQueue.Count == 0) { };  
    Message msg = inboundQueue.Peek();  
    if (msg != null)  
    {  
        return true;  
    }  
    else  
    {  
        return false;  
    }  
    
  9. Geben Sie nun den Rückruf für die Dateiüberwachung an. Fügen Sie dazu der EchoAdapterInboundAdapter-Klasse die neue Methode FileMonitor_Created hinzu.

    private void FileMonitor_Created(object sender, FileSystemEventArgs e)  
    {  
        lock (inboundQueueSynchronizationLock)  
        {  
            if (e.ChangeType == WatcherChangeTypes.Created)  
            {  
                // wait for file to close - should do this in a better manner  
                System.Threading.Thread.Sleep(500);  
                try  
                {  
                    EchoAdapterUtilities.Trace.Trace(TraceEventType.Information, "http://echoadapterv2/FileMonitorCreated", "File " + e.FullPath + " created.", this);  
                    FileInfo fileInfo = new FileInfo(e.FullPath);  
                    // Create WCF message to send to the inbound service  
                    // that is listening for messages from adapter  
                    String xmlData = String.Format(@"<OnReceiveEcho xmlns=""{0}""><path>{1}</path><length>{2}</length></OnReceiveEcho>", EchoAdapter.SERVICENAMESPACE, e.FullPath, fileInfo.Length);  
                    // set action string  
                    XmlReader reader = XmlReader.Create(new StringReader(xmlData));  
                    // create WCF message  
                    Message requestMessage = Message.CreateMessage(MessageVersion.Default  
                                , "Echo/OnReceiveEcho"  
                                , reader);  
                    requestMessage.Headers.To = new Uri(path);  
                    inboundQueue.Enqueue(requestMessage);  
                }  
                catch (Exception ex)  
                {  
                    String message = String.Format("An exception was thrown while trying to open file {1}.", e.FullPath);  
                    EchoAdapterUtilities.Trace.Trace(System.Diagnostics.TraceEventType.Error, "http://echoadapterv2/FileMonitorCreated", message, this, ex);  
                    throw new AdapterException(message, ex);  
                }  
            }  
        }  
    }  
    
  10. Nun müssen Sie die NotImplementedException-Ausnahmen entfernen, die von der internen EchoAdapterInboundReply-Klasse ausgelöst werden. Löschen Sie dazu die folgende Anweisung aus den Methoden Abort und Reply .

    throw new NotImplementedException("The method or operation is not implemented.");  
    

    Die Methoden Abort und Reply sollten wie folgt aussehen.

    /// <summary>  
    /// Abort the inbound reply call  
    /// </summary>  
    public override void Abort()  
    {  
    }  
    
    /// <summary>  
    /// Reply message implemented  
    /// </summary>  
    public override void Reply(System.ServiceModel.Channels.Message message  
        , TimeSpan timeout)  
    {  
    }  
    
  11. Fügen Sie echoAdapterOutboundHandler.cs die folgende Klasse hinzu, um die Implementierung für den eingehenden Handler abzuschließen. Diese Klasse bietet Timeoutunterstützung für die Implementierung des eingehenden Handlers.

    /// <summary>  
    /// Utility class containing helper functions for measuring timeout   
    /// </summary>  
    class TimeoutHelper  
    {  
        private TimeSpan timeout;  
        private DateTime creationTime;  
        private Boolean isInfinite;  
    
        /// <summary>  
        /// Constructor  
        /// </summary>  
        /// <param name="timeout"></param>  
        public TimeoutHelper(TimeSpan timeout)  
        {  
            this.creationTime = DateTime.Now;  
            this.timeout = timeout;  
            if (timeout.Equals(Infinite)) this.isInfinite = true;  
        }  
    
        /// <summary>  
        /// Value of infinite timespan  
        /// </summary>  
        public static TimeSpan Infinite  
        {  
            get { return TimeSpan.MaxValue; }  
        }  
    
        /// <summary>  
        /// Value indicating remaining timeout  
        /// </summary>  
        public TimeSpan RemainingTimeout  
        {  
            get  
            {  
                if (this.isInfinite) return Infinite;  
                return this.timeout.Subtract(DateTime.Now.Subtract(this.creationTime));  
            }  
        }  
    
        /// <summary>  
        /// Get remaining timeout value and throw an exception if the timeout  
        /// has expired.  
        /// </summary>  
        /// <param name="exceptionMessage"></param>  
        /// <returns></returns>  
        public TimeSpan GetRemainingTimeoutAndThrowIfExpired(String exceptionMessage)  
        {  
            if (this.isInfinite) return Infinite;  
            if (RemainingTimeout < TimeSpan.Zero)  
            {  
                throw new TimeoutException(exceptionMessage);  
            }  
            return RemainingTimeout;  
        }  
    
        /// <summary>  
        /// Throw an exception if the timeout has expired.  
        /// </summary>  
        /// <param name="exceptionMessage"></param>  
        public void ThrowIfTimeoutExpired(String exceptionMessage)  
        {  
            if (RemainingTimeout < TimeSpan.Zero)  
            {  
                throw new TimeoutException(exceptionMessage);  
            }  
    
        }  
    
        /// <summary>  
        /// Value indicating whether timeout has expired.  
        /// </summary>  
        public Boolean IsExpired  
        {  
            get  
            {  
                if (this.isInfinite) return false;  
                return RemainingTimeout < TimeSpan.Zero;  
            }  
        }  
    }  
    
  12. Klicken Sie in Visual Studio im Menü Datei auf Alle speichern.

  13. Klicken Sie im Menü Erstellen auf Projektmappe erstellen. Es sollte ohne Fehler kompiliert werden. Falls nicht, stellen Sie sicher, dass Sie alle oben genannten Schritte ausgeführt haben.

Hinweis

Sie haben Ihre Arbeit gespeichert. Sie können Visual Studio zu diesem Zeitpunkt sicher schließen oder mit dem nächsten Schritt fortfahren, Schritt 9: Erstellen und Bereitstellen des Echoadapters.

Was habe ich gerade getan?

In diesem Schritt des Echoadapter-Tutorials haben Sie eine Implementierung für den Eingehenden Handler bereitgestellt. Diese Implementierung bietet Dateiüberwachungsfunktionen für den Echo-Adapter mithilfe der FileSystemWatcher-Klasse des .NET Framework.

Nächste Schritte

Im nächsten Schritt stellen Sie den Adapter bereit.

Weitere Informationen

Schritt 9: Erstellen und Bereitstellen des Echo-Adapters
Schritt 7: Implementieren des synchronen Ausgangshandlers für den Echo-Adapter