File: WorkflowOperationBehavior.cs

package info (click to toggle)
mono 4.6.2.7%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 778,148 kB
  • ctags: 914,052
  • sloc: cs: 5,779,509; xml: 2,773,713; ansic: 432,645; sh: 14,749; makefile: 12,361; perl: 2,488; python: 1,434; cpp: 849; asm: 531; sql: 95; sed: 16; php: 1
file content (204 lines) | stat: -rw-r--r-- 9,269 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//----------------------------------------------------------------

namespace System.ServiceModel.Activities.Description
{
    using System.Collections;
    using System.Collections.Generic;
    using System.Activities;
    using System.Runtime;
    using System.Runtime.Diagnostics;
    using System.Runtime.DurableInstancing;
    using System.ServiceModel.Activities.Dispatcher;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.ServiceModel.Diagnostics;
    using System.ServiceModel.Dispatcher;
    using System.Transactions;

    class WorkflowOperationBehavior : IOperationBehavior
    {
        Bookmark bookmark;


        public WorkflowOperationBehavior(Bookmark bookmark, bool canCreateInstance)
            : this(canCreateInstance)
        {
            Fx.Assert(bookmark != null, "bookmark must not be null!");
            this.bookmark = bookmark;
        }

        protected WorkflowOperationBehavior(bool canCreateInstance)
        {
            this.CanCreateInstance = canCreateInstance;
        }

        internal bool CanCreateInstance
        {
            get;
            set;
        }

        public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
        {
        }

        public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
        {
            if (operationDescription == null)
            {
                throw FxTrace.Exception.ArgumentNull("operationDescription");
            }
            if (dispatchOperation == null)
            {
                throw FxTrace.Exception.ArgumentNull("dispatchOperation");
            }
            if (dispatchOperation.Parent == null
                || dispatchOperation.Parent.ChannelDispatcher == null
                || dispatchOperation.Parent.ChannelDispatcher.Host == null
                || dispatchOperation.Parent.ChannelDispatcher.Host.Description == null
                || dispatchOperation.Parent.ChannelDispatcher.Host.Description.Behaviors == null)
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.DispatchOperationInInvalidState));
            }

            ServiceHostBase serviceHost = dispatchOperation.Parent.ChannelDispatcher.Host;
            if (!(serviceHost is WorkflowServiceHost))
            {
                throw FxTrace.Exception.AsError(
                   new InvalidOperationException(SR.WorkflowBehaviorWithNonWorkflowHost(typeof(WorkflowOperationBehavior).Name)));
            }

            CorrelationKeyCalculator correlationKeyCalculator = null;

            ServiceEndpoint endpoint = null;
            foreach (ServiceEndpoint endpointToMatch in serviceHost.Description.Endpoints)
            {
                if (endpointToMatch.Id == dispatchOperation.Parent.EndpointDispatcher.Id)
                {
                    endpoint = endpointToMatch;
                    break;
                }
            }

            if (endpoint != null)
            {
                CorrelationQueryBehavior queryBehavior = endpoint.Behaviors.Find<CorrelationQueryBehavior>();

                if (queryBehavior != null)
                {
                    correlationKeyCalculator = queryBehavior.GetKeyCalculator();
                }
            }

            dispatchOperation.Invoker = new WorkflowOperationInvoker(operationDescription,
                endpoint, correlationKeyCalculator, this, serviceHost, dispatchOperation.Invoker);
        }

        public void Validate(OperationDescription operationDescription)
        {
        }

        protected internal virtual Bookmark OnResolveBookmark(WorkflowOperationContext context, out BookmarkScope bookmarkScope, out object value)
        {
            Fx.Assert(this.bookmark != null, "bookmark must not be null!");

            CorrelationMessageProperty correlationMessageProperty;
            if (CorrelationMessageProperty.TryGet(context.OperationContext.IncomingMessageProperties, out correlationMessageProperty))
            {
                bookmarkScope = new BookmarkScope(correlationMessageProperty.CorrelationKey.Value);
            }
            else
            {
                bookmarkScope = BookmarkScope.Default;
            }
            value = context;
            return this.bookmark;
        }

        //Invoker for workflowbased application endpoint operation 
        class WorkflowOperationInvoker : ControlOperationInvoker, IInstanceTransaction
        {
            bool performanceCountersEnabled;
            bool propagateActivity;
            bool isHostingEndpoint;
            IOperationInvoker innerInvoker;
            WorkflowOperationBehavior behavior;
            bool isFirstReceiveOfTransactedReceiveScopeTree;
            
            public WorkflowOperationInvoker(OperationDescription operationDescription, ServiceEndpoint endpoint,
                CorrelationKeyCalculator keyCalculator, WorkflowOperationBehavior behavior, ServiceHostBase host, IOperationInvoker innerInvoker)
                : base(operationDescription, endpoint, keyCalculator, host)
            {
                Fx.Assert(operationDescription != null, "Null OperationDescription");
                Fx.Assert(behavior != null, "Null WorkflowOperationBehavior");
                this.StaticBookmarkName = behavior.bookmark == null ? null : behavior.bookmark.Name;
                this.behavior = behavior;
                this.CanCreateInstance = behavior.CanCreateInstance;
                this.performanceCountersEnabled = PerformanceCounters.PerformanceCountersEnabled;
                this.propagateActivity = TraceUtility.ShouldPropagateActivity;
                this.isHostingEndpoint = endpoint is WorkflowHostingEndpoint;
                this.innerInvoker = innerInvoker;
                this.isFirstReceiveOfTransactedReceiveScopeTree = operationDescription.IsFirstReceiveOfTransactedReceiveScopeTree;
            }

            public override object[] AllocateInputs()
            {
                if (this.isHostingEndpoint)
                {
                    return this.innerInvoker.AllocateInputs();
                }
                // InternalReceiveMessage & InternalSendMessage is always MessageIn - MessageOut.
                // Therefore we always need an array of size 1.
                // DispatchOperationRuntime saves the request into this array in this case ( i.e., when DeserializeRequest is false)
                return new object[1];
            }

            protected override IAsyncResult OnBeginServiceOperation(WorkflowServiceInstance workflowInstance, OperationContext operationContext,
                object[] inputs, Transaction currentTransaction, IInvokeReceivedNotification notification, TimeSpan timeout, AsyncCallback callback, object state)
            {
                Fx.Assert(workflowInstance != null, "caller must verify");
                Fx.Assert(inputs != null, "caller must verify");

                return WorkflowOperationContext.BeginProcessRequest(workflowInstance, operationContext, this.OperationName, inputs,
                    this.performanceCountersEnabled, this.propagateActivity, currentTransaction, notification, this.behavior, this.endpoint, timeout, callback, state);
            }

            protected override object OnEndServiceOperation(WorkflowServiceInstance durableInstance, out object[] outputs, IAsyncResult result)
            {
                // InternalSendMessage always redirects the replyMessage into the returnValue
                object returnValue = WorkflowOperationContext.EndProcessRequest(result, out outputs);

                //we will just assert that outputs is always an empty array
                Fx.Assert(this.isHostingEndpoint || outputs == null || outputs.Length == 0, "Workflow returned a non-empty out-arg");
                
                return returnValue;
            }

            public Transaction GetTransactionForInstance(OperationContext operationContext)
            {
                Transaction tx = null;

                // We are only going to go ask the PPD for the transaction if we are NOT the first
                // Receive in a TransactedReceiveScope;
                if (!this.isFirstReceiveOfTransactedReceiveScopeTree)
                {
                    // We need to get the InstanceKey.
                    InstanceKey instanceKey;
                    ICollection<InstanceKey> additionalKeys;
                    this.GetInstanceKeys(operationContext, out instanceKey, out additionalKeys);
                    Fx.Assert((instanceKey != null) && (instanceKey.IsValid), "InstanceKey is null or invalid in GetInstanceTransaction");

                    tx = this.InstanceManager.PersistenceProviderDirectory.GetTransactionForInstance(instanceKey);
                }

                return tx;
            }
        }
    }
}