Accesso alle informazioni sull'identità in un servizio del flusso di lavoroAccessing Identity Information inside a Workflow Service

Per accedere alle informazioni di identità in un servizio del flusso di lavoro, è necessario implementare l'interfaccia IReceiveMessageCallback in una proprietà di esecuzione personalizzata.To access identity information inside a workflow service, you must implement the IReceiveMessageCallback interface in a custom execution property. Nel metodo OnReceiveMessage(OperationContext, ExecutionProperties) è possibile accedere all'elemento ServiceSecurityContext per accedere alle informazioni di identità.In the OnReceiveMessage(OperationContext, ExecutionProperties) method you can access the ServiceSecurityContext to access identity information. In questo argomento viene descritta l'implementazione della proprietà di esecuzione e di un'attività personalizzata che esporrà tale proprietà all'attività Receive in fase di esecuzione.This topic will walk you through implementing this execution property, as well as a custom activity that will surface this property to the Receive activity at runtime. L'attività personalizzata implementerà lo stesso comportamento di un System.ServiceModel.Activities.Sequence attività, ad eccezione che, quando un Receive viene posizionato all'interno, il IReceiveMessageCallback verrà chiamato e verranno recuperate le informazioni di identità.The custom activity will implement the same behavior as a System.ServiceModel.Activities.Sequence activity, except that when a Receive is placed inside of it, the IReceiveMessageCallback will be called and the identity information will be retrieved.

Implementare IReceiveMessageCallbackImplement IReceiveMessageCallback

  1. Creare una soluzione Visual Studio 2012Visual Studio 2012 vuota.Create an empty Visual Studio 2012Visual Studio 2012 solution.

  2. Aggiungere alla soluzione una nuova applicazione console denominata Service.Add a new console application called Service to the solution.

  3. Aggiungere riferimenti agli assembly riportati di seguito:Add references to the following assemblies:

    1. System.Runtime.SerializationSystem.Runtime.Serialization

    2. System.ServiceModelSystem.ServiceModel

    3. System.ServiceModel.ActivitiesSystem.ServiceModel.Activities

  4. Aggiungere una nuova classe denominata AccessIdentityCallback e implementare IReceiveMessageCallback come illustrato nell'esempio seguente.Add a new class called AccessIdentityCallback and implement IReceiveMessageCallback as shown in the following example.

    class AccessIdentityCallback : IReceiveMessageCallback  
    {  
       public void OnReceiveMessage(System.ServiceModel.OperationContext operationContext, System.Activities.ExecutionProperties activityExecutionProperties)  
       {  
          try  
          {  
             Console.WriteLine("Received a message from a workflow with the following identity");  
             Console.WriteLine("Windows Identity Name: {0}", operationContext.ServiceSecurityContext.WindowsIdentity.Name);  
             Console.WriteLine("Windows Identity User: {0}", operationContext.ServiceSecurityContext.WindowsIdentity.User);  
             Console.WriteLine("Windows Identity IsAuthenticated: {0}", operationContext.ServiceSecurityContext.WindowsIdentity.IsAuthenticated);  
          }            
          catch (Exception ex)  
          {  
             Console.WriteLine("An exception occurred: " + ex.Message);  
          }  
        }  
    }  
    

    In questo codice viene utilizzato OperationContext passato al metodo per accedere alle informazioni di identità.This code uses the OperationContext passed into the method to access identity information.

Implementare l'attività Native per aggiungere l'implementazione IReceiveMessageCallback a NativeActivityContextImplement a Native activity to add the IReceiveMessageCallback implementation to the NativeActivityContext

  1. Aggiungere una nuova classe derivata da NativeActivity denominata AccessIdentityScope.Add a new class derived from NativeActivity called AccessIdentityScope.

  2. Aggiungere variabili locali per tenere traccia di attività figlio, variabili e indice dell'attività corrente e un callback CompletionCallback.Add local variables to keep track of child activities, variables, current activity index, and a CompletionCallback callback.

    public sealed class AccessIdentityScope : NativeActivity  
    {  
        Collection<Activity> children;  
        Collection<Variable> variables;  
        Variable<int> currentIndex;  
        CompletionCallback onChildComplete;  
    }  
    
  3. Implementare il costruttoreImplement the constructor

    public AccessIdentityScope() : base()  
    {  
        this.children = new Collection<Activity>();  
        this.variables = new Collection<Variable>();  
        this.currentIndex = new Variable<int>();  
    }  
    
  4. Implementare le proprietà Activities e Variables.Implement the Activities and Variables properties.

    public Collection<Activity> Activities  
    {  
         get { return this.children; }  
    }  
    
    public Collection<Variable> Variables  
    {  
        get { return this.variables; }  
    }  
    
  5. Eseguire l'override di CacheMetadata.Override CacheMetadata

    protected override void CacheMetadata(NativeActivityMetadata metadata)  
    {  
        //call base.CacheMetadata to add the Activities and Variables to this activity's metadata  
        base.CacheMetadata(metadata);  
        //add the private implementation variable: currentIndex   
        metadata.AddImplementationVariable(this.currentIndex);  
    }  
    
  6. Eseguire l'override di Execute.Override Execute

    protected override void Execute(NativeActivityContext context)  
    {  
       // Add the IReceiveMessageCallback implementation as an Execution property   
       context.Properties.Add("AccessIdentityCallback", new AccessIdentityCallback());  
       InternalExecute(context, null);  
    }  
    
    void InternalExecute(NativeActivityContext context, ActivityInstance instance)  
    {  
       //grab the index of the current Activity  
       int currentActivityIndex = this.currentIndex.Get(context);  
       if (currentActivityIndex == Activities.Count)  
       {  
          //if the currentActivityIndex is equal to the count of MySequence's Activities  
          //MySequence is complete  
          return;  
       }  
    
       if (this.onChildComplete == null)  
       {  
          //on completion of the current child, have the runtime call back on this method  
          this.onChildComplete = new CompletionCallback(InternalExecute);  
       }  
    
       //grab the next Activity in MySequence.Activities and schedule it  
       Activity nextChild = Activities[currentActivityIndex];  
       context.ScheduleActivity(nextChild, this.onChildComplete);  
    
       //increment the currentIndex  
       this.currentIndex.Set(context, ++currentActivityIndex);  
    }  
    

Implementare il servizio di flusso di lavoroImplement the workflow service

  1. Aprire Program classe.Open the existing Program class.

  2. Definire le costanti seguenti:Define the following constants:

    class Program  
    {  
       const string addr = "http://localhost:8080/Service";  
       static XName contract = XName.Get("IService", "http://tempuri.org");  
    }  
    
  3. Aggiungere un metodo statico denominato GetWorkflowService che crea il servizio di flusso di lavoro.Add a static method called GetWorkflowService that creates the workflow service.

    static Activity GetServiceWorkflow()  
    {  
       Variable<string> echoString = new Variable<string>();  
    
       // Create the Receive activity  
       Receive echoRequest = new Receive  
       {  
          CanCreateInstance = true,  
          ServiceContractName = contract,  
          OperationName = "Echo",  
          Content = new ReceiveParametersContent()  
          {  
             Parameters = { { "echoString", new OutArgument<string>(echoString) } }  
          }  
       };  
    
       return new AccessIdentityScope  
       {  
          Variables = { echoString },  
          Activities =  
          {  
             echoRequest,  
             new WriteLine { Text = new InArgument<string>( (e) => "Received: " + echoString.Get(e) ) },  
             new SendReply  
             {  
                Request = echoRequest,  
                Content = new SendParametersContent()  
                {  
                   Parameters = { { "result", new InArgument<string>(echoString) } }   
                }  
             }  
          }  
       };  
     }  
    
  4. Nel metodo Main esistente ospitare il servizio di flusso di lavoro.In the existing Main method, host the workflow service.

    static void Main(string[] args)  
    {  
       string addr = "http://localhost:8080/Service";  
    
       using (WorkflowServiceHost host = new WorkflowServiceHost(GetServiceWorkflow()))  
       {  
          WSHttpBinding binding = new WSHttpBinding(SecurityMode.Message);  
          host.AddServiceEndpoint(contract, binding, addr);  
    
          host.Open();  
          Console.WriteLine("Service waiting at: " + addr);  
          Console.WriteLine("Press [ENTER] to exit");  
          Console.ReadLine();  
          host.Close();  
       }  
    }  
    

Implementare un client flusso di lavoroImplement a workflow client

  1. Creare un nuovo progetto di applicazione console denominato Client.Create a new console application project called Client.

  2. Aggiungere riferimenti agli assembly riportati di seguito:Add references to the following assemblies:

    1. System.ActivitiesSystem.Activities

    2. System.ServiceModelSystem.ServiceModel

    3. System.ServiceModel.ActivitiesSystem.ServiceModel.Activities

  3. Aprire il file Program.cs generato e aggiungere un metodo statico denominato GetClientWorkflow per creare il client flusso di lavoro.Open the generated Program.cs file and add a static method called GetClientWorkflow to create the client workflow.

    static Activity GetClientWorkflow()  
    {  
       Variable<string> echoString = new Variable<string>();  
    
       Endpoint clientEndpoint = new Endpoint  
       {  
          Binding = new WSHttpBinding(SecurityMode.Message),  
          AddressUri = new Uri("http://localhost:8080/Service")  
       };  
    
       Send echoRequest = new Send  
       {  
          Endpoint = clientEndpoint,  
          ServiceContractName = XName.Get("IService", "http://tempuri.org"),  
          OperationName = "Echo",  
          Content = new SendParametersContent()  
          {  
             Parameters = { { "echoString", new InArgument<string>("Hello, World") } }   
          }  
       };  
    
       return new Sequence  
       {  
          Variables = { echoString },  
          Activities =  
          {                      
             new CorrelationScope  
             {  
                Body = new Sequence  
                {  
                   Activities =   
                   {  
                      echoRequest,  
                      new ReceiveReply  
                      {  
                         Request = echoRequest,  
                         Content = new ReceiveParametersContent  
                         {  
                            Parameters = { { "result", new OutArgument<string>(echoString) } }  
                         }  
                      }  
                   }  
                }  
             },                      
             new WriteLine { Text = new InArgument<string>( (e) => "Received Text: " + echoString.Get(e) ) },                      
             }  
          };  
       }  
    }  
    
  4. Aggiungere il codice di hosting seguente per implementare il metodo Main().Add the following hosting code to the Main() method.

    static void Main(string[] args)  
    {  
       Activity workflow = GetClientWorkflow();  
       WorkflowInvoker.Invoke(workflow);  
       WorkflowInvoker.Invoke(workflow);  
       Console.WriteLine("Press [ENTER] to exit");  
       Console.ReadLine();  
    }  
    

EsempioExample

Di seguito è riportato il codice sorgente utilizzato in questo argomento.Here is a complete listing of the source code used in this topic.

// AccessIdentityCallback.cs  
//----------------------------------------------------------------  
// Copyright (c) Microsoft Corporation.  All rights reserved.  
//----------------------------------------------------------------  

using System;  
using System.ServiceModel;  
using System.ServiceModel.Activities;  

namespace Microsoft.Samples.AccessingOperationContext.Service  
{  
    class AccessIdentityCallback : IReceiveMessageCallback  
    {  
        public const string HeaderName = "InstanceIdHeader";  
        public const string HeaderNS = "http://Microsoft.Samples.AccessingOperationContext";  

        public void OnReceiveMessage(System.ServiceModel.OperationContext operationContext, System.Activities.ExecutionProperties activityExecutionProperties)  
        {  
            try  
            {  
                // Guid instanceId = operationContext.IncomingMessageHeaders.GetHeader<Guid>(HeaderName, HeaderNS);  
                Console.WriteLine("Received a message from a workflow with the following identity" ); // with instanceId = {0}", instanceId);  
                Console.WriteLine("Windows Identity Name: {0}", operationContext.ServiceSecurityContext.WindowsIdentity.Name);  
                Console.WriteLine("Windows Identity User: {0}", operationContext.ServiceSecurityContext.WindowsIdentity.User);  
                Console.WriteLine("Windows Identity IsAuthenticated: {0}", operationContext.ServiceSecurityContext.WindowsIdentity.IsAuthenticated);  
            }  
            catch (MessageHeaderException)  
            {  
                Console.WriteLine("This message must not be from a workflow.");  
            }  
            catch (Exception ex)  
            {  
                Console.WriteLine("An exception occurred: " + ex.Message);  
            }  
        }  
    }  
}  
// AccessIdentityScope.cs  
//----------------------------------------------------------------  
// Copyright (c) Microsoft Corporation.  All rights reserved.  
//----------------------------------------------------------------  

using System.Activities;  
using System.Collections.ObjectModel;  

namespace Microsoft.Samples.AccessingOperationContext.Service  
{  
    public sealed class AccessIdentityScope : NativeActivity  
    {  
        Collection<Activity> children;  
        Collection<Variable> variables;  
        Variable<int> currentIndex;  
        CompletionCallback onChildComplete;  

        public AccessIdentityScope()  
            : base()  
        {  
            this.children = new Collection<Activity>();  
            this.variables = new Collection<Variable>();  
            this.currentIndex = new Variable<int>();  
        }  

        public Collection<Activity> Activities  
        {  
            get  
            {  
                return this.children;  
            }  
        }  

        public Collection<Variable> Variables  
        {  
            get  
            {  
                return this.variables;  
            }  
        }  

        protected override void CacheMetadata(NativeActivityMetadata metadata)  
        {  
            //call base.CacheMetadata to add the Activities and Variables to this activity's metadata  
            base.CacheMetadata(metadata);  
            //add the private implementation variable: currentIndex   
            metadata.AddImplementationVariable(this.currentIndex);  
        }                     

        protected override void Execute(  
            NativeActivityContext context)  
        {  
            context.Properties.Add("AccessIdentityCallback", new AccessIdentityCallback());  
            InternalExecute(context, null);  
        }  

        void InternalExecute(NativeActivityContext context, ActivityInstance instance)  
        {  
            //grab the index of the current Activity  
            int currentActivityIndex = this.currentIndex.Get(context);  
            if (currentActivityIndex == Activities.Count)  
            {  
                //if the currentActivityIndex is equal to the count of MySequence's Activities  
                //MySequence is complete  
                return;  
            }  

            if (this.onChildComplete == null)  
            {  
                //on completion of the current child, have the runtime call back on this method  
                this.onChildComplete = new CompletionCallback(InternalExecute);  
            }  

            //grab the next Activity in MySequence.Activities and schedule it  
            Activity nextChild = Activities[currentActivityIndex];  
            context.ScheduleActivity(nextChild, this.onChildComplete);  

            //increment the currentIndex  
            this.currentIndex.Set(context, ++currentActivityIndex);  
        }  
    }  
}  
// Service.cs  
//----------------------------------------------------------------  
// Copyright (c) Microsoft Corporation.  All rights reserved.  
//----------------------------------------------------------------  

using System;  
using System.Activities;  
using System.Activities.Statements;  
using System.ServiceModel;  
using System.ServiceModel.Activities;  
using System.Xml.Linq;  

namespace Microsoft.Samples.AccessingOperationContext.Service  
{      
    class Program  
    {  
        const string addr = "http://localhost:8080/Service";  
        static XName contract = XName.Get("IService", "http://tempuri.org");  

        static void Main(string[] args)  
        {  
            string addr = "http://localhost:8080/Service";  

            using (WorkflowServiceHost host = new WorkflowServiceHost(GetServiceWorkflow()))  
            {  
                WSHttpBinding binding = new WSHttpBinding(SecurityMode.Message);  
                host.AddServiceEndpoint(contract, binding, addr);  

                host.Open();  
                Console.WriteLine("Service waiting at: " + addr);  
                Console.WriteLine("Press [ENTER] to exit");  
                Console.ReadLine();  
                host.Close();  
            }  

        }  

        static Activity GetServiceWorkflow()  
        {  
            Variable<string> echoString = new Variable<string>();  

            Receive echoRequest = new Receive  
            {  
                CanCreateInstance = true,  
                ServiceContractName = contract,  
                OperationName = "Echo",  
                Content = new ReceiveParametersContent()  
                {  
                    Parameters = { { "echoString", new OutArgument<string>(echoString) } }  
                }  
            };  

            return new AccessIdentityScope  
            {  
                Variables = { echoString },  
                Activities =  
                {  
                    echoRequest,  
                    new WriteLine { Text = new InArgument<string>( (e) => "Received: " + echoString.Get(e) ) },  
                    new SendReply  
                    {  
                        Request = echoRequest,  
                        Content = new SendParametersContent()  
                        {  
                            Parameters = { { "result", new InArgument<string>(echoString) } }   
                        }  
                    }  
                }  
            };  
        }  
    }  
}  
// client.cs   
//----------------------------------------------------------------  
// Copyright (c) Microsoft Corporation.  All rights reserved.  
//----------------------------------------------------------------  

using System;  
using System.Activities;  
using System.Activities.Statements;  
using System.ServiceModel;  
using System.ServiceModel.Activities;  
using System.Xml.Linq;  

namespace Microsoft.Samples.AccessingOperationContext.Client  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            Activity workflow = GetClientWorkflow();  
            WorkflowInvoker.Invoke(workflow);  
            WorkflowInvoker.Invoke(workflow);  
            Console.WriteLine("Press [ENTER] to exit");  
            Console.ReadLine();  
        }  

        static Activity GetClientWorkflow()  
        {  
            Variable<string> echoString = new Variable<string>();  

            Endpoint clientEndpoint = new Endpoint  
            {  
                Binding = new WSHttpBinding(SecurityMode.Message),  
                AddressUri = new Uri("http://localhost:8080/Service")  
            };  

            Send echoRequest = new Send  
            {  
                Endpoint = clientEndpoint,  
                ServiceContractName = XName.Get("IService", "http://tempuri.org"),  
                OperationName = "Echo",  
                Content = new SendParametersContent()  
                {  
                    Parameters = { { "echoString", new InArgument<string>("Hello, World") } }   
                }  
            };  

            return new Sequence  
            {  
                Variables = { echoString },  
                Activities =  
                {                      
                    new CorrelationScope  
                    {  
                        Body = new Sequence  
                        {  
                            Activities =   
                            {  
                                echoRequest,  
                                new ReceiveReply  
                                {  
                                    Request = echoRequest,  
                                    Content = new ReceiveParametersContent  
                                    {  
                                        Parameters = { { "result", new OutArgument<string>(echoString) } }  
                                    }  
                                }  
                            }  
                        }  
                    },                      
                    new WriteLine { Text = new InArgument<string>( (e) => "Received Text: " + echoString.Get(e) ) },                      
                }  
            };  
        }  
    }  
}  

Vedere ancheSee Also

Servizi flusso di lavoroWorkflow Services
Accesso a OperationContextAccessing OperationContext
Creazione di flussi di lavoro, attività ed espressioni tramite codice imperativoAuthoring Workflows, Activities, and Expressions Using Imperative Code