WorkflowService.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.ServiceModel.Activities / System / ServiceModel / Activities / WorkflowService.cs / 1480445 / WorkflowService.cs

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

namespace System.ServiceModel.Activities 
{
    using System.Activities; 
    using System.Activities.Debugger; 
    using System.Collections.Generic;
    using System.Collections.ObjectModel; 
    using System.ComponentModel;
    using System.Runtime;
    using System.ServiceModel.Activities.Description;
    using System.ServiceModel.Description; 
    using System.ServiceModel.XamlIntegration;
    using System.Windows.Markup; 
    using System.Xml; 
    using System.Xml.Linq;
 
    [ContentProperty("Body")]
    public class WorkflowService : IDebuggableWorkflowTree
    {
        Collection endpoints; 

        IDictionary cachedInferredContracts; 
        IDictionary> correlationQueryByContract; 

        IList knownServiceActivities; 
        HashSet receiveAndReplyPairs;
        ServiceDescription serviceDescription;

        XName inferedServiceName; 

        public WorkflowService() 
        { 
        }
 
        [DefaultValue(null)]
        public Activity Body
        {
            get; 
            set;
        } 
 
        [Fx.Tag.KnownXamlExternal]
        [DefaultValue(null)] 
        [TypeConverter(typeof(ServiceXNameTypeConverter))]
        public XName Name
        {
            get; 
            set;
        } 
 
        [DefaultValue(null)]
        public string ConfigurationName 
        {
            get;
            set;
        } 

        [DefaultValue(false)] 
        public bool AllowBufferedReceive 
        {
            get; 
            set;
        }

        public Collection Endpoints 
        {
            get 
            { 
                if (this.endpoints == null)
                { 
                    this.endpoints = new Collection();
                }
                return this.endpoints;
            } 
        }
 
        internal XName InternalName 
        {
            get 
            {
                if (this.Name != null)
                {
                    return this.Name; 
                }
                else 
                { 
                    if (this.inferedServiceName == null)
                    { 
                        Fx.Assert(this.Body != null, "Body cannot be null!");

                        if (this.Body.DisplayName.Length == 0)
                        { 
                            throw FxTrace.Exception.AsError(new InvalidOperationException(SR.MissingDisplayNameInRootActivity));
                        } 
 
                        this.inferedServiceName = XName.Get(XmlConvert.EncodeLocalName(this.Body.DisplayName));
                    } 
                    return this.inferedServiceName;
                }
            }
        } 

        internal IDictionary> CorrelationQueries 
        { 
            get
            { 
                Fx.Assert(this.cachedInferredContracts != null, "Must infer contract first!");
                return this.correlationQueryByContract;
            }
        } 

        public Activity GetWorkflowRoot() 
        { 
            return this.Body;
        } 

        internal ServiceDescription GetEmptyServiceDescription()
        {
            if (this.serviceDescription == null) 
            {
                WalkActivityTree(); 
 
                ServiceDescription result = new ServiceDescription
                { 
                    Name = this.InternalName.LocalName,
                    Namespace = string.IsNullOrEmpty(this.InternalName.NamespaceName) ? NamingHelper.DefaultNamespace : this.InternalName.NamespaceName,
                    ConfigurationName = this.ConfigurationName ?? this.InternalName.LocalName
                }; 
                result.Behaviors.Add(new WorkflowServiceBehavior(this.Body));
                this.serviceDescription = result; 
            } 
            return this.serviceDescription;
        } 

        internal IDictionary GetContractDescriptions()
        {
            if (this.cachedInferredContracts == null) 
            {
                WalkActivityTree(); 
 
                Fx.Assert(this.knownServiceActivities != null && this.receiveAndReplyPairs != null, "Failed to walk the activity tree!");
                this.correlationQueryByContract = new Dictionary>(); 

                // Contract inference
                IDictionary inferredContracts = new Dictionary();
                IDictionary keyedByNameOperationInfo = 
                    new Dictionary();
 
                foreach (Receive receive in this.knownServiceActivities) 
                {
                    XName contractXName = FixServiceContractName(receive.ServiceContractName); 
                    ContractAndOperationNameTuple tuple = new ContractAndOperationNameTuple(contractXName, receive.OperationName);

                    OperationInfo operationInfo;
                    if (keyedByNameOperationInfo.TryGetValue(tuple, out operationInfo)) 
                    {
                        // All Receives with same ServiceContractName and OperationName need to be validated 
                        ContractValidationHelper.ValidateReceiveWithReceive(receive, operationInfo.Receive); 
                    }
                    else 
                    {
                        // Note that activities in keyedByNameOperationInfo are keyed by
                        // ServiceContractName and OperationName tuple. So we won't run into the case where
                        // two opertions have the same OperationName. 

                        ContractDescription contract; 
                        if (!inferredContracts.TryGetValue(contractXName, out contract)) 
                        {
                            // Infer Name, Namespace 
                            contract = new ContractDescription(contractXName.LocalName, contractXName.NamespaceName);

                            // We use ServiceContractName.LocalName to bind contract with config
                            contract.ConfigurationName = contractXName.LocalName; 

                            // We do NOT infer ContractDescription.ProtectionLevel 
 
                            inferredContracts.Add(contractXName, contract);
                        } 

                        OperationDescription operation = ContractInferenceHelper.CreateOperationDescription(receive, contract);
                        contract.Operations.Add(operation);
 
                        operationInfo = new OperationInfo(receive, operation);
                        keyedByNameOperationInfo.Add(tuple, operationInfo); 
                    } 

                    CorrectOutMessageForOperationWithFault(receive, operationInfo); 

                    ContractInferenceHelper.UpdateIsOneWayFlag(receive, operationInfo.OperationDescription);

                    // FaultTypes and KnownTypes need to be collected from all Receive activities 
                    ContractInferenceHelper.AddFaultDescription(receive, operationInfo.OperationDescription);
                    ContractInferenceHelper.AddKnownTypesToOperation(receive, operationInfo.OperationDescription); 
 
                    // WorkflowFormatterBehavior should have reference to all the Receive activities
                    ContractInferenceHelper.AddReceiveToFormatterBehavior(receive, operationInfo.OperationDescription); 

                    Collection correlationQueries = null;

                    // Collect CorrelationQuery from Receive 
                    if (receive.HasCorrelatesOn || receive.HasCorrelationInitializers)
                    { 
                        MessageQuerySet select = receive.HasCorrelatesOn ? receive.CorrelatesOn : null; 
                        CorrelationQuery correlationQuery = ContractInferenceHelper.CreateServerCorrelationQuery(select,
                            receive.CorrelationInitializers, operationInfo.OperationDescription, false); 
                        CollectCorrelationQuery(ref correlationQueries, contractXName, correlationQuery);
                    }

                    // Find all known Receive-Reply pair in the activity tree. Remove them from this.receiveAndReplyPairs 
                    // Also collect CorrelationQuery from following replies
                    if (receive.HasReply) 
                    { 
                        foreach (SendReply reply in receive.FollowingReplies)
                        { 
                            ReceiveAndReplyTuple pair = new ReceiveAndReplyTuple(receive, reply);
                            this.receiveAndReplyPairs.Remove(pair);

                            CollectCorrelationQueryFromReply(ref correlationQueries, contractXName, 
                                reply, operationInfo.OperationDescription);
 
                            reply.SetContractName(contractXName); 
                        }
                    } 
                    if (receive.HasFault)
                    {
                        foreach (Activity fault in receive.FollowingFaults)
                        { 
                            ReceiveAndReplyTuple pair = new ReceiveAndReplyTuple(receive, fault);
                            this.receiveAndReplyPairs.Remove(pair); 
 
                            CollectCorrelationQueryFromReply(ref correlationQueries, contractXName,
                                fault, operationInfo.OperationDescription); 
                        }
                    }
                }
 
                // Check for Receive referenced by SendReply but no longer in the activity tree
                if (this.receiveAndReplyPairs.Count != 0) 
                { 
                    throw FxTrace.Exception.AsError(new ValidationException(SR.DanglingReceive));
                } 

                // Print out tracing information
                if (TD.InferredContractDescriptionIsEnabled())
                { 
                    foreach (ContractDescription contract in inferredContracts.Values)
                    { 
                        TD.InferredContractDescription(contract.Name, contract.Namespace); 

                        if (TD.InferredOperationDescriptionIsEnabled()) 
                        {
                            foreach (OperationDescription operation in contract.Operations)
                            {
                                TD.InferredOperationDescription(operation.Name, contract.Name, operation.IsOneWay.ToString()); 
                            }
                        } 
                    } 
                }
 
                this.cachedInferredContracts = inferredContracts;
            }

            return this.cachedInferredContracts; 
        }
 
        void WalkActivityTree() 
        {
            if (this.knownServiceActivities != null) 
            {
                // We return if we have already walked the activity tree
                return;
            } 

            if (this.Body == null) 
            { 
                throw FxTrace.Exception.AsError(new ValidationException(SR.MissingBodyInWorkflowService));
            } 

            // Validate the activity tree
            WorkflowInspectionServices.CacheMetadata(this.Body);
 
            this.knownServiceActivities = new List();
            this.receiveAndReplyPairs = new HashSet(); 
 
            // Now let us walk the tree here
            Queue activities = new Queue(); 
            // The root activity is never "in" a TransactedReceiveScope
            activities.Enqueue(new QueueItem(this.Body, null, null));
            while (activities.Count > 0)
            { 
                QueueItem queueItem = activities.Dequeue();
                Fx.Assert(queueItem != null, "Queue item cannot be null"); 
 
                Activity activity = queueItem.Activity;
                Fx.Assert(queueItem.Activity != null, "Queue item's Activity cannot be null"); 

                TransactedReceiveScope transactedReceiveScope = queueItem.ParentTransactedReceiveScope;
                TransactedReceiveScope rootTransactedReceiveScope = queueItem.RootTransactedReceiveScope;
 
                if (activity is Receive)  // First, let's see if this is a Receive activity
                { 
                    Receive receive = (Receive)activity; 

                    if (rootTransactedReceiveScope != null) 
                    {
                        receive.InternalReceive.AdditionalData.IsInsideTransactedReceiveScope = true;
                        Fx.Assert(transactedReceiveScope != null, "Internal error.. TransactedReceiveScope should be valid here");
                        if ((receive == transactedReceiveScope.Request) && (transactedReceiveScope == rootTransactedReceiveScope)) 
                        {
                            receive.InternalReceive.AdditionalData.IsFirstReceiveOfTransactedReceiveScopeTree = true; 
                        } 
                    }
 
                    this.knownServiceActivities.Add(receive);
                }
                else if (activity is SendReply)  // Let's see if this is a SendReply
                { 
                    SendReply sendReply = (SendReply)activity;
 
                    Receive pairedReceive = sendReply.Request; 
                    Fx.Assert(pairedReceive != null, "SendReply must point to a Receive!");
 
                    if (sendReply.InternalContent.IsFault)
                    {
                        pairedReceive.FollowingFaults.Add(sendReply);
                    } 
                    else
                    { 
                        if (pairedReceive.HasReply) 
                        {
                            SendReply followingReply = pairedReceive.FollowingReplies[0]; 
                            ContractValidationHelper.ValidateSendReplyWithSendReply(followingReply, sendReply);
                        }

                        pairedReceive.FollowingReplies.Add(sendReply); 
                    }
 
                    ReceiveAndReplyTuple tuple = new ReceiveAndReplyTuple(pairedReceive, sendReply); 
                    this.receiveAndReplyPairs.Add(tuple);
                } 

                // Enqueue child activities and delegates
                if (activity is TransactedReceiveScope)
                { 
                    transactedReceiveScope = activity as TransactedReceiveScope;
                    if (rootTransactedReceiveScope == null) 
                    { 
                        rootTransactedReceiveScope = transactedReceiveScope;
                    } 

                }

                foreach (Activity childActivity in WorkflowInspectionServices.GetActivities(activity)) 
                {
                    QueueItem queueData = new QueueItem(childActivity, transactedReceiveScope, rootTransactedReceiveScope); 
                    activities.Enqueue(queueData); 
                }
            } 
        }

        XName FixServiceContractName(XName serviceContractName)
        { 
            // By default, we use WorkflowService.Name as ServiceContractName
            XName contractXName = serviceContractName ?? this.InternalName; 
 
            ContractInferenceHelper.ProvideDefaultNamespace(ref contractXName);
 
            return contractXName;
        }

        void CorrectOutMessageForOperationWithFault(Receive receive, OperationInfo operationInfo) 
        {
            Fx.Assert(receive != null && operationInfo != null, "Argument cannot be null!"); 
 
            Receive prevReceive = operationInfo.Receive;
            if (receive != prevReceive && receive.HasReply && 
                !prevReceive.HasReply && prevReceive.HasFault)
            {
                ContractInferenceHelper.CorrectOutMessageForOperation(receive, operationInfo.OperationDescription);
                operationInfo.Receive = receive; 
            }
        } 
 
        void CollectCorrelationQuery(ref Collection queries, XName serviceContractName, CorrelationQuery correlationQuery)
        { 
            Fx.Assert(serviceContractName != null, "Argument cannot be null!");

            if (correlationQuery == null)
            { 
                return;
            } 
 
            if (queries == null && !this.correlationQueryByContract.TryGetValue(serviceContractName, out queries))
            { 
                queries = new Collection();
                this.correlationQueryByContract.Add(serviceContractName, queries);
            }
 
            queries.Add(correlationQuery);
        } 
 
        void CollectCorrelationQueryFromReply(ref Collection correlationQueries, XName serviceContractName,
            Activity reply, OperationDescription operation) 
        {
            SendReply sendReply = reply as SendReply;
            if (sendReply != null)
            { 
                CorrelationQuery correlationQuery = ContractInferenceHelper.CreateServerCorrelationQuery(
                    null, sendReply.CorrelationInitializers, operation, true); 
                CollectCorrelationQuery(ref correlationQueries, serviceContractName, correlationQuery); 
            }
        } 

        internal void ResetServiceDescription()
        {
            this.serviceDescription = null; 
            this.cachedInferredContracts = null;
        } 
 
        struct ContractAndOperationNameTuple
        { 
            XName ServiceContractXName;
            string OperationName;

            public ContractAndOperationNameTuple(XName serviceContractXName, string operationName) 
            {
                this.ServiceContractXName = serviceContractXName; 
                this.OperationName = operationName; 
            }
        } 

        struct ReceiveAndReplyTuple
        {
            Receive Receive; 
            Activity Reply;
 
            public ReceiveAndReplyTuple(Receive receive, Activity reply) 
            {
                this.Receive = receive; 
                this.Reply = reply;
            }
        }
 
        class OperationInfo
        { 
            Receive receive; 
            OperationDescription operationDescription;
 
            public OperationInfo(Receive receive, OperationDescription operationDescription)
            {
                this.receive = receive;
                this.operationDescription = operationDescription; 
            }
 
            public Receive Receive 
            {
                get { return this.receive; } 
                set { this.receive = value; }
            }

            public OperationDescription OperationDescription 
            {
                get { return this.operationDescription; } 
            } 
        }
 
        class QueueItem
        {
            Activity activity;
            TransactedReceiveScope parent; 
            TransactedReceiveScope rootTransactedReceiveScope;
 
            public QueueItem(Activity element, TransactedReceiveScope parent, TransactedReceiveScope rootTransactedReceiveScope) 
            {
                this.activity = element; 
                this.parent = parent;
                this.rootTransactedReceiveScope = rootTransactedReceiveScope;
            }
 
            public Activity Activity
            { 
                get { return this.activity; } 
            }
 
            public TransactedReceiveScope ParentTransactedReceiveScope
            {
                get { return this.parent; }
            } 

            public TransactedReceiveScope RootTransactedReceiveScope 
            { 
                get { return this.rootTransactedReceiveScope; }
            } 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK