Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In dieser Aufgabe wird die Kommunikation zwischen dem Client und dem Host mithilfe eines WCF-Vertrags aktiviert. Die Hostanwendung ruft einen Vorgang auf dem Client auf, der den Clientworkflow startet und ihn mit einem Startwert initialisiert.
Anstatt einen weiteren WCF-Vertrag über eine neue Schnittstelle zu erstellen, erfahren Sie in dieser Aufgabe, wie ein WCF-Vertrag programmgesteuert mit der Workflow-zuerst-Methode erstellt wird.
Tipp
Wird der Workflow-Designer von Visual Studio zum Erstellen oder Verwalten von Workflowdiensten verwendet, werden dadurch gelegentlich unechte Validierungsfehler verursacht. Falls Sie das Projekt erfolgreich erstellen können, ignorieren Sie die Auswertungsfehler.
Prozeduren
So erstellen Sie den lokalen Hostkommunikationsvertrag:
Hinweis Wird der Workflow-Designer von Visual Studio zum Erstellen oder Verwalten von Workflowdiensten verwendet, werden dadurch gelegentlich unechte Prüfungsfehler verursacht. Falls Sie das Projekt erfolgreich erstellen können, ignorieren Sie die Auswertungsfehler.
Öffnen Sie die WorkflowServiceTutorial-Projektmappe.
Öffnen Sie im WorkflowServiceClient-Projektknoten den Workflow-Designer für dieses Projekt.
Ziehen Sie eine ReceiveActivity-Aktivität zum Designer, und legen Sie sie über der ersten SendActivity-Aktivität ab, damit die ReceiveActivity-Aktivität zuerst im im Workflow ausgeführt wird.
Mit dieser Aktivität wird der im lokalen Hostkommunikationsvertrag definierte Vorgang implementiert.
Wählen Sie die ReceiveActivity-Aktivität, und klicken Sie im Bereich Eigenschaften unter ServiceOperationInfo auf die Ellipse, um das Dialogfeld Vorgang auswählen zu öffnen.
Sie definieren einen neuen Vertrag mithilfe des Workflow-zuerst-Erstellungsformats. Klicken Sie dazu oben rechts auf Vertrag hinzufügen, und markieren Sie Contract1.
Nennen Sie den Vertrag im Textfeld für den Vertragsnamen ILocalHostContract.
Markieren Sie den ersten Vorgang unter ILocalHostContract, und benennen Sie ihn in StartClientWorkflow um.
Klicken Sie auf der Registerkarte Parameter auf das Hinzufügesymbol, und fügen Sie einen neuen Parameter mit der Bezeichnung initialValue vom Typ Int32 mit der Richtung Eingehend hinzu, und klicken Sie auf OK.
Wählen Sie die ReceiveActivity-Aktivität aus, und stellen Sie im Bereich Eigenschaften initialValue eine Bindung zum inputValue der globalen Variable her.
Legen Sie im Bereich Eigenschaften die CanCreateInstance-Eigenschaft auf True fest.
Ein neuer Vertrag mit der Bezeichnung ILocalHostContract wird nun programmgesteuert für Sie definiert, doch es müssen einige Dateien geändert werden, bevor dieser Vertrag mit dem Workflowdienst interagieren kann.
Öffnen Sie im WorkflowServiceClient-Projekt App.config.
Fügen Sie den folgenden Konfigurationsknoten hinzu:
<services> <service name="WorkflowServiceClient.ClientWorkflow" behaviorConfiguration="WorkflowServiceClient.ClientWorkflowBehavior"> <host> <baseAddresses> <add baseAddress="https://localhost:8090/ClientWorkflow" /> </baseAddresses> </host> <endpoint address="" binding="wsHttpContextBinding" contract="ILocalHostContract" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services> <behaviors> <serviceBehaviors> <behavior name="WorkflowServiceClient.ClientWorkflowBehavior" > <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" /> <serviceCredentials> <windowsAuthentication allowAnonymousLogons="false" includeWindowsGroups="true" /> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors>Sie haben nun die Endpunktadresse für den lokalen Hostkommunikationsvertrag definiert. Der in diesem Lernprogramm verwendete Client implementiert auch diesen neuen Vertrag.
So richten Sie die lokale Hostkommunikation ein:
Öffnen Sie Program.cs, und fügen Sie am Anfang der Datei mithilfe von Anweisungen Folgendes hinzu:
using System.ServiceModel; using System.ServiceModel.Description;Haben Sie eine Visual Basic-Projektmappe erstellt, klicken Sie mit der rechten Maustaste auf den WorkflowServiceClient-Projektknoten, und wählen Sie Eigenschaften aus. Klicken Sie auf die Registerkarte Verweise, und aktivieren Sie unter Importierte Namespaces die Kontrollkästchen für System.ServiceModel und System.ServiceModel.Description.
Da Sie nun WorkflowServiceHost verwenden, um lokale Hostkommunikation zu ermöglichen und die Aufrufe der Clientworkflowvorgänge mit dem Workflowdienst auszuführen, muss die Main-Methode geändert werden, damit die Konsolenhostanwendung mit dem Workflowdienstclient kommunizieren kann. Im folgenden Code wird gezeigt, wie die Implementierung von Main geändert werden muss, um lokale Hostkommunikation zu erleichtern.
Shared Sub Main() ' Create a WorkflowServiceHost object to listen for operation invocations. Using ConsoleHost As New WorkflowServiceHost(GetType(ClientWorkflow)) Dim waitHandle As New AutoResetEvent(False) ' Add ChannelManagerService to the list of services used ' by the WorkflowRuntime. Dim cms As New ChannelManagerService() ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.AddService(cms) AddHandler ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.WorkflowCompleted, AddressOf OnWorkflowCompleted AddHandler ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.WorkflowTerminated, AddressOf OnWorkflowTerminated AddHandler ConsoleHost.Closed, AddressOf OnConsoleClosed ' Call Open to start receiving messages. ConsoleHost.Open() ' After the client workflow is started, block until receiving waitHandle.Set is called ' so that the console application does not exit before the client workflow has completed ' and ConsoleHost.Close is called. waitHandle.WaitOne() End Using End Sub Shared Sub OnWorkflowCompleted(ByVal sender As Object, ByVal e As WorkflowCompletedEventArgs) Console.WriteLine("The client workflow has completed." + vbLf + "Press <Enter> to exit the client application.") Console.ReadLine() WaitHandle.Set() End Sub Shared Sub OnWorkflowTerminated(ByVal sender As Object, ByVal e As WorkflowTerminatedEventArgs) Console.WriteLine(e.Exception.Message) WaitHandle.Set() End Sub ' After the WorkflowServiceHost transitions to the closed state, allow the console ' application to exit by signaling to the AutoResetEvent object that it is okay to unblock ' the main thread. Shared Sub OnConsoleClosed(ByVal sender As Object, ByVal e As EventArgs) WaitHandle.Set() End Substatic void Main(string[] args) { // Create a WorkflowServiceHost object to listen for operation invocations. using (WorkflowServiceHost ConsoleHost = new WorkflowServiceHost(typeof(ClientWorkflow))) { AutoResetEvent waitHandle = new AutoResetEvent(false); // Add ChannelManagerService to the list of services used // by the WorkflowRuntime. ChannelManagerService cms = new ChannelManagerService(); ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.AddService(cms); ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { Console.WriteLine("The client workflow has completed. \nPress <Enter> to exit the client application."); Console.ReadLine(); ConsoleHost.Close(); }; ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e) { Console.WriteLine(e.Exception.Message); waitHandle.Set(); }; // After the WorkflowServiceHost transitions to the closed state, allow the console // application to exit by signaling to the AutoResetEvent object that it is okay to unblock // the main thread. ConsoleHost.Closed += delegate(object sender, EventArgs e) { waitHandle.Set(); }; // Call Open to start receiving messages. ConsoleHost.Open(); // After the client workflow is started, block until receiving waitHandle.Set is called // so that the console application does not exit before the client workflow has completed // and ConsoleHost.Close is called. waitHandle.WaitOne(); } }Erstellen Sie den Clientdienst, und führen Sie ihn aus.
Verwenden Sie SvcUtil.exe, um den zum Interagieren mit den lokalen Hostkommunikationsvorgängen erforderlichen Proxy- und Konfigurationscode zu generieren.
Verwenden von SvcUtil.exe
Informationen zur Verwendung von SvcUtil.exe finden Sie unter ServiceModel Metadata Utility Tool.
Fügen Sie diese Dateien nach dem Generieren des Proxycodes und der Konfigurationsdateien folgendermaßen dem WorkflowServiceClient-Projekt hinzu:
- Navigieren Sie zum Bereich Projektmappen-Explorer.
- Klicken Sie mit der rechten Maustaste auf den WorkflowServiceClient-Projektknoten.
- Markieren Sie Hinzufügen, und wählen Sie Vorhandenes Element aus.
- Navigieren Sie zum Ordner, in dem die Konfiguration und Proxycodedateien von SvcUtil.exe generiert wurden.
- Wählen Sie die Dateien aus, und klicken Sie auf OK.
Nach dem Generieren des Proxycodes und der Konfigurationsdateien muss der Konfigurationsknoten in App.config geändert werden, damit der neue Clientendpunkt, der zum Vereinfachen der lokalen Hostkommunikation verwendet wird, von der Hostanwendung erkannt wird. Zudem können Sie auf Wunsch dieselben Bindungskonfigurationsinformationen wie die derzeit für die Kommunikation mit dem Workflowdienst verwendeten Informationen nutzen. Im folgenden Codebeispiel wird gezeigt, welcher Code der Datei App.Config hinzugefügt werden muss.
<bindings> ... </bindings> <client> <endpoint address="https://localhost:8080/ServerWorkflow" binding="wsHttpContextBinding" bindingConfiguration="WSHttpContextBinding_IWorkflow1" contract="IWorkflow1" name="WSHttpContextBinding_IWorkflow1"> <identity> <userPrincipalName value="someone@example.com" /> </identity> </endpoint> <endpoint address="https://localhost:8090/ClientWorkflow" binding="wsHttpContextBinding" bindingConfiguration="WSHttpContextBinding_IWorkflow1" contract="ILocalHostContract" name="WSHttpContextBinding_ILocalHostContract"> <identity> <userPrincipalName value="someone@example.com" /> </identity> </endpoint> </client> <services> ... </services> <behaviors> ... </behaviors>Nach dem Generieren des Proxyclientcodes für die Kommunikation zwischen dem Host und dem Workflowdienstclient muss der Code zum Aufrufen des LocalHostContractClient.StartClientWorkflow-Vorgangs im Clientworkflow hinzugefügt werden. Öffnen Sie daher Program.cs (oder Module1.vb, falls Sie eine Visual Basic-Lösung erstellt haben), und fügen Sie den folgenden Code hinzu.
Class Program Shared WaitHandle As New AutoResetEvent(False) Shared Sub Main() ' Create a WorkflowServiceHost object to listen for operation invocations. Using ConsoleHost As New WorkflowServiceHost(GetType(WorkflowServiceClient.ClientWorkflow)) Dim waitHandle As New AutoResetEvent(False) ' Create a client that is used by the host application to communicate with the workflow service client. Dim LCSClient As New WorkflowServiceClient.LocalHostContractClient("WSHttpContextBinding_ILocalHostContract") ' Add ChannelManagerService to the list of services used ' by the WorkflowRuntime. Dim cms As New ChannelManagerService() ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.AddService(cms) AddHandler ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.WorkflowCompleted, AddressOf OnWorkflowCompleted AddHandler ConsoleHost.Description.Behaviors.Find(Of WorkflowRuntimeBehavior)().WorkflowRuntime.WorkflowTerminated, AddressOf OnWorkflowTerminated AddHandler ConsoleHost.Closed, AddressOf OnConsoleClosed ' Call Open to start receiving messages. ConsoleHost.Open() Console.WriteLine("Client host service is ready.") Console.WriteLine("Enter a starting value: ") ' Read in a number from the user and use it as the initial number in the arithmetic operation calls. LCSClient.StartClientWorkflow(Int32.Parse(Console.ReadLine())) ' After the client workflow is started, block until receiving waitHandle.Set is called ' so that the console application does not exit before the client workflow has completed ' and ConsoleHost.Close is called. waitHandle.WaitOne() End Using End Sub Shared Sub OnWorkflowCompleted(ByVal sender As Object, ByVal e As WorkflowCompletedEventArgs) Console.WriteLine("The client workflow has completed." + vbLf + "Press <Enter> to exit the client application.") Console.ReadLine() WaitHandle.Set() End Sub Shared Sub OnWorkflowTerminated(ByVal sender As Object, ByVal e As WorkflowTerminatedEventArgs) Console.WriteLine(e.Exception.Message) WaitHandle.Set() End Sub ' After the WorkflowServiceHost transitions to the closed state, allow the console ' application to exit by signaling to the AutoResetEvent object that it is okay to unblock ' the main thread. Shared Sub OnConsoleClosed(ByVal sender As Object, ByVal e As EventArgs) WaitHandle.Set() End Sub End Classstatic void Main(string[] args) { // Create a WorkflowServiceHost object to listen for operation invocations. using (WorkflowServiceHost ConsoleHost = new WorkflowServiceHost(typeof(ClientWorkflow))) { AutoResetEvent waitHandle = new AutoResetEvent(false); // Create a client that is used by the host application to communicate with the workflow service client. LocalHostContractClient LCSClient = new LocalHostContractClient("WSHttpContextBinding_ILocalHostContract"); // Add ChannelManagerService to the list of services used // by the WorkflowRuntime. ChannelManagerService cms = new ChannelManagerService(); ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.AddService(cms); ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { Console.WriteLine("The client workflow has completed. \nPress <Enter> to exit the client application."); Console.ReadLine(); ConsoleHost.Close(); }; ConsoleHost.Description.Behaviors.Find<WorkflowRuntimeBehavior>().WorkflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e) { Console.WriteLine(e.Exception.Message); waitHandle.Set(); }; // After the WorkflowServiceHost transitions to the closed state, allow the console // application to exit by signaling to the AutoResetEvent object that it is okay to unblock // the main thread. ConsoleHost.Closed += delegate(object sender, EventArgs e) { waitHandle.Set(); }; // Call Open to start receiving messages. ConsoleHost.Open(); Console.WriteLine("Client host service is ready."); Console.WriteLine("Enter a starting value: "); // Read in a number from the user and use it as the initial number in the arithmetic operation calls. LCSClient.StartClientWorkflow(Int32.Parse(Console.ReadLine())); // After the client workflow is started, block until receiving waitHandle.Set is called // so that the console application does not exit before the client workflow has completed and // ConsoleHost.Close is called. waitHandle.WaitOne(); } }Da in der ReceiveActivity, mit der dieser Vorgang implementiert wird, CanCreateInstance auf True festgelegt ist, wird eine neue Workflowinstanz erstellt, und der Rest des Workflows wird ebenso wie in den vorherigen Übungen ausgeführt. Zudem handelt es sich bei dem über die Eingabeaufforderung eingegebenen Wert um den ersten Startwert, der beim Aufrufen des Rests der arithmetischen Vorgänge mit dem Workflowdienst verwendet wird.
Öffnen Sie Workflow1.cs (oder Workflow1.vb, falls Sie eine Visual Basic-Lösung erstellt haben), und entfernen Sie die Zeile des Codes, in der die Zahl 1 der inputValue-Variable in der sendActivity2_BeforeSend-Methodenimplementierung zugeordnet wird, damit ein Wert bei der Eingabe durch den Benutzer in der Eingabeaufforderung als erster Startwert für alle Vorgangsaufrufe mit dem Workflowdienst verwendet wird. Das folgende Codebeispiel zeigt, wie die überarbeitete Ereignishandler-Methodenimplementierung aussehen sollte.
Private Sub sendActivity2_BeforeSend(ByVal sender As System.Object, ByVal e As System.Workflow.Activities.SendActivityEventArgs) Console.WriteLine("The initial input value is {0}", inputValue) End Subprivate void sendActivity2_BeforeSend(object sender, SendActivityEventArgs e) { Console.WriteLine("The initial input value is {0}", inputValue); }Erstellen Sie die Workflowdienst-Projektmappe, und führen Sie sie aus. Überwachen Sie ähnliche Ausgaben von der Konsolenhostanwendung.
Client host service is ready. Enter a starting value: 7 A service instance has successfully been created. The initial input value is 7 The value after invoking the Add operation is 7 The new input value is 2 The value after invoking the Subtract operation is 5 The new input value is 6 The value after invoking the Multiply operation is 30 The new input value is 3 The value after invoking the Divide operation is 10 The workflow service instance has successfully shutdown. The client workflow has completed. Press <Enter> to exit the client application.
Siehe auch
Referenz
Aufgabe 1: Aktivieren der Kommunikation zwischen dem Client und seinem Host
Copyright © 2007 Microsoft Corporation. Alle Rechte vorbehalten.