Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to notify a client from wf4-wcf-server asynchronously?
    text
    copied!<p>during the last days I spent a lot of time to find a solution on how to send simple messages from a workflow (WF4)-server to a client (in my case WPF).</p> <p>There exist some examples how to reply on a request (via callback), but I can not find any example how to contact the client asynchronously.</p> <p>I want to be able to have a communication like this:</p> <ul> <li>[8:00 am] Client: "Hello Server, this is my request. Please start your workflow 'MakeCoffee' using this recipe.". </li> <li>[8:01 am] WF-Server: "Hello Client, I'm on it." </li> <li>[8:05 am] WF-Server: "I can't find any coffee. I will buy some."</li> <li>[8:10 am] WF-Server: "I am boiling the water." </li> <li>[8:15 am] WF-Server: "Do you want sugar?"</li> <li>[8:17 am] Client: "Yes." </li> <li>[8:18 am] WF-Server: "I am done."</li> </ul> <p>Until now, I found these solutions:</p> <h2>1. WCF - Service with CallBack-Channel</h2> <p><a href="https://stackoverflow.com/questions/5739501/how-can-a-wcf-service-raise-events-to-its-clients">This example</a> seems to be pretty cool, but I do not see how to use this with my Workflow-Service - for there is no "implementing service" class. Everything is visual, so I can not apply the "SubscribeClient"-method (or at least I do not know where to place the service implementation).</p> <h2>2. Workflow with notifying events</h2> <p><a href="http://code.msdn.microsoft.com/windowsdesktop/Windows-Workflow-eaa24bdb#content" rel="nofollow noreferrer">This example</a> is a nice solution - but (for my understanding) this does not work with a separate workflow-server - it seems to require that the workflow-server and the client are the same.</p> <h2>3. Accessing OperationContext</h2> <p><a href="http://msdn.microsoft.com/en-us/library/ee834517.aspx" rel="nofollow noreferrer">This example</a> creates a WorkflowServiceHost on client-side, but it is not very easy to handle and I can't adjust it to my requirements.</p> <p><strong>Does anyone know a handy solution/pattern on how to send messages from a (separate) workflow-server to a client?</strong> The client does not know, when the server might send him messages and how many it will be.</p> <p>I am kind of new to WF4 and would be very thankful for every hint/advise/idea.</p> <p>Thanks in advance,</p> <p>Timo</p> <h1>UPDATE</h1> <p>According to the comment from Maurice, I tried to use a simple service in my client, but unfortunately, my client does not receive and show any of the messages.</p> <p>This is my client-code:</p> <pre class="lang-cs prettyprint-override"><code>public partial class MainWindow : Window { private ServiceHost _serviceHost; private void Window_Loaded(object sender, RoutedEventArgs e) { ApplicationInterface._app = this; //prepare the serviceHost string clientAddress = "http://localhost:8000/ClientService"; System.ServiceModel.Channels.Binding bBinding = new BasicHttpBinding(); _serviceHost.AddServiceEndpoint(typeof(IClientService), bBinding, clientAddress); _serviceHost.Open(); } public ListBox GetEventListBox() { return this.lstEvents; } } </code></pre> <p>This is my IClientService-Interface:</p> <pre class="lang-cs prettyprint-override"><code>[ServiceContract] public interface IClientService { [OperationContract(IsOneWay=true)] void MeldeStatus(String statusText); } </code></pre> <p>This is the implementation of the IClientService-Interface:</p> <pre class="lang-cs prettyprint-override"><code>public class ClientService : IClientService { public void MeldeStatus(string statusText) { ApplicationInterface.AddEvent(statusText); } } </code></pre> <p>This is the static ApplicationInterface:</p> <pre class="lang-cs prettyprint-override"><code>public static class ApplicationInterface { public static MainWindow _app { get; set; } public static void AddEvent(String eventText) { if (_app != null) { new ListBoxTextWriter(_app.GetEventListBox()).WriteLine(eventText); } } } </code></pre> <p>And this the ListBoxTextWriter-class, which should add the messages to a given ListBox:</p> <pre class="lang-cs prettyprint-override"><code>public class ListBoxTextWriter : TextWriter { const string textClosed = "This TextWriter must be opened before use"; private Encoding _encoding; private bool _isOpen = false; private ListBox _listBox; public ListBoxTextWriter() { // Get the static list box _listBox = ApplicationInterface._app.GetEventListBox(); if (_listBox != null) _isOpen = true; } public ListBoxTextWriter(ListBox listBox) { this._listBox = listBox; this._isOpen = true; } public override Encoding Encoding { get { if (_encoding == null) { _encoding = new UnicodeEncoding(false, false); } return _encoding; } } public override void Close() { this.Dispose(true); } protected override void Dispose(bool disposing) { this._isOpen = false; base.Dispose(disposing); } public override string ToString() { return ""; } public override void Write(char value) { if (!this._isOpen) throw new ApplicationException(textClosed); ; this._listBox.Dispatcher.BeginInvoke (new Action(() =&gt; this._listBox.Items.Add(value.ToString()))); } public override void Write(string value) { if (!this._isOpen) throw new ApplicationException(textClosed); ; if (value != null) this._listBox.Dispatcher.BeginInvoke (new Action(() =&gt; this._listBox.Items.Add(value))); } public override void Write(char[] buffer, int index, int count) { String toAdd = ""; if (!this._isOpen) throw new ApplicationException(textClosed); ; if (buffer == null || index &lt; 0 || count &lt; 0) throw new ArgumentOutOfRangeException("buffer"); if ((buffer.Length - index) &lt; count) throw new ArgumentException("The buffer is too small"); for (int i = 0; i &lt; count; i++) toAdd += buffer[i]; this._listBox.Dispatcher.BeginInvoke (new Action(() =&gt; this._listBox.Items.Add(toAdd))); } } </code></pre> <p>My WF-Server uses this Send-Activity:</p> <pre class="lang-html prettyprint-override"><code>&lt;Send Action="MeldeStatus" EndpointConfigurationName="BasicHttpBinding_Client" sap:VirtualizedContainerService.HintSize="255,90" OperationName="MeldeStatus" ProtectionLevel="None" ServiceContractName="p:IClientService"&gt; &lt;SendParametersContent&gt; &lt;p1:InArgument x:TypeArguments="x:String" x:Key="statusText"&gt;Yes, it works.&lt;/p1:InArgument&gt; &lt;/SendParametersContent&gt; &lt;/Send&gt; </code></pre> <p>This is the configuration of my endpoint at the WF-server:</p> <pre class="lang-html prettyprint-override"><code>&lt;system.serviceModel&gt; &lt;bindings&gt; &lt;basicHttpBinding&gt; &lt;binding name="DefaultHTTPBinding" allowCookies="true" /&gt; &lt;/basicHttpBinding&gt; &lt;/bindings&gt; &lt;behaviors&gt; &lt;serviceBehaviors&gt; &lt;behavior&gt; &lt;serviceMetadata httpGetEnabled="true"/&gt; &lt;serviceDebug includeExceptionDetailInFaults="true"/&gt; &lt;/behavior&gt; &lt;/serviceBehaviors&gt; &lt;/behaviors&gt; &lt;services&gt; &lt;service name="WFServer.ReklamationErfassen"&gt; &lt;endpoint address="http://localhost:7812/ReklamationErfassen.xamlx" binding="basicHttpBinding" bindingConfiguration="DefaultHTTPBinding" contract="IReklamationService" /&gt; &lt;/service&gt; &lt;/services&gt; &lt;client&gt; &lt;endpoint address="http://localhost:8000/ClientService" binding="basicHttpBinding" bindingConfiguration="DefaultHTTPBinding" contract="IClientService" name="BasicHttpBinding_Client" /&gt; &lt;/client&gt; &lt;/system.serviceModel&gt; &lt;system.webServer&gt; &lt;modules runAllManagedModulesForAllRequests="true"/&gt; &lt;/system.webServer&gt; </code></pre> <p>I do not get any messages, error or warnings - can somebody please have a quick check on the given code?</p> <p>Thanks again,<br> Timo</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload