Tarea 1: Habilitación de la comunicación entre el cliente y su host

En esta tarea habilitará la comunicación entre su cliente y su host a través del uso de un contrato WCF. La aplicación host invocará una operación en el cliente que está diseñada para iniciar el flujo de trabajo del cliente e inicializarlo con un valor de arranque.

Además, en lugar de crear otro contrato WCF a través de una nueva interfaz, en esta tarea obtendrá información acerca de cómo crear un contrato WCF programáticamente a través del método de flujo de trabajo primero.

Nota

Cuando se usa el diseñador de flujo de trabajo de Visual Studio para crear o administrar servicios de flujo de trabajo, a veces se generan errores de validación falsos. Si puede generar correctamente su proyecto, omita los errores de validación.

Procedimientos

Creación del contrato de comunicación de host local

  1. Nota: cuando se usa el diseñador de flujo de trabajo de Visual Studio para crear o administrar los servicios de flujo de trabajo, a veces genera errores de validación falsos. Si puede generar correctamente su proyecto, omita los errores de validación.

  2. Abra la solución WorkflowServiceTutorial.

  3. En el nodo de proyecto de WorkflowServiceClient, abra el diseñador de flujo de trabajo para ese proyecto.

  4. Arrastre una actividad ReceiveActivity al diseñador y colóquelo sobre la primera actividad SendActivity para que la actividad ReceiveActivity se ejecute primero en el flujo de trabajo.

    Esta actividad implementará la operación definida en el contrato de comunicación de host local.

  5. Seleccione la actividad ReceiveActivity y en el panel de Propiedades, en ServiceOperationInfo, haga clic en los puntos suspensivos para abrir el cuadro de diálogo Seleccionar operación.

  6. Va a definir un nuevo contrato mediante el estilo de creación de flujo de trabajo primero, y para ello ha de hacer clic en Agregar contrato en la esquina superior derecha y resaltar Contract1.

  7. En el cuadro de texto Nombre de contrato, denomine a su contrato ILocalHostContract.

  8. Resalte la primera operación bajo ILocalHostContract y cámbiele el nombre a StartClientWorkflow.

  9. En la pestaña Parámetros, haga clic en el símbolo Agregar y agregue un nuevo parámetro denominado initialValue de tipo Int32 con una Dirección de En y haga clic en Aceptar.

  10. Seleccione la actividad ReceiveActivity y en el panel Propiedades, enlace initialValue a la variable global inputValue.

  11. También en el panel Propiedades, establezca la propiedad CanCreateInstance en Verdadero.

    Ahora hay un nuevo contrato denominado ILocalHostContract definido mediante programación para usted, pero aún debe modificar algunos archivos antes de poder utilizar este contrato para interactuar con su servicio del flujo de trabajo.

  12. Abra App.config en el proyecto WorkflowServiceClient.

  13. Agregue el siguiente código de configuración:

          <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>
    

    Ha definido la dirección del extremo para su contrato de comunicación de host local. El cliente que ha utilizado a lo largo de este tutorial también implementará este nuevo contrato.

Para preparar la comunicación del host local

  1. Abra Program.cs y agregue las siguientes instrucciones de uso a la parte superior del archivo:

    using System.ServiceModel;
    using System.ServiceModel.Description;
    

    Si ha creado una solución Visual Basic, haga clic con el botón secundario del mouse en el nodo de proyecto WorkflowServiceClient y seleccione Propiedades. Seleccione la pestaña Referencias y en Espacios de nombres importados, haga clic en las casillas para System.ServiceModel y System.ServiceModel.Description.

  2. Dado que estará utilizando ahora WorkflowServiceHost para habilitar la comunicación del host local y ejecutar las invocaciones de operación del flujo de trabajo del cliente con el servicio del flujo de trabajo, debe modificar el método Principal para que la aplicación host de la consola pueda comunicarse con el cliente de servicio del flujo de trabajo. El código siguiente muestra cómo la implementación de Principal debe cambiar para facilitar la comunicación con el host local.

    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 Sub
    
    static 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();
        }
    }
    
  3. Genere su servicio de cliente y ejecútelo.

  4. Utilice Svcutil.exe para generar el código proxy y el código de configuración necesarios para interactuar con las operaciones de comunicación de host locales.

    Utilizar Svcutil.exe

    Para utilizar SvcUtil.exe, consulte ServiceModel Metadata Utility Tool.

    Después de haber generado sus archivos de configuración y código proxy, agregue esos archivos al proyecto WorkflowServiceClient haciendo lo siguiente:

    1. Navegue al panel Explorador desoluciones.
    2. Haga clic con el botón secundario del mouse en el nodo del proyecto WorkflowServiceClient.
    3. Resalte Agregar y seleccione Elemento existente.
    4. Navegue a la carpeta donde Svcutil.exe generó los archivos de código proxy y configuración.
    5. Seleccione los archivos y haga clic en Aceptar.
  5. Cuando haya generado sus archivos de configuración y código proxy, modifique el código de configuración en App.config para que la aplicación host reconozca el nuevo extremo del cliente utilizado para facilitar la comunicación del host local. Asimismo, puede utilizar la misma información de configuración de enlace que la que se utiliza para comunicarse con su servicio del flujo de trabajo si así lo desea. El siguiente ejemplo de código muestra qué código debe agregar a su archivo App.Config.

        <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>
    
  6. Ahora que ha generado su código proxy de cliente para comunicarse entre el host y el cliente de servicio de flujo de trabajo, debe agregar el código para invocar la operación LocalHostContractClient.StartClientWorkflow en su flujo de trabajo de cliente, así que abra Program.cs (o Module1.vb si crea una solución Visual Basic) y agregue el código siguiente.

    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 Class
    
    static 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();
        }
    }
    

    Dado que la ReceiveActivity que implementa esta operación tiene CanCreateInstance establecido en True, se creará una nueva instancia de flujo de trabajo y el resto del flujo de trabajo se ejecutará como en ejercicios anteriores. Además, el valor que se especifica a través del símbolo del sistema será el valor de inicialización inicial utilizado al invocar el resto de operaciones aritméticas en el servicio del flujo de trabajo.

  7. Abra Workflow1.cs (o Workflow1.vb si crea una solución Visual Basic) y quite la línea de código que asigna el número 1 a la variable inputValue en la implementación de método sendActivity2_BeforeSend para que cuando el usuario especifique un valor en el símbolo del sistema, se utilice ese valor como valor de inicialización inicial para todas las invocaciones de operación del servicio del flujo de trabajo. El ejemplo de código siguiente muestra qué apariencia debería tener la implementación del método de control de eventos revisada.

    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 Sub
    
    private void sendActivity2_BeforeSend(object sender, SendActivityEventArgs e)
    {
        Console.WriteLine("The initial input value is {0}", inputValue);
    }
    
  8. Genere y ejecute la solución WorkflowServiceTutorial. El resultado debería ser similar a este en la aplicación host de la consola.

    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.
    

Consulte también

Referencia

Tarea 1: Habilitación de la comunicación entre el cliente y su host

Copyright © 2007 Microsoft Corporation. Reservados todos los derechos.