File: System\ServiceModel\Description\WorkflowServiceBehavior.cs
Project: ndp\cdf\src\NetFx35\System.WorkflowServices\System.WorkflowServices.csproj (System.WorkflowServices)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Description
{
    using System.Collections.ObjectModel;
    using System.IO;
    using System.Runtime;
    using System.ServiceModel.Administration;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Dispatcher;
    using System.Workflow.ComponentModel;
    using System.Workflow.Runtime;
    using System.Workflow.Runtime.Hosting;
    using System.Xml;
 
    class WorkflowServiceBehavior : IServiceBehavior, IContextSessionProvider, IWmiInstanceProvider
    {
        static readonly object[] emptyObjectArray = new object[] { };
        AddressFilterMode addressFilterMode;
        string configurationName;
        bool ignoreExtensionDataObject;
        bool includeExceptionDetailInFaults;
        int maxItemsInObjectGraph = -1;
        string name;
        string nameSpace;
        bool useSynchronizationContext;
        bool validateMustUnderstand;
        WorkflowDefinitionContext workflowDefinitionContext;
        string workflowDefinitionPath;
        string workflowRulesPath;
 
        public WorkflowServiceBehavior(Type workflowType) :
            this(new CompiledWorkflowDefinitionContext(workflowType))
        {
 
        }
 
        public WorkflowServiceBehavior(string workflowDefinitionPath)
            :
            this(workflowDefinitionPath, null)
        {
 
        }
 
        public WorkflowServiceBehavior(string workflowDefinitionPath, string ruleDefinitionPath)
            :
            this(new StreamedWorkflowDefinitionContext(workflowDefinitionPath, ruleDefinitionPath, null))
        {
            this.workflowDefinitionPath = workflowDefinitionPath;
            this.workflowRulesPath = ruleDefinitionPath;
        }
 
        public WorkflowServiceBehavior(Stream workflowDefinitionStream)
            : this(new StreamedWorkflowDefinitionContext(workflowDefinitionStream, null, null))
        {
 
        }
 
        public WorkflowServiceBehavior(Stream workflowDefinitionStream, Stream ruleDefinitionStream)
            : this(new StreamedWorkflowDefinitionContext(workflowDefinitionStream, ruleDefinitionStream, null))
        {
 
        }
 
        internal WorkflowServiceBehavior(WorkflowDefinitionContext workflowDefinitionContext)
        {
            if (workflowDefinitionContext == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("workflowDefinitionContext");
            }
 
            this.workflowDefinitionContext = workflowDefinitionContext;
            this.name = this.workflowDefinitionContext.WorkflowName;
            this.configurationName = this.workflowDefinitionContext.ConfigurationName;
        }
 
        public AddressFilterMode AddressFilterMode
        {
            get
            {
                return this.addressFilterMode;
            }
            set
            {
                if (!AddressFilterModeHelper.IsDefined(value))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
                }
                this.addressFilterMode = value;
            }
        }
 
        public string ConfigurationName
        {
            get
            {
                return this.configurationName;
            }
            set
            {
                if (value == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
                }
                this.configurationName = value;
            }
        }
 
        public bool IgnoreExtensionDataObject
        {
            get
            {
                return this.ignoreExtensionDataObject;
            }
            set
            {
                this.ignoreExtensionDataObject = value;
            }
        }
 
        public bool IncludeExceptionDetailInFaults
        {
            get
            {
                return this.includeExceptionDetailInFaults;
            }
            set
            {
                this.includeExceptionDetailInFaults = value;
            }
        }
 
        public int MaxItemsInObjectGraph
        {
            get
            {
                return this.maxItemsInObjectGraph;
            }
            set
            {
                this.maxItemsInObjectGraph = value;
            }
        }
 
        public string Name
        {
            get
            {
                return this.name;
            }
            set
            {
                if (value == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
                }
                this.name = value;
            }
        }
 
        public string Namespace
        {
            get
            {
                return this.nameSpace;
            }
            set
            {
                if (value == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
                }
                this.nameSpace = value;
            }
        }
 
        public bool UseSynchronizationContext
        {
            get
            {
                return this.useSynchronizationContext;
            }
            set
            {
                this.useSynchronizationContext = value;
            }
        }
 
        public bool ValidateMustUnderstand
        {
            get
            {
                return this.validateMustUnderstand;
            }
            set
            {
                this.validateMustUnderstand = value;
            }
        }
 
 
        public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
        {
 
        }
 
        public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
            if (description == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("description");
            }
 
            if (serviceHostBase == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serviceHostBase");
            }
            if (description.Behaviors == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("description", SR2.GetString(SR2.NoBehaviors));
            }
            if (description.Endpoints == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("description", SR2.GetString(SR2.NoEndpoints));
            }
 
            bool syncContextRegistered = false;
            WorkflowRuntimeBehavior workflowRuntimeBehavior = description.Behaviors.Find<WorkflowRuntimeBehavior>();
 
            if (workflowRuntimeBehavior == null)
            {
                workflowRuntimeBehavior = new WorkflowRuntimeBehavior();
                description.Behaviors.Add(workflowRuntimeBehavior);
            }
 
            WorkflowPersistenceService persistenceService = workflowRuntimeBehavior.WorkflowRuntime.GetService<WorkflowPersistenceService>();
            if (persistenceService != null)
            {
                bool wasRuntimeStarted = workflowRuntimeBehavior.WorkflowRuntime.IsStarted;
                if (wasRuntimeStarted)
                {
                    workflowRuntimeBehavior.WorkflowRuntime.StopRuntime();
                }
                workflowRuntimeBehavior.WorkflowRuntime.RemoveService(persistenceService);
                workflowRuntimeBehavior.WorkflowRuntime.AddService(new SkipUnloadOnFirstIdleWorkflowPersistenceService(persistenceService));
                if (wasRuntimeStarted)
                {
                    workflowRuntimeBehavior.WorkflowRuntime.StartRuntime();
                }
            }
 
            this.workflowDefinitionContext.Register(workflowRuntimeBehavior.WorkflowRuntime, workflowRuntimeBehavior.ValidateOnCreate);
 
            WorkflowInstanceContextProvider instanceContextProvider = new WorkflowInstanceContextProvider(
                serviceHostBase,
                false,
                this.workflowDefinitionContext
                );
 
            WorkflowInstanceContextProvider singleCallInstanceContextProvider = null;
 
            IInstanceProvider instanceProvider = new WorkflowInstanceProvider(instanceContextProvider);
            ServiceDebugBehavior serviceDebugBehavior = description.Behaviors.Find<ServiceDebugBehavior>();
 
            bool includeExceptionDetailsInFaults = this.IncludeExceptionDetailInFaults;
            if (serviceDebugBehavior != null)
            {
                includeExceptionDetailsInFaults |= serviceDebugBehavior.IncludeExceptionDetailInFaults;
            }
 
            IErrorHandler workflowOperationErrorHandler = new WorkflowOperationErrorHandler(includeExceptionDetailsInFaults);
 
            foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
 
                if (channelDispatcher != null && channelDispatcher.HasApplicationEndpoints())
                {
                    channelDispatcher.IncludeExceptionDetailInFaults = includeExceptionDetailsInFaults;
                    channelDispatcher.ErrorHandlers.Add(workflowOperationErrorHandler);
                    foreach (EndpointDispatcher endPointDispatcher in channelDispatcher.Endpoints)
                    {
                        if (endPointDispatcher.IsSystemEndpoint)
                        {
                            continue;
                        }
 
                        ServiceEndpoint serviceEndPoint = description.Endpoints.Find(new XmlQualifiedName(endPointDispatcher.ContractName, endPointDispatcher.ContractNamespace));
 
                        if (serviceEndPoint != null)
                        {
 
                            DispatchRuntime dispatchRuntime = endPointDispatcher.DispatchRuntime;
 
                            dispatchRuntime.AutomaticInputSessionShutdown = true;
                            dispatchRuntime.ConcurrencyMode = ConcurrencyMode.Single;
                            dispatchRuntime.ValidateMustUnderstand = this.ValidateMustUnderstand;
 
                            if (!this.UseSynchronizationContext)
                            {
                                dispatchRuntime.SynchronizationContext = null;
                            }
                            else if (!syncContextRegistered)
                            {
                                SynchronizationContextWorkflowSchedulerService syncSchedulerService = workflowRuntimeBehavior.WorkflowRuntime.GetService<SynchronizationContextWorkflowSchedulerService>();
                                Fx.Assert(syncSchedulerService != null, "Wrong Synchronization Context Set");
                                syncSchedulerService.SetSynchronizationContext(dispatchRuntime.SynchronizationContext);
                                syncContextRegistered = true;
                            }
 
                            if (!endPointDispatcher.AddressFilterSetExplicit)
                            {
                                EndpointAddress endPointAddress = endPointDispatcher.OriginalAddress;
                                if ((endPointAddress == null) || (this.AddressFilterMode == AddressFilterMode.Any))
                                {
                                    endPointDispatcher.AddressFilter = new MatchAllMessageFilter();
                                }
                                else if (this.AddressFilterMode == AddressFilterMode.Prefix)
                                {
                                    endPointDispatcher.AddressFilter = new PrefixEndpointAddressMessageFilter(endPointAddress);
                                }
                                else if (this.AddressFilterMode == AddressFilterMode.Exact)
                                {
                                    endPointDispatcher.AddressFilter = new EndpointAddressMessageFilter(endPointAddress);
                                }
                            }
 
                            if (serviceEndPoint.Contract.SessionMode != SessionMode.NotAllowed)
                            {
                                endPointDispatcher.DispatchRuntime.InstanceContextProvider = instanceContextProvider;
                            }
                            else
                            {
                                if (singleCallInstanceContextProvider == null)
                                {
                                    singleCallInstanceContextProvider = new WorkflowInstanceContextProvider(
                                        serviceHostBase,
                                        true,
                                        this.workflowDefinitionContext);
                                }
                                endPointDispatcher.DispatchRuntime.InstanceContextProvider = singleCallInstanceContextProvider;
                            }
                            endPointDispatcher.DispatchRuntime.MessageInspectors.Add(new DurableMessageDispatchInspector(serviceEndPoint.Contract.SessionMode));
                            endPointDispatcher.DispatchRuntime.InstanceProvider = instanceProvider;
                            SetContractFilterToIncludeAllOperations(endPointDispatcher, serviceEndPoint.Contract);
                        }
                    }
                }
            }
            DataContractSerializerServiceBehavior.ApplySerializationSettings(description, this.ignoreExtensionDataObject, this.maxItemsInObjectGraph);
        }
 
        void IWmiInstanceProvider.FillInstance(IWmiInstance wmiInstance)
        {
            wmiInstance.SetProperty("AddressFilterMode", this.AddressFilterMode.ToString());
            wmiInstance.SetProperty("ConfigurationName", this.ConfigurationName);
            wmiInstance.SetProperty("IgnoreExtensionDataObject", this.IgnoreExtensionDataObject);
            wmiInstance.SetProperty("IncludeExceptionDetailInFaults", this.IncludeExceptionDetailInFaults);
            wmiInstance.SetProperty("MaxItemsInObjectGraph", this.MaxItemsInObjectGraph);
            wmiInstance.SetProperty("Name", this.Name);
            wmiInstance.SetProperty("Namespace", this.Namespace);
            wmiInstance.SetProperty("UseSynchronizationContext", this.UseSynchronizationContext);
            wmiInstance.SetProperty("ValidateMustUnderstand", this.ValidateMustUnderstand);
            wmiInstance.SetProperty("WorkflowType", this.workflowDefinitionContext.WorkflowName);
            wmiInstance.SetProperty("WorkflowDefinitionPath", this.workflowDefinitionPath);
            wmiInstance.SetProperty("WorkflowRulesPath", this.workflowRulesPath);
        }
 
        string IWmiInstanceProvider.GetInstanceType()
        {
            return "WorkflowServiceBehavior";
        }
 
        public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
            ContextBindingElement.ValidateContextBindingElementOnAllEndpointsWithSessionfulContract(description, this);
        }
 
        internal static void SetContractFilterToIncludeAllOperations(EndpointDispatcher dispatcher, ContractDescription contract)
        {
            if (dispatcher == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dispatcher");
            }
            if (contract == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contract");
            }
 
            if (contract.SessionMode == SessionMode.Required)
            {
                EndpointFilterProvider provider = new EndpointFilterProvider();
                foreach (OperationDescription operation in contract.Operations)
                {
                    if (!operation.IsServerInitiated())
                    {
                        provider.InitiatingActions.Add(operation.Messages[0].Action);
                    }
                }
                int priority;
                dispatcher.ContractFilter = provider.CreateFilter(out priority);
                dispatcher.FilterPriority = priority;
            }
        }
 
        class SkipUnloadOnFirstIdleWorkflowPersistenceService : WorkflowPersistenceService
        {
            WorkflowPersistenceService inner;
 
            public SkipUnloadOnFirstIdleWorkflowPersistenceService(WorkflowPersistenceService inner)
            {
                if (inner == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("inner");
                }
 
                this.inner = inner;
            }
 
            protected internal override Activity LoadCompletedContextActivity(Guid scopeId, Activity outerActivity)
            {
                return this.inner.LoadCompletedContextActivity(scopeId, outerActivity);
            }
 
            protected internal override Activity LoadWorkflowInstanceState(Guid instanceId)
            {
                return this.inner.LoadWorkflowInstanceState(instanceId);
            }
 
            protected internal override void SaveCompletedContextActivity(Activity activity)
            {
                this.inner.SaveCompletedContextActivity(activity);
            }
 
            protected internal override void SaveWorkflowInstanceState(Activity rootActivity, bool unlock)
            {
                this.inner.SaveWorkflowInstanceState(rootActivity, unlock);
            }
 
            protected internal override void Start()
            {
                this.inner.SetRuntime(this.Runtime);
                this.inner.Start();
            }
 
            protected internal override void Stop()
            {
                this.inner.Stop();
                this.inner.SetRuntime(null);
            }
 
            protected internal override bool UnloadOnIdle(Activity activity)
            {
                if (WorkflowDispatchContext.Current != null && WorkflowDispatchContext.Current.IsWorkflowStarting)
                {
                    return false;
                }
                else
                {
                    return this.inner.UnloadOnIdle(activity);
                }
            }
 
            protected internal override void UnlockWorkflowInstanceState(Activity rootActivity)
            {
                this.inner.UnlockWorkflowInstanceState(rootActivity);
            }
        }
    }
}