<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Über Individualsoftware, Webanwendungen und Datenbanken</title>
	<atom:link href="http://www.flexbit.at/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.flexbit.at/blog</link>
	<description>Gedanken, Probleme und Lösungen</description>
	<lastBuildDate>Sun, 10 Jul 2011 04:26:33 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>WCF-Duplex zwischen Windows Sevice und GUI-Frontend</title>
		<link>http://www.flexbit.at/blog/wcf-duplex-zwischen-windows-sevice-und-gui-frontend/</link>
		<comments>http://www.flexbit.at/blog/wcf-duplex-zwischen-windows-sevice-und-gui-frontend/#comments</comments>
		<pubDate>Sun, 10 Jul 2011 04:21:32 +0000</pubDate>
		<dc:creator>Daniel Lang</dc:creator>
				<category><![CDATA[Windows]]></category>
		<category><![CDATA[IPC]]></category>
		<category><![CDATA[Service]]></category>

		<guid isPermaLink="false">http://www.flexbit.at/blog/?p=78</guid>
		<description><![CDATA[Mithile von WCF lässt sich einfach und schnell eine grafische Benutzeroberfläche für einen Windows-Service entwickeln. Über einen Duplex-Contract werden einerseits Statusmeldungen und Informationen vom Dienst zur Benutzeroberfläche übertragen, andererseits kann der Anwender auch Steuerbefehle an den Dienst schicken. Durch den Einsatz von WCF und einem Subcriber-Modell, können beliebig viele Frontends gleichzeitig auf unterschiedlichen Computern verwendet werden. Entstehung In meinem letzten Artikel habe ich beschrieben, welche unterschiedlichen Möglichkeiten es zur Inter-Process-Communication zwischen einer GUI und einem Windows-Service gibt. Für unsere Magento-Schnittstelle, die ebenfalls als Windows-Dienst im Hintergrund arbeitet, wollten wir eine einfache Möglichkeit schaffen um auch über das Netzwerk oder sogar [...]]]></description>
			<content:encoded><![CDATA[<p>Mithile von WCF lässt sich einfach und schnell eine grafische Benutzeroberfläche für einen Windows-Service entwickeln. Über einen Duplex-Contract werden einerseits Statusmeldungen und Informationen vom Dienst zur Benutzeroberfläche übertragen, andererseits kann der Anwender auch Steuerbefehle an den Dienst schicken. Durch den Einsatz von WCF und einem Subcriber-Modell, können beliebig viele Frontends gleichzeitig auf unterschiedlichen Computern verwendet werden.<span id="more-78"></span></p>
<h3>Entstehung</h3>
<p>In meinem letzten Artikel habe ich beschrieben, welche unterschiedlichen Möglichkeiten es zur Inter-Process-Communication zwischen einer <a title="GUI für Windows Service in .NET" href="http://www.flexbit.at/blog/gui-fur-windows-service-in-net/">GUI und einem Windows-Service</a> gibt. Für unsere <a href="http://www.mageconnector.com">Magento-Schnittstelle</a>, die ebenfalls als Windows-Dienst im Hintergrund arbeitet, wollten wir eine einfache Möglichkeit schaffen um auch über das Netzwerk oder sogar eine Internetverbindung den Dienst kontrollieren und steuern zu können. Dazu haben wir uns letztendlich für den Einatz von WCF (Windows-Communication-Foundation) entschieden. Etwas verspätet aber doch, halte ich damit mein Versprechen und präsentiere unsere Lösung und auch etwas Beispielcode.</p>
<h3>Systemaufbau</h3>
<p>Wir haben einen Windows-Dienst, der im Hintergrund irgendeine lange Aufgabe ausführt und dabei Statusmeldungen via WCF an einen oder mehrere Frontends schickt. Der Dienst läuf mit .NET 4 und hostet einen WCF-Service, der einen Endpunkt über ein NamedPipe-Binding zur Verfügung stellt. Der Frontend ist eine relativ überschaubare WPF-Anwendung, der den WCF-Service konsumiert (=Client) und auch einen Callback-Kontrakt implementiert, damit der Dienst (=Server) jederzeit Nachrichten an den oder die Clients schicken kann. Hier eine schematische Darstellung:<br />
<img class="alignnone size-full wp-image-80" src="http://www.flexbit.at/blog/wp-content/uploads/2011/07/aufbau.png" alt="Schematischer Systemaufbau" width="500" height="198" /></p>
<h3>Der Windows-Dienst</h3>
<p>Zunächst einmal erstellen wir einen Windows-Dienst, der im Sekunden-Takt irgendeine Aufgabe ausführt und dabei eine Nachricht in die Event-Log schreibt. Wie man grundsätzlich einen Windows-Dienst in C#/.NET erstellt kann man zur Auffrischung <a title="Creating a Windows Service in C#" href="http://www.codeproject.com/KB/system/WindowsService.aspx" target="_blank">hier</a> nachlesen. Interessanter wird es in der OnStart-Methode. Hier starten wir einen neuen Thread, der für die regelmäßige Ausführung der Aufgabe zuständig ist (deshalb auch <em>schedulerThread</em>):</p>
<pre class="brush:csharp">        protected override void OnStart(string[] args)
        {
            ...

            // start scheduler-thread
            SchedulerThread = new Thread(this.ScheduleHandler);
            SchedulerThread.Start();
        }</pre>
<p>Hier die Methode des neuen Threads, die dann pro Sekunde einen Tick in die EventLog schreibt (vorerst):</p>
<pre class="brush:csharp">        private void ScheduleHandler()
        {
            while (true)
            {
                var beginTime = DateTime.UtcNow;

                try
                {
                    EventLog.WriteEntry(EventLogSource, "Tick", EventLogEntryType.Information);
                }
                catch (Exception ex)
                {
                    EventLog.WriteEntry(EventLogSource, "Error: " + ex.Message, EventLogEntryType.Error);
                }

                // wait until next processing-cycle
                var duration = DateTime.UtcNow - beginTime;
                int milisecondsToWait = (1000) - (int)duration.TotalMilliseconds;
                if (milisecondsToWait &gt; 0)
                    Thread.Sleep(milisecondsToWait);
            }
        }</pre>
<p>Zu guter letzt noch die killer-Methode, die den Thread wieder beendet, wenn der Windows-Dienst gestoppt wird:</p>
<pre class="brush:csharp">        protected override void OnStop()
        {
            // stop scheduler-thread
            killThread(SchedulerThread);
        }

        private void killThread(Thread threadToKill)
        {
            if (threadToKill != null &amp;&amp; threadToKill.IsAlive)
            {
                // interrupt the thread so it has the opportunity to clean up
                threadToKill.Interrupt();

                // wait one seconds for the thread to finish
                threadToKill.Join(1000);

                // if the thread is still alive, kill it
                if (threadToKill.IsAlive)
                    threadToKill.Abort();
            }
        }</pre>
<h3>Hosten des WCF Service</h3>
<p>Bis jetzt haben wir nur einen &#8220;normalen&#8221; Windows-Dienst, der pro Sekunde einen Tick in die Ereignisanzeige schreibt. Damit sich aber später unsere Frontend-Anwendung mit dem Dienst verbinden kann, hosten wir einen WCF Service innerhalb des Windows-Dienstes. In diesem Beispiel verwenden wir einen NamedPipe-Endpunkt, der sich für eine besonders schnelle Kommunikation auf demselben Computer eignet. Natürlich könnten wir hier aber auch ein TcpBinding oder ein WsDualHttpBinding verwenden, wenn die Kommunikation über das Netzwerk stattfinden soll. Wichtig ist hier nur, dass es sich um ein Duplex-kompatibles Binding handelt, damit wir über die WCF-Callbacks auch Nachrichten vom Server an den Client <em>pushen</em> können.</p>
<p>Das Hosten eines WCF-Services innerhalb eines Windows-Dienstes ist mihtilfe der ServiceHost-Klasse recht einfach. In unserem Beispiel verzichten wir zur Gänze auf eine Konfiguration über die app.config, sondern erstellen den ServiceHost programmatisch. Hier die finale OnStart und OnStop-Methode.</p>
<pre class="brush:csharp">        protected override void OnStart(string[] args)
        {
            /////////////////////////////
            // wcf-service host

            controlServiceHost = new ServiceHost(typeof(ControlService), new Uri[] { new Uri("net.pipe://localhost/servicecontrol") });
            controlServiceHost.AddServiceEndpoint(typeof(IControlService), new NetNamedPipeBinding(), "");

            // add metadata-binding, so that a proxy can be generated for the client (not recommended for production-use!)
            var serviceMetadataBehaviour = new System.ServiceModel.Description.ServiceMetadataBehavior();
            controlServiceHost.Description.Behaviors.Add(serviceMetadataBehaviour);
            controlServiceHost.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexNamedPipeBinding(), "mex");

            // start wcf-service
            controlServiceHost.Open();

            // start scheduler-thread
            SchedulerThread = new Thread(this.ScheduleHandler);
            SchedulerThread.Start();
        }

        protected override void OnStop()
        {
            // stop wcf-service
            controlServiceHost.Close();

            // stop scheduler-thread
            killThread(SchedulerThread);
        }</pre>
<p>Beim Starten des Windows-Dienstes wird somit ein WCF-Endpunkt mit der Adresse &#8220;net.pipe://localhost/servicecontrol&#8221; erstellt. Zusätzlich erstellen wir auch noch einen Metadata-Endpunkt, damit uns Visual Studio im Client-Projekt schnell und einfach einen Service-Proxy erstellen kann.</p>
<p>Bevor ich jetzt zeige, wie die Klasse <em>ServiceControl</em>, also die Implementierung unseres WCF-Services aussieht, ersetzen wir in der <em>ScheduleHandler</em> &#8211; Methode (siehe weiter oben) das Schreiben in die Eventlog, durch einen Aufruf unseres WCF-Services (Singleton!), der eine Nachricht (z.B. eine Statusmeldung) an alle Clients veröffentlicht:</p>
<pre class="brush:csharp">//EventLog.WriteEntry(EventLogSource, "Tick", EventLogEntryType.Information);
ControlService.CurrentInstance.PublishMessage("Tick");</pre>
<h3>WCF Duplex Service</h3>
<p>Jetzt kommt der spannendere Teil&#8230; für die 2-Wege-Kommunikation brauchen wir einen sogenannten Duplex-Service, bei dem nicht nur der Client, sondern auch der Server eine Nachricht an den jeweils anderen schicken kann. Damit wird eigentlich ein Nachrichten-Pushing gemacht, d.h. der Server schickt immer dann &#8211; und nur dann &#8211; wenn er eine neue Nachricht hat, diese zu den Clients. Die schlechtere Alternative wäre hier einen normalen WCF-Dienst zu erstellen, wo der Client in einem kurzen Intervall <em>pollt</em> und den Server dabei nach neuen Nachrichten abfragt. Schlechter ist diese Variante deshalb, weil durch das ständige Aufrufen des Dienstes von dem Client unnötiger Overhead (Traffic) entsteht. Außerdem kommen die Nachrichten bei längeren polling-Intervallen (zugunsten eines verringerten Overheads) nur zeitverzögert am Client an.</p>
<p>Für die Umsetzung der Duplex-Kommunikation, bietet uns WCF das Konzept von Callback-Methoden, also Methoden, die vom Server aus auf dem Client aufgerufen werden. Damit der Server aber die entsprechenden Methoden am Client aufrufen kann um Nachrichten an diesen pushen, muss zunächst der Client eine Verbindung zum Server aufbauen und sich &#8220;subscriben&#8221;. Der Server speichert dann den CallbackChannel (also die Verbindung zum Client) in einer Liste ab, und kann dann bei Bedarf an alle Clients die Nachrichten schicken.</p>
<p>Aber erstmal langsam, hier die Interfaces für den Service-Contract:</p>
<pre class="brush:csharp">    [ServiceContract(CallbackContract = typeof(IControlServiceCallback))]
    public interface IControlService
    {
        [OperationContract]
        void Subscribe();

        [OperationContract]
        void Unsubscribe();
    }

    public interface IControlServiceCallback
    {
        [OperationContract(IsOneWay = true, AsyncPattern = true)]
        IAsyncResult BeginOnMessageReceived(string message, AsyncCallback acb, object state);
        void EndOnMessageReceived(IAsyncResult iar);
    }</pre>
<p>Das <em>IControlService</em> unterscheidet sich hier von einem &#8220;normalen&#8221; WCF-Service nur dadurch, dass wir auch gleich einen <em>CallbackContract</em> definieren. Im <em>IControlServiceCallback</em> definieren wir nur eine einzige Methode, die der Client implementierung muss. Diese ist hier asynchron ausgeführt und teilt sich somit in eine &#8220;Begin&#8230;&#8221; und eine &#8220;End&#8230;&#8221; &#8211; Methode. Der Grund warum hier eine asynchrone anstelle einer &#8220;normalen&#8221; Methode verwendet wird ist, dass dadurch der Server selbst die Callback-Methoden der Clients ansynchron ausführt. Das ist wichtig, denn wenn mehrere Clients verbunden sind, und der Server eine Nachricht an alle innerhalb einer Schleife &#8220;pusht&#8221;, dann würde ein einzelner Client mit einer fehlerhaften Verbindung den Aufruf an die nachfolgenden Clients verzögern (bis zum timeout, und das kann lang eingestellt sein!).</p>
<p>Als nächstes müssen wir das <em>IControlService</em> Interface am Server implementieren (<em>IControlServiceCallback</em> dann erst am Client). Hier einmal der ganze Code &#8211; Erklärungen dazu kommen darunter:</p>
<pre class="brush:csharp">    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class ControlService : IControlService
    {
        // returns the singleton-instance
        public static ControlService CurrentInstance { get; private set; }

        // holds the channels to all currently connected callbacks (=clients)
        private volatile IDictionary&lt;string, IControlServiceCallback&gt; connectedClients;

        // lock-object to synchronize between multiple concurrent threads
        private object syncRoot;

        public ControlService()
        {
            if (CurrentInstance != null)
                throw new Exception("This service-class is intended to be instatiated only once!");
            CurrentInstance = this;

            syncRoot = new object();
            connectedClients = new Dictionary&lt;string, IControlServiceCallback&gt;();
        }

        public void Subscribe()
        {
            // get the callback-channel to the client that called this method
            var callbackChannel = OperationContext.Current.GetCallbackChannel&lt;IControlServiceCallback&gt;();
            string sessionId = OperationContext.Current.Channel.SessionId;

            // store it for later use (to push messages)
            lock (syncRoot)
            {
                // make sure, that we don't add the same session twice (e.g. the client tries to subscribe multiple times)
                if (!connectedClients.ContainsKey(sessionId))
                {
                    connectedClients.Add(sessionId, callbackChannel);

                    // register for error-events of the current channel
                    OperationContext.Current.Channel.Closing += new EventHandler(Channel_Closing);
                    OperationContext.Current.Channel.Faulted += new EventHandler(Channel_Faulted);
                }
            }
        }

        public void Unsubscribe()
        {
            DisconnectClient(OperationContext.Current.Channel.SessionId);
        }

        void Channel_Faulted(object sender, EventArgs e)
        {
            var channel = sender as IContextChannel;
            if (channel != null)
                DisconnectClient(channel.SessionId);
        }

        void Channel_Closing(object sender, EventArgs e)
        {
            var channel = sender as IContextChannel;
            if (channel != null)
                DisconnectClient(channel.SessionId);
        }

        private void DisconnectClient(string sessionId)
        {
            // remove the session
            lock (syncRoot)
            {
                if (connectedClients.ContainsKey(sessionId))
                {
                    connectedClients.Remove(sessionId);
                }
            }
        }

        public void PublishMessage(string message)
        {
            lock (syncRoot)
            {
                // iterate through all connected clients and push message to each of them
                foreach (var callbackChannel in connectedClients.Values)
                {
                    // call the callback-method asynchronously, so that a leaking connection to one of the clients does not affect this loop
                    var asyncResult = callbackChannel.BeginOnMessageReceived(message, new AsyncCallback(OnPushMessageComplete), callbackChannel);
                    if (asyncResult.CompletedSynchronously)
                        CompletePushMessage(asyncResult);
                }
            }
        }

        void OnPushMessageComplete(IAsyncResult asyncResult)
        {
            CompletePushMessage(asyncResult);
        }

        void CompletePushMessage(IAsyncResult asyncResult)
        {
            var callbackChannel = (IControlServiceCallback)asyncResult.AsyncState;
            try
            {
                callbackChannel.EndOnMessageReceived(asyncResult);
            }
            catch { }
        }

    }</pre>
<p>Ganz wichtiges Detail gleich zu Beginn ist folgendes:</p>
<pre class="brush:csharp">[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]</pre>
<p>Durch die Verwendung dieses InstanceContextMode erzwingen wir, dass das Service als Singleton ausgeführt, also nur ein einziges mal instantiiert wird. Das ist wichtig, denn in einem privaten Feld speichern wir die Liste der verbundenen Clients mit deren SessionId ab, die wir <em>PublishMessage</em> &#8211; Methode brauchen um die Callbacks der verbundenen Clients aufzurufen. Der Rest des Codes sollte selbsterklärend sein, bzw. aus den Kommentaren deutlich werden. Einzig dem <em>lock(syncRoot)</em> kommt noch eine besondere Bedeutung zu &#8211; Wir verwenden dieses um sicherzustellen, dass mehrere Threads nicht gleichzeitig das Dictionary der Clients verwenden. Zwar sind alle Collections des .NET &#8211; Frameworks an sich schon thread-safe, jedoch könnte es ohne dem expliziten locken zu Probleme kommen, wenn ein Thread gereade die foreach-Schleife beim Pushen durchläuft und gleichzeitig dem Dictionary hinzugefügt oder entfernt wird indem sich Clients an- oder abmelden.</p>
<h3>WPF Clientanwendung / Benutzeroberfläche für den Dienst</h3>
<p>Den Frontend habe ich in diesem Beispiel recht einfach gehalten. Er beinhaltet aber dennoch die wichtigsten Funktionen und sollte für seinen Zweck ausreichend sein:</p>
<p><img class="alignnone size-full wp-image-90" title="Service-Client Benutzeroberfläche" src="http://www.flexbit.at/blog/wp-content/uploads/2011/07/client.png" alt="" width="535" height="360" /></p>
<p>In der Textbox werden Zeile für Zeile die eingehenden Nachrichten vom Server angezeigt. Die Nachrichten werden aber erst empfangen, wenn der Client am Server (am Windows-Dienst) &#8220;angemeldet&#8221; ist.</p>
<p>Für die Umsetzung habe ich in diesem Beispiel WPF verwendet. In einem neuen WPF-Projekt müssen wir dazu zunächst eine ServiceReference hinzufügen und können dabei die Adresse &#8220;net.pipe://localhost&#8221; verwenden. Visual Studio erkennt dann automatisch den Metadata-Endpunkt des laufenden Dienstes (vorher bitte installieren und starten!) und generiert einen entsprechenden Proxy. Hier der Code-Behind des MainWindows:</p>
<pre class="brush:csharp">    public partial class MainWindow : Window
    {
        private ControlServiceClient controlService;

        public MainWindow()
        {
            InitializeComponent();

            // register event-handler
            this.btnSubschribe.Click += new RoutedEventHandler(btnSubschribe_Click);
            this.btnUnsubscribe.Click += new RoutedEventHandler(btnUnsubscribe_Click);

            // intialize callback
            var callback = new ControlServiceHandler();
            callback.OnMessageReceivedEvent += new ControlServiceHandler.MessageReceivedHandler(callback_OnMessageReceivedEvent);
            var callbackInstanceContext = new InstanceContext(callback);

            // create wcf-proxy
            controlService = new ControlServiceClient(callbackInstanceContext);
        }

        void btnSubschribe_Click(object sender, RoutedEventArgs e)
        {
            // subscribe to receive messages from the wcf-service
            controlService.Subscribe();
        }

        void btnUnsubscribe_Click(object sender, RoutedEventArgs e)
        {
            // unsubscribe from wcf-service
            controlService.Unsubscribe();
        }

        void callback_OnMessageReceivedEvent(string message)
        {
            Dispatcher.BeginInvoke((Action) (() =&gt;
                {
                    tbLog.AppendText(DateTime.Now.ToLongTimeString() + " " + message + Environment.NewLine);
                    tbLog.ScrollToEnd();
                }));
        }
    }

    [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
    public class ControlServiceHandler : IControlServiceCallback
    {
        public delegate void MessageReceivedHandler(string message);
        public event MessageReceivedHandler OnMessageReceivedEvent;

        public void OnMessageReceived(string message)
        {
            if (this.OnMessageReceivedEvent != null)
                this.OnMessageReceivedEvent(message);
        }
    }</pre>
<p>Interessant ist hier nur die Klasse <em>ControlServiceHandler</em>, die den CallbackContract des WCF-Service implementiert und somit die vom Server kommenden Nachrichten empfängt, sobald via <em>Subscribe</em> am Server angemeldet wurde. Hier sieht man auch schon, dass bei der Generierung des <em>IControlServiceCallback</em> am Client nur mehr eine Methode <em>OnMessageReceived</em> da ist, während im selben Interface am Server durch das <em>AsyncPattern</em> noch die beiden Methoden <em>BeginOnMessageReceived</em> und <em>EndMessageReceived</em> definiert wurden.</p>
<p>Ganz wichtig ist hier, dass <em>ConcurrencyMode.Reentrant</em> verwendet wird, und der WPF-eigene <em>SynchronizationContext</em> deaktiviert wurde! Letzterer ist der Grund für unzählige Posting auf <a title="Stackoverflow - Q&amp;A" href="http://www.stackoverflow.com" target="_blank">StackOverflow</a>, bei denen über &#8220;hängende&#8221; Benutzeroberflächen geklagt wird. Grund dafür ist, dass die Callback-Methode am Client in einem eigenen Thread ausgeführt wird und man die UI bekanntlich nur im UI-Thread ändern darf. Um dieses Problem zu vereinfachen hätte WPF diesen <em>SynchronizationContext</em> eingeführt um dem Programmierer den manuellen BeginInvoke-Aufruf zu ersparen, nur leider funktioniert der in vielen Situation nicht ordentlich. Deshalb verlassen wir uns hier besser auf die bekannten Methoden und verwenden im Event-Handler der MainWindow-Klasse <em>Dispatcher.BeginInvoke</em> um den WCF-Thread mit dem UI-Thread zu synchronisieren.</p>
<p>So, das war&#8217;s auch schon. Wir haben jetzt einen Windows-Dienst geschaffen und einen WPF-Client entwickelt, der die Nachrichten des Windows-Service empfängt und anzeigt. Das Beispielprogramm kann einfach erweitert werden, sodass der Client auch Befehle an den Dienst schicken kann oder z.B. auch über ein NetTcpBinding die Ausführung von mehreren Clients auf unterschiedlichen Computern im Netzwerk zulässt.</p>
<p>Den vollständigen Code zum Projekt gibt es <a href="http://www.flexbit.at/blog/wp-content/uploads/2011/07/ServiceGui.zip">hier zum Herunterladen</a>.</p>
<p>Ich hoffe mit diesem Beitrag dem einen oder anderen helfen zu können, und freue mich über Verbesserungsvorschläge und Tipps wie man meinen Code optimieren könnte!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.flexbit.at/blog/wcf-duplex-zwischen-windows-sevice-und-gui-frontend/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>GUI für Windows Service in .NET</title>
		<link>http://www.flexbit.at/blog/gui-fur-windows-service-in-net/</link>
		<comments>http://www.flexbit.at/blog/gui-fur-windows-service-in-net/#comments</comments>
		<pubDate>Sat, 09 Apr 2011 18:29:43 +0000</pubDate>
		<dc:creator>Daniel Lang</dc:creator>
				<category><![CDATA[Windows]]></category>
		<category><![CDATA[IPC]]></category>
		<category><![CDATA[Service]]></category>

		<guid isPermaLink="false">http://www.flexbit.at/blog/?p=48</guid>
		<description><![CDATA[Dieser Artikel beschreibt, welche Möglichkeiten es gibt um eine Benutzeroberfläche für einen Windows Dienst in .NET zu entwickeln. Die GUI soll dem Anwender Log-Meldungen vom Service in Echtzeit darstellen und gleichzeitig Steuerbefehle an den Service schicken können. Die vielen unterschiedlichen Möglichkeiten zur Inter-Process-Communication (IPC) zwischen Service- und GUI-Applikation werden kurz und einfach erklärt. Hintergrund Bei einem aktuellen Projekt verwenden wir einen Windows Service um im Hintergrund Daten zwischen einem Warenwirtschaftssystem und Magento zu synchronisieren. Dieser Vorgang wird in einem Intervall von 10 Minuten automatisch ausgeführt. Während einer Synchronisation werden hunderte Log-Meldungen erzeugt, die vom Dienst zunächst zwischengespeichert und am Ende [...]]]></description>
			<content:encoded><![CDATA[<p>Dieser Artikel beschreibt, welche Möglichkeiten es gibt um<strong> eine Benutzeroberfläche für einen Windows Dienst in .NET</strong> zu entwickeln. Die GUI soll dem Anwender <strong>Log-Meldungen</strong> vom Service in Echtzeit darstellen und gleichzeitig <strong>Steuerbefehle </strong>an den Service schicken können. Die vielen unterschiedlichen Möglichkeiten zur<strong> Inter-Process-Communication (IPC)</strong> zwischen Service- und GUI-Applikation werden kurz und einfach erklärt.</p>
<h3><span id="more-48"></span>Hintergrund</h3>
<p>Bei einem aktuellen Projekt verwenden wir einen Windows Service um im Hintergrund Daten zwischen einem Warenwirtschaftssystem und Magento zu synchronisieren. Dieser Vorgang wird in einem Intervall von 10 Minuten automatisch ausgeführt. Während einer Synchronisation werden hunderte Log-Meldungen erzeugt, die vom Dienst zunächst zwischengespeichert und am Ende der Synchronisation zusammengefasst in die EventLog geschrieben werden. Nachteil dabei ist, dass man während einer Synchronisation nicht live verfolgen kann, was der Dienst gerade macht und erst am Ende die fertige Rechnung präsentiert bekommt. Gleichzeitig soll es zukünftig auch möglich sein, einfache Befehle an den Dienst zu schicken, um etwa damit eine Synchronisation manuell anzustoßen oder den Cache zu leeren.</p>
<h3>Anforderungen</h3>
<p>Ziel ist es, eine WPF-Anwendung zu erstellen die in einem Textfenster die einzelnen Log-Meldungen &#8220;live&#8221; anzeigt und gleichzeitig eine einfache Steuerung des Dienstes ermöglicht. Für unseren Anwendungsfall ist es ausreichend, dass die Anwendung lokal auf der selben Maschine läuft, auf der auch der Windows-Dienst installiert ist. Für zukünftige Weiterentwicklungen wäre es allerdings wünschenswert, wenn die Anwendung auch von einem anderen PC aus ausgeführt werden kann. Die Performance der Applikation spielt dabei keine Rolle, das heisst auch mehrere Sekunden Zeitverzögerung bis zur Anzeige der Log-Meldungen sind tolerierbar.</p>
<h3>Recherche</h3>
<p>Zu Beginn habe ich gedacht, dass diese Aufgabe ziemlich trivial sei, besonders auch deshalb weil ich zig verschiedene Anwendungen kenne und verwende, die genau das selbe machen. Ich hatte angenommen, Microsoft hätte uns sicherlich schon ein fertiges Konzept bzw. ein einfach zu nutzendes Framework für genau eben diese Anforderung zur Verfügung gestellt. Stattdessen gibt es eine Fülle unterschiedlichster Möglichkeiten und Technologien um Inter-Process-Communication zwischen dem Windows-Dienst und WPF-Anwendung zu implementieren. Auch in den spärlichen Foren-Beiträgen und Blogs gehen die Meinungen zu diesen Varianten weit auseinander. Ist für einige WCF die erste Wahl, so geht für andere nichts über Named Pipes über ein eigenes Protokoll/Kontrakt.</p>
<p>Nachdem sich die Recherche für mich sehr mühsam und langwierig gestaltet hat, versuche ich mit diesem Artikel die Lücke zu schließen, und einen Überblick über die verschiedenen Möglichkeiten zu geben. In einem weiteren Artikel werde ich dann näher auf die Umsetzung mit einer der vorgestellten Methoden eingehen. Bitte verzeiht mir, dass ich die Pros und Kontras nach unseren eigenen Anforderungen erstellt habe und daher für diese keinen Anspruch an allgemeingültige Objektivität erhebe.</p>
<p>Auf folgende Möglichkeiten werde ich kurz eingehen:</p>
<ul>
<li>Microsoft Message Queuing (MSMQ)</li>
<li>Shared Memory</li>
<li>Named Pipes</li>
<li>Remoting</li>
<li>WCF</li>
<li>Logfiles</li>
</ul>
<h3>Microsoft Message Queuing (MSMQ)</h3>
<p>MSMQ ist ein Service-Bus und ermöglicht IPC zwischen unterschiedlichen Anwendungen auch über Systemgrenzen hinweg. MSMQ wird dabei als eigener Dienst ausgeführt und bietet den Teilnehmern die Möglichkeit asynchron Nachrichten zu senden und empfangen. Das Protokoll ist grundsätzlich &#8211; ähnlich wie das Versenden einer E-Mail &#8211; für die Einwegkommunikation konzipiert (entsprechende Kontrakte auf Applikationsebene können natürlich selbst erstellt werden). Es gilt als sehr robust und zuverlässig und eignet sich daher auch für komplexe Enterprise-Systeme. Obwohl es bei Windows 7 standardmäßig mitgeliefert wird, ist eine manuelle Installation des Features notwendig.</p>
<ul class="procontra">
<li class="pro">Nachrichten gehen nicht verloren auch wenn kein Client verbunden ist</li>
<li class="pro">Sehr zuverlässig und robust</li>
<li class="con">Grundsätzlich ein OneWay-Konzept, obwohl man Duplex-Kommunikation &#8220;bauen&#8221; kann (siehe <a href="http://www.codeproject.com/KB/WCF/duplexmsmq.aspx" target="_blank">hier</a>)</li>
<li class="con">Manuelle Installation des Dienstes notwendig</li>
</ul>
<p>&nbsp;</p>
<h3>Shared Memory</h3>
<p>Das Prinzip hinter Shared Memory ist im Grunde ziemlich simpel &#8211; zwei Prozesse teilen sich einen gemeinsamen Speicherbereich. In diesem Speicherbereich können dann sowohl der Windows-Dienst als auch die GUI-Applikation lesen und schreiben, wobei mit entsprechenden Locks darauf zu achten ist, dass nicht gleichzeitig darauf zugegriffen wird. Dank eines Posts im <a href="http://dotnet-forum.de/" target="_blank">dotnet-forum</a> bin ich auf den Blog von Klaus Bock aufmerksam geworden, der beschreibt wie man<a href="http://blog.klaus-b.net/post/2008/07/06/Shared-Memory-in-verwaltetem-Code.aspx" target="_blank"> Shared Memory in verwaltetem Code</a> verwendet. Seit .NET 4 hat sich der dafür notwendige Code dramatisch reduziert, und <a href="http://msdn.microsoft.com/en-us/magazine/ee428166.aspx" target="_blank">MemoryMappedFiles</a> werden jetzt standardmäßig vom Framework unterstützt.</p>
<ul class="procontra">
<li class="pro">Extrem schnelle Kommunikation</li>
<li class="pro">Seit .NET 4 relativ einfach zu verwenden</li>
<li class="con">Kontrakt zur Duplex-Kommunikation muss auf Applikationsebene erstellt werden</li>
<li class="con">Funktioniert nur auf demselben System</li>
</ul>
<p>&nbsp;</p>
<h3>Named Pipes</h3>
<p>Eine NamedPipe ist ein &#8220;Kanal&#8221; zur Kommunikation zwischen zwei Prozessen auf demselben System war noch vor wenigen Jahren die Standardtechnik um zwischen Service und GUI zu kommunizieren. Obwohl es grundsätzlich ein Server-Client-Prinzip ist, kann &#8211; sobald der Kanal aufgebaut ist &#8211; eine Kommunikation in beide Richtungen stattfinden, ähnlich dem TcpServer und TcpClient unter .NET. So wie bei der SharedMemory-Methode muss aber auch hier der Duplex-Kontrakt auf Applikationsebene selbst gebaut werden. <a href="http://msdn.microsoft.com/en-us/library/aa365590%28v=vs.85%29.aspx" target="_blank">Hier</a> ist das Prinzip besser erklärt.</p>
<ul class="procontra">
<li class="pro">Seit .NET 3.5 sehr einfach zu verwenden (siehe <a href="http://www.switchonthecode.com/tutorials/dotnet-35-adds-named-pipes-support" target="_blank">hier</a>)</li>
<li class="pro">Sehr schnelle Kommunikation</li>
<li class="con">Kontrakt zur Duplex-Kommunikation muss auf Applikationsebene erstellt werden</li>
<li class="con">Funktioniert nur auf demselben System</li>
</ul>
<p>&nbsp;</p>
<h3>.NET Remoting</h3>
<p>Remoting war unter .NET die bevorzugte Technologie um über Systemgrenzen hinweg zwischen zwei Prozessen zu kommunizieren. Die Funktionsweise ist dabei ähnlich dem eines Webservice, d.h. die Daten werden serialisiert und per XML übermittelt. Beide Seiten müssen dabei .NET verwenden und jeweils eine Kopie einer &#8220;geteilten&#8221; Klassenbibliothek haben, die das sogenannte RemoteObject beinhaltet. Letzteres ist eine Klasse die von MarshalByRefObject ableiten muss und dann zur Kommunikation verwendet wird. Das Framework erstellt dabei für die Applikation intransparent die Proxy-Klasse, sodass das RemoteObject in der Consumer-Applikation (hier die GUI-Anwendung) wie ein lokales Objekt verwendet werden kann. Remoting wurde mit dem .NET Framework 3.0 durch WCF abgelöst und wird zwar weiterhin unterstützt, jedoch nicht mehr von Microsoft empfohlen und weiterentwickelt.</p>
<ul class="procontra">
<li class="pro">Einfach zu implementieren</li>
<li class="pro">Einfache Duplex-Kommunikation (über Rückgabewerte von Methoden)</li>
<li class="pro">Kann sowohl auf TCP-Ebene als auch über Http betrieben werden (Endpunkte können über das Internet verbunden werden)</li>
<li class="con">Von Microsoft nicht mehr empfohlen / weiterentwickelt</li>
<li class="con">Eng gekoppelte objektorientierte Architektur (keine SOA, beide Anwendung teilen sich eine Klasse oder ein Interface)</li>
</ul>
<p>&nbsp;</p>
<h3>Windows Communication Framework (WCF)</h3>
<p>WCF ist seit Version 3.0 Bestandteil des .NET Frameworks und ist als allgemeines Framework zur Kommunikation zwischen verschiedenen Endpunkten gedacht. Durch das Konzept der Bindings ist es möglich mehrere Transportwege gleichzeitig zur Verfügung zu stellen (Webservice-Binding, NamedPipe-Binding, binäres Binding über Tcp, etc.). Für alle relevanten Transportwegen (lokal und über http) sind Bindings mit Duplex-Kontrakten verfügbar, sodass über das Konzept der Callback-Funktionen eine einfachste Zwei-Wege-Kommunikation möglich ist.</p>
<ul class="procontra">
<li class="pro">Bevorzugtes Framework von Microsoft (daher zukunftssicher)</li>
<li class="pro">Einfache TwoWay-Kommunikation</li>
<li class="pro">Verschiedene Bindings möglich (z.B. lokal über TCP; WAN über http)</li>
<li class="con">Etwas geringere Performance gegenüber SharedMemory (für uns nicht relevant)</li>
</ul>
<p>&nbsp;</p>
<h3>Logfiles</h3>
<p>Der Vollständigkeit halber, möchte ich auch auf die wahrscheinlich simpelste Variante eingehen &#8211; die Kommunikation über Textdateien. Die Idee dahinter ist, dass der Service seine Logmeldungen in eine Textdatei einzeln hinzufügt und gleichzeitig die GUI-Anwendung in einem kurzen Intervall die Datei liest und dessen Inhalt parst. Sogar der Rückweg ließe sich über eine zweite Textdatei in umgekehrter Reihenfolge realisieren. In der Praxis stellt diese Methode allerdings für uns keine echte Alternative dar.</p>
<ul class="procontra">
<li class="pro">Extrem einfach zu implementieren</li>
<li class="con">Schlechte performance durch große Anzahl an IO-Operationen</li>
<li class="con">Fehleranfällig (es muss sichergestellt werden, dass die Datei direkt nach dem Schreiben wieder geschlossen wird, damit sich die Prozesse nicht gegenseitig blockieren)</li>
<li class="con">usw.</li>
</ul>
<p>&nbsp;</p>
<h3>Fazit</h3>
<p>Nachdem ich nun alle möglichen Varianten auf dem Tisch hatte fiel die Entscheidung recht eindeutig auf WCF. Einerseits haben wir bereits einiges an Erfahrung mit WCF / Webservices und auch bei einem Projekt bereits einen Duplex-Contract mit einem NetTcpBinding eingesetzt, andererseits hat man mit WCF ein sehr stabiles und robutes Framework und muss sich um keine low-level-Details wie bei SharedMemory oder NamedPipes kümmern.</p>
<p>In den nächsten Tagen werde ich hier in einem weiteren Artikel beschreiben, wie wir schließlich die Kommunikation zwischen Service und GUI-Anwendung mit WCF realisiert haben und auch etwas Beispielcode liefern.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.flexbit.at/blog/gui-fur-windows-service-in-net/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>ASP.NET 4 Child Application unter ASP.NET 3.5</title>
		<link>http://www.flexbit.at/blog/asp-net-4-child-application-unter-asp-net-3-5/</link>
		<comments>http://www.flexbit.at/blog/asp-net-4-child-application-unter-asp-net-3-5/#comments</comments>
		<pubDate>Sun, 27 Mar 2011 16:57:42 +0000</pubDate>
		<dc:creator>Daniel Lang</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[IIS]]></category>

		<guid isPermaLink="false">http://www.flexbit.at/blog/?p=6</guid>
		<description><![CDATA[Hat man eine bestehende Seite mit ASP.NET 2 oder 3.5 und möchte darunter eine Virtual Application auf Basis von ASP.NET 4 betreiben bekommt man schnell Probleme. Grund dafür ist die Vererbung der web.config auf die untergeordneten virtuellen Anwendungen. In diesem Artikel beschreibe ich wie man das Problem löst und erfolgreich eine ASP.NET 4 Sub-Application unter einer ASP.NET 3.5 Seite betreiben kann. Szenario Für unsere Firmenwebseite verwenden wir das CMS-System Sitefinity auf Basis von ASP.NET 3.5. Im Moment bin ich dabei ein Unterverzeichnis /produkte zu erstellen, das wir zukünftig verwenden möchten um einige Tools und Anwendungen online zu verkaufen. Aus unterschiedlichsten [...]]]></description>
			<content:encoded><![CDATA[<p>Hat man eine bestehende Seite mit ASP.NET 2 oder 3.5 und möchte darunter eine Virtual Application auf Basis von ASP.NET 4 betreiben bekommt man schnell Probleme. Grund dafür ist die Vererbung der web.config auf die untergeordneten virtuellen Anwendungen. In diesem Artikel beschreibe ich wie man das Problem löst und erfolgreich eine ASP.NET 4 Sub-Application unter einer ASP.NET 3.5 Seite betreiben kann.</p>
<h3><span id="more-6"></span>Szenario</h3>
<p>Für unsere Firmenwebseite verwenden wir das CMS-System <a title="Sitefinity" href="http://www.sitefinity.com/" target="_blank">Sitefinity</a> auf Basis von ASP.NET 3.5. Im Moment bin ich dabei ein Unterverzeichnis /produkte zu erstellen, das wir zukünftig verwenden möchten um einige Tools und Anwendungen online zu verkaufen. Aus unterschiedlichsten Gründen haben wir uns für den Einsatz von ASP.NET MVC 3 mit der Razor-ViewEngine entschieden. Selbstverständlich läuft das Ganze mit ASP.NET 4. Im Grunde genommen eine einfache Aufgabe würde man meinen &#8211; im IIS-Manager eine virtuellen Anwendung hinzufügen, einen Anwendungspool mit v4.0 zuweisen und fertig. Die Ernüchterung kam dann gleich beim ersten Versuch die Anwendung in der Testumgebung zu starten:</p>
<blockquote><p>Der &#8220;system.web.extensions/scripting/scriptResourceHandler&#8221;-Abschnitt wurde doppelt definiert.</p></blockquote>
<p>&#8220;Doppelt definiert&#8221; ist einfach verständlich war mein Gedanke&#8230; nur leider ließ sich der beklagte Abschnitt nirgendswo in der web.config der Child Application finden. Nach kurzer Denkpause kam mir aber dann die Erinnerung an die machine.config, die sich irgendwo im Installationsverzeichnis vom .NET Framework befinden müsste und von der alle web.configs implizit erben. Eine kurze Google-Suche hat mir dann auch den genauen Pfad verraten: <em>C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config</em>. Als gelernte ASP.NETler wissen wir, dass diese config als &#8220;Basis&#8221; für alle web.configs verwendet wird und am Ende eine einzige &#8220;verschmelzte&#8221; Konfigurationsdatei herauskommt die dann von der Runtime verwendet wird. Und tatsächlich &#8211; in dieser machine.config fand sich eine Zeile <em>&lt;section name=&#8221;scriptResourceHandler&#8221;&#8230;</em> somit hatte ich den doppelten Eintrag gefunden.</p>
<h3>Lösung / Teil 1</h3>
<p>Nun da ich das Problem kann, versuchte die ersten spärlichen Tipps aus dem Internet zu verwerten. Diese gingen von einem &lt;clear /&gt; in der web.config der Child Application bis zu einem &lt;location path=&#8221;.&#8221;&gt; in der config der Hauptseite &#8211; alles vergebens. Irgendwann fand ich schließlich den entscheidenen Hinweis hier: <a href="http://www.asp.net/learn/whitepapers/aspnet4/breaking-changes#0.1__Toc256770150" target="_blank">ASP.NET 4 Breaking Changes</a><br />
Die Lösung war dann wieder einmal einfacher als gedacht &#8211; Man nimmt den gesamten Bereich <em>&lt;configSections&gt;</em> aus der web.config der Hautpseite (ASP.NET 3.5) heraus und gibt ihn stattdessen in die globale web.config, die sich auf einem 64Bit-System hier befindet: <em>C:\Windows\Microsoft.NET\Framework64\v2.0.50727\web.config</em>. Diese wird also in der Hierarchie der config-Dateien beim Kompilieren der Child Application mit v4 ignoriert und man hat somit auch keinen doppelten Eintrag mehr!</p>
<p>Nach der anfänglichen Freude endlich dieses Problem gelöst zu haben, machte sich aber wieder die Ernüchterung breit, denn der nächste Fehler wartete schon:</p>
<blockquote><p>The value for the &#8216;compilerVersion&#8217; attribute in the provider options must be &#8216;v4.0&#8242; or later if you are compiling for version 4.0 or later of the .NET Framework. To compile this Web application for version 3.5 or earlier of the .NET Framework, remove the &#8216;targetFramework&#8217; attribute from the &lt;compilation&gt; element of the Web.config file.</p></blockquote>
<p>Irgendwie auch wieder verständlich, denn in der web.config der Hauptseite befand sich die Zeile <em>&lt;providerOption name=&#8221;CompilerVersion&#8221; value=&#8221;v3.5&#8243;/&gt;</em>. Damit wurde der Runtime klar gemacht, dass wir die ASP.NET 3.5 wollen. Die Einstellung wird in die Child Application vererbt und dort haben wir aber ASP.NET 4. Wie kann ich also verhindern, dass diese Einstellung an die Child Application vererbt wird?</p>
<h3>Lösung / Teil 2</h3>
<p>Um zu verhindern, dass einzelne Einstellungen einer web.config in die Child Applications vererbt werden, kann man die betreffende Einstellung folgendermaßen verpacken:</p>
<pre class="brush:xml">&lt;location path="." inheritInChildApplications="false"&gt;
  &lt;!-- Einstellung die nicht vererbt werden soll --&gt;
&lt;/location&gt;</pre>
<p>Damit bleibt diese Einstellung in der web.config und wird nicht an die Child-Application vererbt. ACHTUNG: Dieser &#8220;Trick&#8221; funktioniert nicht mit allen Elementen einer web.config &#8211; <em>&lt;configSections&gt;</em> hätten wir auf diese Art nicht verpacken können!</p>
<p>Nachdem ich also den gesamten Bereich <em>&lt;system.codedom&gt;</em> per <em>&lt;location &#8230;&gt;</em> davon hinderte sich zu vererben, war dieses Problem gelöst. Wie erwartet kam aber auch schon das nächste, dieses Mal ein altbekannte Fehlermeldung:</p>
<blockquote><p>Die Datei oder Assembly &#8220;assemblyName&#8221; oder eine Abhängigkeit davon wurde nicht gefunden</p></blockquote>
<p>Dabei beziehte sich <em>assemblyName </em>auf einen selbstgebauten HttpHandler, der in der Hauptseite mit ASP.NET 3.5 verwendet wurde. Natürlich war die entsprechende dll-Datei nicht im <em>bin</em>-Ordner der Child-Application vorhanden.</p>
<h3>Lösung / Teil 3</h3>
<p>Ich musste verhindern, dass auch diese Abhängigkeit von der Hauptseite zur Child Application vererbt wird. Die Vorgangsweise per <em>interhitInChildApplications=&#8221;false&#8221;</em> kannte ich bereits. Als danach allerdings schon die nächste Abhängigkeit Probleme verursachte hatte ich endlich den Mut, den gesamten Bereich &lt;system.webServer&gt; zu verpacken und konnte damit schließlich das Problem lösen:</p>
<pre class="brush:xml">&lt;location path="." inheritInChildApplications="false"&gt;
  &lt;system.webServer&gt;
    &lt;!-- ... --&gt;
  &lt;/system.webServer&gt;
&lt;/location&gt;</pre>
<p>Damit war sichergestellt, dass alle Einstellungen der Hauptseite auch dort bleiben und meine Child Application mit ASP.NET 4 hat endlich funktioniert!<br />
Ich finde es immer wieder spannend, wieviel Zeit und Nerven solche scheinbar einfachen Aufgaben plötzlich verursachen können und hoffe mit diesem Beitrag auch anderen zu helfen, die vor ähnlichen Aufgaben stehen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.flexbit.at/blog/asp-net-4-child-application-unter-asp-net-3-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

