Merge pull request #3213 from henricm/fix-for-win-securestring-to-bstr
[mono.git] / mcs / class / referencesource / System.Activities / System / Activities / WorkflowApplication.cs
1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4
5 namespace System.Activities
6 {
7     using System;
8     using System.Activities.Hosting;
9     using System.Activities.DurableInstancing;
10     using System.Activities.DynamicUpdate;
11     using System.Activities.Persistence;
12     using System.Activities.Runtime;
13     using System.Activities.Tracking;
14     using System.Collections.Generic;
15     using System.Collections.ObjectModel;
16     using System.ComponentModel;
17     using System.Linq;
18     using System.Runtime;
19     using System.Runtime.DurableInstancing;
20     using System.Runtime.Serialization;
21     using System.Threading;
22     using System.Transactions;
23     using System.Xml.Linq;
24     using System.Text;
25     using System.Security;
26
27     // WorkflowApplication is free-threaded. It is responsible for the correct locking and usage of the ActivityExecutor.
28     // Given that there are two simultaneous users of ActivityExecutor (WorkflowApplication and NativeActivityContext),
29     // it is imperative that WorkflowApplication only calls into ActivityExecutor when there are no activities executing
30     // (and thus no worries about colliding with AEC calls).
31
32     // SYNCHRONIZATION SCHEME
33     // WorkflowInstance is defined to not be thread safe and to disallow all operations while it is (potentially
34     // asynchronously) running.  The WorkflowInstance is in the "running" state between a call to Run and the
35     // subsequent call to either WorkflowInstance NotifyPaused or NotifyUnhandledException.
36     // WorkflowApplication keeps track of a boolean "isBusy" and a list of pending operations.  WI is busy whenever
37     // it is servicing an operation or the runtime is in the "running" state.
38     // Enqueue - This enqueues an operation into the pending operation list.  If WI is not busy then the operation
39     //    can be serviced immediately.  This is the only place where "isBusy" flips to true.
40     // OnNotifiedUnhandledException - This method performs some processing and then calls OnNotifiedPaused.
41     // OnNotifiedPaused - This method is only ever called when "isBusy" is true.  It first checks to see if there
42     //    is other work to be done (prioritization: raise completed, handle an operation, resume execution, raise
43     //    idle, stop).  This is the only place where "isBusy" flips to false and this only occurs when there is no
44     //    other work to be done.
45     // [Force]NotifyOperationComplete - These methods are called by individual operations when they are done
46     //    processing.  If the operation was notified (IE - actually performed in the eyes of WI) then this is simply
47     //    a call to OnNotifiedPaused.
48     // Operation notification - The InstanceOperation class keeps tracks of whether a specified operation was
49     //    dispatched by WI or not.  If it was dispatched (determined either in Enqueue, FindOperation, or Remove)
50     //    then it MUST result in a call to OnNotifiedPaused when complete.
51     [Fx.Tag.XamlVisible(false)]
52     public sealed class WorkflowApplication : WorkflowInstance
53     {
54         static AsyncCallback eventFrameCallback;
55         static IdleEventHandler idleHandler;
56         static CompletedEventHandler completedHandler;
57         static UnhandledExceptionEventHandler unhandledExceptionHandler;
58         static Action<object, TimeoutException> waitAsyncCompleteCallback;
59         static readonly WorkflowIdentity unknownIdentity = new WorkflowIdentity();
60
61         Action<WorkflowApplicationAbortedEventArgs> onAborted;
62         Action<WorkflowApplicationEventArgs> onUnloaded;
63         Action<WorkflowApplicationCompletedEventArgs> onCompleted;
64         Func<WorkflowApplicationUnhandledExceptionEventArgs, UnhandledExceptionAction> onUnhandledException;
65         Func<WorkflowApplicationIdleEventArgs, PersistableIdleAction> onPersistableIdle;
66         Action<WorkflowApplicationIdleEventArgs> onIdle;
67
68         WorkflowEventData eventData;
69
70         WorkflowInstanceExtensionManager extensions;
71         PersistencePipeline persistencePipelineInUse;
72         InstanceStore instanceStore;
73         PersistenceManager persistenceManager;
74         WorkflowApplicationState state;
75         int handlerThreadId;
76         bool isInHandler;
77         Action invokeCompletedCallback;
78         Guid instanceId;
79         bool instanceIdSet;  // Checking for Guid.Empty is expensive.
80
81         // Tracking for one-time actions per in-memory pulse
82         bool hasCalledAbort;
83         bool hasCalledRun;
84
85         // Tracking for one-time actions per instance lifetime (these end up being persisted)
86         bool hasRaisedCompleted;
87
88         Quack<InstanceOperation> pendingOperations;
89         bool isBusy;
90         bool hasExecutionOccurredSinceLastIdle;
91
92         // Count of operations that are about to be enqueued.
93         // We use this when enqueueing multiple operations, to avoid raising
94         // idle on dequeue of the first operation.
95         int pendingUnenqueued;
96
97         // We use this to keep track of the number of "interesting" things that have happened.
98         // Notifying operations and calling Run on the runtime count as interesting things.
99         // All operations are stamped with the actionCount at the time of being enqueued.
100         int actionCount;
101
102         // Initial creation data
103         IDictionary<string, object> initialWorkflowArguments;
104         IList<Handle> rootExecutionProperties;
105
106         IDictionary<XName, InstanceValue> instanceMetadata;
107         
108         public WorkflowApplication(Activity workflowDefinition)
109             : this(workflowDefinition, (WorkflowIdentity)null)
110         {
111         }
112
113         public WorkflowApplication(Activity workflowDefinition, IDictionary<string, object> inputs)
114             : this(workflowDefinition, inputs, (WorkflowIdentity)null)
115         {
116         }
117
118         public WorkflowApplication(Activity workflowDefinition, WorkflowIdentity definitionIdentity)
119             : base(workflowDefinition, definitionIdentity)
120         {
121             this.pendingOperations = new Quack<InstanceOperation>();
122             Fx.Assert(this.state == WorkflowApplicationState.Paused, "We always start out paused (the default)");
123         }
124
125         public WorkflowApplication(Activity workflowDefinition, IDictionary<string, object> inputs, WorkflowIdentity definitionIdentity)
126             : this(workflowDefinition, definitionIdentity)
127         {
128             if (inputs == null)
129             {
130                 throw FxTrace.Exception.ArgumentNull("inputs");
131             }
132             this.initialWorkflowArguments = inputs;
133         }
134
135         WorkflowApplication(Activity workflowDefinition, IDictionary<string, object> inputs, IList<Handle> executionProperties)
136             : this(workflowDefinition)
137         {
138             this.initialWorkflowArguments = inputs;
139             this.rootExecutionProperties = executionProperties;
140         }
141
142         public InstanceStore InstanceStore
143         {
144             get
145             {
146                 return this.instanceStore;
147             }
148             set
149             {
150                 ThrowIfReadOnly();
151                 this.instanceStore = value;
152             }
153         }
154
155         public WorkflowInstanceExtensionManager Extensions
156         {
157             get
158             {
159                 if (this.extensions == null)
160                 {
161                     this.extensions = new WorkflowInstanceExtensionManager();
162                     if (base.IsReadOnly)
163                     {
164                         this.extensions.MakeReadOnly();
165                     }
166                 }
167                 return this.extensions;
168             }
169         }
170
171         public Action<WorkflowApplicationAbortedEventArgs> Aborted
172         {
173             get
174             {
175                 return this.onAborted;
176             }
177             set
178             {
179                 ThrowIfMulticast(value);
180                 this.onAborted = value;
181             }
182         }
183
184         public Action<WorkflowApplicationEventArgs> Unloaded
185         {
186             get
187             {
188                 return this.onUnloaded;
189             }
190             set
191             {
192                 ThrowIfMulticast(value);
193                 this.onUnloaded = value;
194             }
195         }
196
197         public Action<WorkflowApplicationCompletedEventArgs> Completed
198         {
199             get
200             {
201                 return this.onCompleted;
202             }
203             set
204             {
205                 ThrowIfMulticast(value);
206                 this.onCompleted = value;
207             }
208         }
209
210         public Func<WorkflowApplicationUnhandledExceptionEventArgs, UnhandledExceptionAction> OnUnhandledException
211         {
212             get
213             {
214                 return this.onUnhandledException;
215             }
216             set
217             {
218                 ThrowIfMulticast(value);
219                 this.onUnhandledException = value;
220             }
221         }
222
223         public Action<WorkflowApplicationIdleEventArgs> Idle
224         {
225             get
226             {
227                 return this.onIdle;
228             }
229             set
230             {
231                 ThrowIfMulticast(value);
232                 this.onIdle = value;
233             }
234         }
235
236         public Func<WorkflowApplicationIdleEventArgs, PersistableIdleAction> PersistableIdle
237         {
238             get
239             {
240                 return this.onPersistableIdle;
241             }
242             set
243             {
244                 ThrowIfMulticast(value);
245                 this.onPersistableIdle = value;
246             }
247         }
248
249         public override Guid Id
250         {
251             get
252             {
253                 if (!this.instanceIdSet)
254                 {
255                     lock (this.pendingOperations)
256                     {
257                         if (!this.instanceIdSet)
258                         {
259                             this.instanceId = Guid.NewGuid();
260                             this.instanceIdSet = true;
261                         }
262                     }
263                 }
264                 return this.instanceId;
265             }
266         }
267
268         protected internal override bool SupportsInstanceKeys
269         {
270             get
271             {
272                 return false;
273             }
274         }
275
276         static AsyncCallback EventFrameCallback
277         {
278             get
279             {
280                 if (eventFrameCallback == null)
281                 {
282                     eventFrameCallback = Fx.ThunkCallback(new AsyncCallback(EventFrame));
283                 }
284
285                 return eventFrameCallback;
286             }
287         }
288
289         WorkflowEventData EventData
290         {
291             get
292             {
293                 if (this.eventData == null)
294                 {
295                     this.eventData = new WorkflowEventData(this);
296                 }
297
298                 return this.eventData;
299             }
300         }
301
302         bool HasPersistenceProvider
303         {
304             get
305             {
306                 return this.persistenceManager != null;
307             }
308         }
309
310         bool IsHandlerThread
311         {
312             get
313             {
314                 return this.isInHandler && this.handlerThreadId == Thread.CurrentThread.ManagedThreadId;
315             }
316         }
317
318         bool IsInTerminalState
319         {
320             get
321             {
322                 return this.state == WorkflowApplicationState.Unloaded || this.state == WorkflowApplicationState.Aborted;
323             }
324         }
325
326         public void AddInitialInstanceValues(IDictionary<XName, object> writeOnlyValues)
327         {
328             ThrowIfReadOnly();
329
330             if (writeOnlyValues != null)
331             {
332                 if (this.instanceMetadata == null)
333                 {
334                     this.instanceMetadata = new Dictionary<XName, InstanceValue>(writeOnlyValues.Count);
335                 }
336
337                 foreach (KeyValuePair<XName, object> pair in writeOnlyValues)
338                 {
339                     // We use the indexer so that we can replace keys that already exist
340                     this.instanceMetadata[pair.Key] = new InstanceValue(pair.Value, InstanceValueOptions.Optional | InstanceValueOptions.WriteOnly);
341                 }
342             }
343         }
344
345         // host-facing access to our cascading ExtensionManager resolution. Used by WorkflowApplicationEventArgs
346         internal IEnumerable<T> InternalGetExtensions<T>() where T : class
347         {
348             return base.GetExtensions<T>();
349         }
350
351
352         static void EventFrame(IAsyncResult result)
353         {
354             if (result.CompletedSynchronously)
355             {
356                 return;
357             }
358
359             WorkflowEventData data = (WorkflowEventData)result.AsyncState;
360             WorkflowApplication thisPtr = data.Instance;
361
362             bool done = true;
363
364             try
365             {
366                 Exception abortException = null;
367
368                 try
369                 {
370                     // The "false" is to notify that we are not still [....]
371                     done = data.NextCallback(result, thisPtr, false);
372                 }
373                 catch (Exception e)
374                 {
375                     if (Fx.IsFatal(e))
376                     {
377                         throw;
378                     }
379
380                     abortException = e;
381                 }
382
383                 if (abortException != null)
384                 {
385                     thisPtr.AbortInstance(abortException, true);
386                 }
387             }
388             finally
389             {
390                 if (done)
391                 {
392                     thisPtr.OnNotifyPaused();
393                 }
394             }
395         }
396
397         bool ShouldRaiseComplete(WorkflowInstanceState state)
398         {
399             return state == WorkflowInstanceState.Complete && !this.hasRaisedCompleted;
400         }
401
402         void Enqueue(InstanceOperation operation)
403         {
404             Enqueue(operation, false);
405         }
406
407         void Enqueue(InstanceOperation operation, bool push)
408         {
409             lock (this.pendingOperations)
410             {
411                 operation.ActionId = this.actionCount;
412
413                 if (this.isBusy)
414                 {
415                     // If base.IsReadOnly == false, we can't call the Controller yet because WorkflowInstance is not initialized.
416                     // But that's okay; if the instance isn't initialized then the scheduler's not running yet, so no need to pause it.
417                     if (operation.InterruptsScheduler && base.IsReadOnly)
418                     {
419                         this.Controller.RequestPause();
420                     }
421
422                     AddToPending(operation, push);
423                 }
424                 else
425                 {
426                     // first make sure we're ready to run
427                     if (operation.RequiresInitialized)
428                     {
429                         EnsureInitialized();
430                     }
431
432                     if (!operation.CanRun(this) && !this.IsInTerminalState)
433                     {
434                         AddToPending(operation, push);
435                     }
436                     else
437                     {
438                         // Action: Notifying an operation
439                         this.actionCount++;
440
441                         // We've essentially just notified this
442                         // operation that it is free to do its
443                         // thing
444                         try
445                         {
446                         }
447                         finally
448                         {
449                             operation.Notified = true;
450                             this.isBusy = true;
451                         }
452                     }
453                 }
454             }
455         }
456
457         void IncrementPendingUnenqueud()
458         {
459             lock (this.pendingOperations)
460             {
461                 this.pendingUnenqueued++;
462             }
463         }
464
465         void DecrementPendingUnenqueud()
466         {
467             lock (this.pendingOperations)
468             {
469                 this.pendingUnenqueued--;
470             }
471         }
472
473         void AddToPending(InstanceOperation operation, bool push)
474         {
475             if (base.IsReadOnly)
476             {
477                 // We're already initialized
478                 operation.RequiresInitialized = false;
479             }
480
481             if (push)
482             {
483                 this.pendingOperations.PushFront(operation);
484             }
485             else
486             {
487                 this.pendingOperations.Enqueue(operation);
488             }
489
490             operation.OnEnqueued();
491         }
492
493         bool Remove(InstanceOperation operation)
494         {
495             lock (this.pendingOperations)
496             {
497                 return this.pendingOperations.Remove(operation);
498             }
499         }
500
501         bool WaitForTurn(InstanceOperation operation, TimeSpan timeout)
502         {
503             Enqueue(operation);
504             return this.WaitForTurnNoEnqueue(operation, timeout);
505         }
506
507         bool WaitForTurnNoEnqueue(InstanceOperation operation, TimeSpan timeout)
508         {
509             if (!operation.WaitForTurn(timeout))
510             {
511                 if (Remove(operation))
512                 {
513                     throw FxTrace.Exception.AsError(new TimeoutException(SR.TimeoutOnOperation(timeout)));
514                 }
515             }
516             return true;
517         }        
518
519         bool WaitForTurnAsync(InstanceOperation operation, TimeSpan timeout, Action<object, TimeoutException> callback, object state)
520         {
521             return WaitForTurnAsync(operation, false, timeout, callback, state);
522         }
523
524         bool WaitForTurnAsync(InstanceOperation operation, bool push, TimeSpan timeout, Action<object, TimeoutException> callback, object state)
525         {
526             Enqueue(operation, push);
527
528             return this.WaitForTurnNoEnqueueAsync(operation, timeout, callback, state);
529         }
530
531         bool WaitForTurnNoEnqueueAsync(InstanceOperation operation, TimeSpan timeout, Action<object, TimeoutException> callback, object state)
532         {
533             if (waitAsyncCompleteCallback == null)
534             {
535                 waitAsyncCompleteCallback = new Action<object, TimeoutException>(OnWaitAsyncComplete);
536             }
537             return operation.WaitForTurnAsync(timeout, waitAsyncCompleteCallback, new WaitForTurnData(callback, state, operation, this));
538         }
539
540         static void OnWaitAsyncComplete(object state, TimeoutException exception)
541         {
542             WaitForTurnData data = (WaitForTurnData)state;
543
544             if (!data.Instance.Remove(data.Operation))
545             {
546                 exception = null;
547             }
548
549             data.Callback(data.State, exception);
550         }
551
552         // For when we know that the operation is non-null
553         // and notified (like in async paths)
554         void ForceNotifyOperationComplete()
555         {
556             OnNotifyPaused();
557         }
558
559         void NotifyOperationComplete(InstanceOperation operation)
560         {
561             if (operation != null && operation.Notified)
562             {
563                 OnNotifyPaused();
564             }
565         }
566
567         InstanceOperation FindOperation()
568         {
569             if (this.pendingOperations.Count > 0)
570             {
571                 // Special case the first one
572                 InstanceOperation temp = this.pendingOperations[0];
573
574                 if (temp.RequiresInitialized)
575                 {
576                     EnsureInitialized();
577                 }
578
579                 // Even if we can't run this operation we want to notify
580                 // it if all the operations are invalid.  This will cause
581                 // the Validate* method to throw to the caller.
582                 if (temp.CanRun(this) || this.IsInTerminalState)
583                 {
584                     // Action: Notifying an operation
585                     this.actionCount++;
586
587                     temp.Notified = true;
588                     this.pendingOperations.Dequeue();
589                     return temp;
590                 }
591                 else
592                 {
593                     for (int i = 0; i < this.pendingOperations.Count; i++)
594                     {
595                         temp = this.pendingOperations[i];
596
597                         if (temp.RequiresInitialized)
598                         {
599                             EnsureInitialized();
600                         }
601
602                         if (temp.CanRun(this))
603                         {
604                             // Action: Notifying an operation
605                             this.actionCount++;
606
607                             temp.Notified = true;
608                             this.pendingOperations.Remove(i);
609                             return temp;
610                         }
611                     }
612                 }
613             }
614
615             return null;
616         }
617
618         // assumes that we're called under the pendingOperations lock
619         void EnsureInitialized()
620         {
621             if (!base.IsReadOnly)
622             {
623                 // For newly created workflows (e.g. not the Load() case), we need to initialize now
624                 base.RegisterExtensionManager(this.extensions);
625                 base.Initialize(this.initialWorkflowArguments, this.rootExecutionProperties);
626
627                 // make sure we have a persistence manager if necessary
628                 if (this.persistenceManager == null && this.instanceStore != null)
629                 {
630                     Fx.Assert(this.Id != Guid.Empty, "should have a valid Id at this point");
631                     this.persistenceManager = new PersistenceManager(this.instanceStore, GetInstanceMetadata(), this.Id);
632                 }
633             }
634         }
635
636         protected override void OnNotifyPaused()
637         {
638             Fx.Assert(this.isBusy, "We're always busy when we get this notification.");
639
640             WorkflowInstanceState? localInstanceState = null;
641             if (base.IsReadOnly)
642             {
643                 localInstanceState = this.Controller.State;
644             }
645             WorkflowApplicationState localApplicationState = this.state;
646
647             bool stillSync = true;
648
649             while (stillSync)
650             {
651                 if (localInstanceState.HasValue && ShouldRaiseComplete(localInstanceState.Value))
652                 {
653                     Exception abortException = null;
654
655                     try
656                     {
657                         // We're about to notify the world that this instance is completed
658                         // so let's make it official.
659                         this.hasRaisedCompleted = true;
660
661                         if (completedHandler == null)
662                         {
663                             completedHandler = new CompletedEventHandler();
664                         }
665                         stillSync = completedHandler.Run(this);
666                     }
667                     catch (Exception e)
668                     {
669                         if (Fx.IsFatal(e))
670                         {
671                             throw;
672                         }
673
674                         abortException = e;
675                     }
676
677                     if (abortException != null)
678                     {
679                         AbortInstance(abortException, true);
680                     }
681                 }
682                 else
683                 {
684                     InstanceOperation toRun = null;
685                     bool shouldRunNow;
686                     bool shouldRaiseIdleNow;
687
688                     lock (this.pendingOperations)
689                     {
690                         toRun = FindOperation();
691
692                         // Cache the state in local variables to ensure that none 
693                         // of the decision points in the ensuing "if" statement flip 
694                         // when control gets out of the lock.
695                         shouldRunNow = (localInstanceState.HasValue && localInstanceState == WorkflowInstanceState.Runnable && localApplicationState == WorkflowApplicationState.Runnable);
696                         shouldRaiseIdleNow = this.hasExecutionOccurredSinceLastIdle &&
697                             localInstanceState.HasValue && localInstanceState == WorkflowInstanceState.Idle &&
698                             !this.hasRaisedCompleted && this.pendingUnenqueued == 0;
699
700                         if (toRun == null && !shouldRunNow && !shouldRaiseIdleNow)
701                         {
702                             this.isBusy = false;
703                             stillSync = false;
704                         }
705                     }
706
707                     if (toRun != null)
708                     {
709                         toRun.NotifyTurn();
710                         stillSync = false;
711                     }
712                     else if (shouldRaiseIdleNow)
713                     {
714                         this.hasExecutionOccurredSinceLastIdle = false;
715
716                         Fx.Assert(this.isBusy, "we must be busy if we're raising idle");
717
718                         Exception abortException = null;
719
720                         try
721                         {
722                             if (idleHandler == null)
723                             {
724                                 idleHandler = new IdleEventHandler();
725                             }
726                             stillSync = idleHandler.Run(this);
727                         }
728                         catch (Exception e)
729                         {
730                             if (Fx.IsFatal(e))
731                             {
732                                 throw;
733                             }
734
735                             abortException = e;
736                         }
737
738                         if (abortException != null)
739                         {
740                             AbortInstance(abortException, true);
741                         }
742                     }
743                     else if (shouldRunNow)
744                     {
745                         this.hasExecutionOccurredSinceLastIdle = true;
746
747                         // Action: Running the scheduler
748                         this.actionCount++;
749
750                         this.Controller.Run();
751                         stillSync = false;
752                     }
753                 }
754             }
755         }
756
757         // used by WorkflowInvoker in the InvokeAsync case
758         internal void GetCompletionStatus(out Exception terminationException, out bool cancelled)
759         {
760             IDictionary<string, object> dummyOutputs;
761             ActivityInstanceState completionState = this.Controller.GetCompletionState(out dummyOutputs, out terminationException);
762             Fx.Assert(completionState != ActivityInstanceState.Executing, "Activity cannot be executing when this method is called");
763             cancelled = (completionState == ActivityInstanceState.Canceled);
764         }
765
766         protected internal override void OnRequestAbort(Exception reason)
767         {
768             this.AbortInstance(reason, false);
769         }
770
771         public void Abort()
772         {
773             Abort(SR.DefaultAbortReason);
774         }
775
776         public void Abort(string reason)
777         {
778             this.Abort(reason, null);
779         }
780
781         void Abort(string reason, Exception innerException)
782         {
783             // This is pretty loose check, but it is okay if we
784             // go down the abort path multiple times
785             if (this.state != WorkflowApplicationState.Aborted)
786             {
787                 AbortInstance(new WorkflowApplicationAbortedException(reason, innerException), false);
788             }
789         }
790
791         void AbortPersistence()
792         {
793             if (this.persistenceManager != null)
794             {
795                 this.persistenceManager.Abort();
796             }
797
798             PersistencePipeline currentPersistencePipeline = this.persistencePipelineInUse;
799             if (currentPersistencePipeline != null)
800             {
801                 currentPersistencePipeline.Abort();
802             }
803         }
804
805         void AbortInstance(Exception reason, bool isWorkflowThread)
806         {
807             this.state = WorkflowApplicationState.Aborted;
808
809             // Need to ensure that either components see the Aborted state, this method sees the components, or both.
810             Thread.MemoryBarrier();
811
812             // We do this outside of the lock since persistence
813             // might currently be blocking access to the lock.
814             AbortPersistence();
815
816             if (isWorkflowThread)
817             {
818                 if (!this.hasCalledAbort)
819                 {
820                     this.hasCalledAbort = true;
821                     this.Controller.Abort(reason);
822
823                     // We should get off this thread because we're unsure of its state
824                     ScheduleTrackAndRaiseAborted(reason);
825                 }
826             }
827             else
828             {
829                 bool completeSelf = true;
830                 InstanceOperation operation = null;
831
832                 try
833                 {
834                     operation = new InstanceOperation();
835
836                     completeSelf = WaitForTurnAsync(operation, true, ActivityDefaults.AcquireLockTimeout, new Action<object, TimeoutException>(OnAbortWaitComplete), reason);
837
838                     if (completeSelf)
839                     {
840                         if (!this.hasCalledAbort)
841                         {
842                             this.hasCalledAbort = true;
843                             this.Controller.Abort(reason);
844
845                             // We need to get off this thread so we don't block the caller
846                             // of abort
847                             ScheduleTrackAndRaiseAborted(reason);
848                         }
849                     }
850                 }
851                 finally
852                 {
853                     if (completeSelf)
854                     {
855                         NotifyOperationComplete(operation);
856                     }
857                 }
858             }
859         }
860
861         void OnAbortWaitComplete(object state, TimeoutException exception)
862         {
863             if (exception != null)
864             {
865                 // We ---- this exception because we were simply doing our
866                 // best to get the lock.  Note that we won't proceed without
867                 // the lock because we may have already succeeded on another
868                 // thread.  Technically this abort call has failed.
869
870                 return;
871             }
872
873             bool shouldRaise = false;
874             Exception reason = (Exception)state;
875
876             try
877             {
878                 if (!this.hasCalledAbort)
879                 {
880                     shouldRaise = true;
881                     this.hasCalledAbort = true;
882                     this.Controller.Abort(reason);
883                 }
884             }
885             finally
886             {
887                 ForceNotifyOperationComplete();
888             }
889
890             if (shouldRaise)
891             {
892                 // We call this from this thread because we've already
893                 // had a thread switch
894                 TrackAndRaiseAborted(reason);
895             }
896         }
897
898         void ScheduleTrackAndRaiseAborted(Exception reason)
899         {
900             if (this.Controller.HasPendingTrackingRecords || this.Aborted != null)
901             {
902                 ActionItem.Schedule(new Action<object>(TrackAndRaiseAborted), reason);
903             }
904         }
905
906         // This is only ever called from an appropriate thread (not the thread
907         // that called abort unless it was an internal abort).
908         // This method is called without the lock.  We still provide single threaded
909         // guarantees to the Controller because:
910         //    * No other call can ever enter the executor again once the state has
911         //      switched to Aborted
912         //    * If this was an internal abort then the thread was fast pathing its
913         //      way out of the runtime and won't conflict
914         void TrackAndRaiseAborted(object state)
915         {
916             Exception reason = (Exception)state;
917
918             if (this.Controller.HasPendingTrackingRecords)
919             {
920                 try
921                 {
922                     IAsyncResult result = this.Controller.BeginFlushTrackingRecords(ActivityDefaults.TrackingTimeout, Fx.ThunkCallback(new AsyncCallback(OnAbortTrackingComplete)), reason);
923
924                     if (result.CompletedSynchronously)
925                     {
926                         this.Controller.EndFlushTrackingRecords(result);
927                     }
928                     else
929                     {
930                         return;
931                     }
932                 }
933                 catch (Exception e)
934                 {
935                     if (Fx.IsFatal(e))
936                     {
937                         throw;
938                     }
939
940                     // We ---- any exception here because we are on the abort path
941                     // and are doing a best effort to track this record.
942                 }
943             }
944
945             RaiseAborted(reason);
946         }
947
948         void OnAbortTrackingComplete(IAsyncResult result)
949         {
950             if (result.CompletedSynchronously)
951             {
952                 return;
953             }
954
955             Exception reason = (Exception)result.AsyncState;
956
957             try
958             {
959                 this.Controller.EndFlushTrackingRecords(result);
960             }
961             catch (Exception e)
962             {
963                 if (Fx.IsFatal(e))
964                 {
965                     throw;
966                 }
967
968                 // We ---- any exception here because we are on the abort path
969                 // and are doing a best effort to track this record.
970             }
971
972             RaiseAborted(reason);
973         }
974
975         void RaiseAborted(Exception reason)
976         {
977             if (this.invokeCompletedCallback == null)
978             {
979                 Action<WorkflowApplicationAbortedEventArgs> abortedHandler = this.Aborted;
980
981                 if (abortedHandler != null)
982                 {
983                     try
984                     {
985                         this.handlerThreadId = Thread.CurrentThread.ManagedThreadId;
986                         this.isInHandler = true;
987
988                         abortedHandler(new WorkflowApplicationAbortedEventArgs(this, reason));
989                     }
990                     finally
991                     {
992                         this.isInHandler = false;
993                     }
994                 }
995             }
996             else
997             {
998                 this.invokeCompletedCallback();
999             }
1000
1001             if (TD.WorkflowInstanceAbortedIsEnabled())
1002             {
1003                 TD.WorkflowInstanceAborted(this.Id.ToString(), reason);
1004             }
1005         }
1006
1007         public void Terminate(string reason)
1008         {
1009             Terminate(reason, ActivityDefaults.AcquireLockTimeout);
1010         }
1011
1012         public void Terminate(Exception reason)
1013         {
1014             Terminate(reason, ActivityDefaults.AcquireLockTimeout);
1015         }
1016
1017         public void Terminate(string reason, TimeSpan timeout)
1018         {
1019             if (string.IsNullOrEmpty(reason))
1020             {
1021                 throw FxTrace.Exception.ArgumentNullOrEmpty("reason");
1022             }
1023
1024             Terminate(new WorkflowApplicationTerminatedException(reason, this.Id), timeout);
1025         }
1026
1027         public void Terminate(Exception reason, TimeSpan timeout)
1028         {
1029             if (reason == null)
1030             {
1031                 throw FxTrace.Exception.ArgumentNull("reason");
1032             }
1033
1034             ThrowIfHandlerThread();
1035
1036             TimeoutHelper.ThrowIfNegativeArgument(timeout);
1037
1038             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1039             InstanceOperation operation = null;
1040
1041             try
1042             {
1043                 operation = new InstanceOperation();
1044
1045                 WaitForTurn(operation, timeoutHelper.RemainingTime());
1046
1047                 ValidateStateForTerminate();
1048
1049                 TerminateCore(reason);
1050
1051                 this.Controller.FlushTrackingRecords(timeoutHelper.RemainingTime());
1052             }
1053             finally
1054             {
1055                 NotifyOperationComplete(operation);
1056             }
1057         }
1058
1059         void TerminateCore(Exception reason)
1060         {
1061             this.Controller.Terminate(reason);
1062         }
1063
1064         public IAsyncResult BeginTerminate(string reason, AsyncCallback callback, object state)
1065         {
1066             return BeginTerminate(reason, ActivityDefaults.AcquireLockTimeout, callback, state);
1067         }
1068
1069         public IAsyncResult BeginTerminate(Exception reason, AsyncCallback callback, object state)
1070         {
1071             return BeginTerminate(reason, ActivityDefaults.AcquireLockTimeout, callback, state);
1072         }
1073
1074         public IAsyncResult BeginTerminate(string reason, TimeSpan timeout, AsyncCallback callback, object state)
1075         {
1076             if (string.IsNullOrEmpty(reason))
1077             {
1078                 throw FxTrace.Exception.ArgumentNullOrEmpty("reason");
1079             }
1080
1081             return BeginTerminate(new WorkflowApplicationTerminatedException(reason, this.Id), timeout, callback, state);
1082         }
1083
1084         public IAsyncResult BeginTerminate(Exception reason, TimeSpan timeout, AsyncCallback callback, object state)
1085         {
1086             if (reason == null)
1087             {
1088                 throw FxTrace.Exception.ArgumentNull("reason");
1089             }
1090
1091             ThrowIfHandlerThread();
1092
1093             TimeoutHelper.ThrowIfNegativeArgument(timeout);
1094
1095             return TerminateAsyncResult.Create(this, reason, timeout, callback, state);
1096         }
1097
1098         public void EndTerminate(IAsyncResult result)
1099         {
1100             TerminateAsyncResult.End(result);
1101         }
1102
1103         // called from the [....] and async paths
1104         void CancelCore()
1105         {
1106             // We only actually do any work if we haven't completed and we aren't
1107             // unloaded.
1108             if (!this.hasRaisedCompleted && this.state != WorkflowApplicationState.Unloaded)
1109             {
1110                 this.Controller.ScheduleCancel();
1111
1112                 // This is a loose check, but worst case scenario we call
1113                 // an extra, unnecessary Run
1114                 if (!this.hasCalledRun && !this.hasRaisedCompleted)
1115                 {
1116                     RunCore();
1117                 }
1118             }
1119         }
1120
1121         public void Cancel()
1122         {
1123             Cancel(ActivityDefaults.AcquireLockTimeout);
1124         }
1125
1126         public void Cancel(TimeSpan timeout)
1127         {
1128             ThrowIfHandlerThread();
1129
1130             TimeoutHelper.ThrowIfNegativeArgument(timeout);
1131
1132             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1133
1134             InstanceOperation operation = null;
1135
1136             try
1137             {
1138                 operation = new InstanceOperation();
1139
1140                 WaitForTurn(operation, timeoutHelper.RemainingTime());
1141
1142                 ValidateStateForCancel();
1143
1144                 CancelCore();
1145
1146                 this.Controller.FlushTrackingRecords(timeoutHelper.RemainingTime());
1147             }
1148             finally
1149             {
1150                 NotifyOperationComplete(operation);
1151             }
1152         }
1153
1154         public IAsyncResult BeginCancel(AsyncCallback callback, object state)
1155         {
1156             return BeginCancel(ActivityDefaults.AcquireLockTimeout, callback, state);
1157         }
1158
1159         public IAsyncResult BeginCancel(TimeSpan timeout, AsyncCallback callback, object state)
1160         {
1161             ThrowIfHandlerThread();
1162
1163             TimeoutHelper.ThrowIfNegativeArgument(timeout);
1164
1165             return CancelAsyncResult.Create(this, timeout, callback, state);
1166         }
1167
1168         public void EndCancel(IAsyncResult result)
1169         {
1170             CancelAsyncResult.End(result);
1171         }
1172
1173         // called on the Invoke path, this will go away when WorkflowInvoker implements WorkflowInstance directly
1174         static WorkflowApplication CreateInstance(Activity activity, IDictionary<string, object> inputs, WorkflowInstanceExtensionManager extensions, SynchronizationContext syncContext, Action invokeCompletedCallback)
1175         {
1176             // 1) Create the workflow instance
1177             Transaction ambientTransaction = Transaction.Current;
1178             List<Handle> workflowExecutionProperties = null;
1179
1180             if (ambientTransaction != null)
1181             {
1182                 // no need for a NoPersistHandle since the ActivityExecutor performs a no-persist zone
1183                 // as part of the RuntimeTransactionHandle processing
1184                 workflowExecutionProperties = new List<Handle>(1)
1185                 {
1186                     new RuntimeTransactionHandle(ambientTransaction)
1187                 };
1188             }
1189
1190             WorkflowApplication instance = new WorkflowApplication(activity, inputs, workflowExecutionProperties)
1191                 {
1192                     SynchronizationContext = syncContext
1193                 };
1194
1195             bool success = false;
1196
1197             try
1198             {
1199                 // 2) Take the executor lock before allowing extensions to be added
1200                 instance.isBusy = true;
1201
1202                 // 3) Add extensions
1203                 if (extensions != null)
1204                 {
1205                     instance.extensions = extensions;
1206                 }
1207
1208                 // 4) Setup miscellaneous state
1209                 instance.invokeCompletedCallback = invokeCompletedCallback;
1210
1211                 success = true;
1212             }
1213             finally
1214             {
1215                 if (!success)
1216                 {
1217                     instance.isBusy = false;
1218                 }
1219             }
1220
1221             return instance;
1222         }
1223
1224         static void RunInstance(WorkflowApplication instance)
1225         {
1226             // We still have the lock because we took it in Create
1227
1228             // first make sure we're ready to run
1229             instance.EnsureInitialized();
1230
1231             // Shortcut path for resuming the instance
1232             instance.RunCore();
1233
1234             instance.hasExecutionOccurredSinceLastIdle = true;
1235             instance.Controller.Run();
1236         }
1237
1238         static WorkflowApplication StartInvoke(Activity activity, IDictionary<string, object> inputs, WorkflowInstanceExtensionManager extensions, SynchronizationContext syncContext, Action invokeCompletedCallback, AsyncInvokeContext invokeContext)
1239         {
1240             WorkflowApplication instance = CreateInstance(activity, inputs, extensions, syncContext, invokeCompletedCallback);
1241             if (invokeContext != null)
1242             {
1243                 invokeContext.WorkflowApplication = instance;
1244             }
1245             RunInstance(instance);
1246             return instance;
1247         }
1248
1249         internal static IDictionary<string, object> Invoke(Activity activity, IDictionary<string, object> inputs, WorkflowInstanceExtensionManager extensions, TimeSpan timeout)
1250         {
1251             Fx.Assert(activity != null, "Activity must not be null.");
1252
1253             // Create the invoke synchronization context
1254             PumpBasedSynchronizationContext syncContext = new PumpBasedSynchronizationContext(timeout);
1255             WorkflowApplication instance = CreateInstance(activity, inputs, extensions, syncContext, new Action(syncContext.OnInvokeCompleted));
1256             // Wait for completion
1257             try
1258             {
1259                 RunInstance(instance);
1260                 syncContext.DoPump();
1261
1262             }
1263             catch (TimeoutException)
1264             {
1265                 instance.Abort(SR.AbortingDueToInstanceTimeout);
1266                 throw;
1267             }
1268
1269             Exception completionException = null;
1270             IDictionary<string, object> outputs = null;
1271
1272             if (instance.Controller.State == WorkflowInstanceState.Aborted)
1273             {
1274                 completionException = new WorkflowApplicationAbortedException(SR.DefaultAbortReason, instance.Controller.GetAbortReason());
1275             }
1276             else
1277             {
1278                 Fx.Assert(instance.Controller.State == WorkflowInstanceState.Complete, "We should only get here when we are completed.");
1279
1280                 instance.Controller.GetCompletionState(out outputs, out completionException);
1281             }
1282
1283             if (completionException != null)
1284             {
1285                 throw FxTrace.Exception.AsError(completionException);
1286             }
1287
1288             return outputs;
1289         }
1290
1291         internal static IAsyncResult BeginInvoke(Activity activity, IDictionary<string, object> inputs, WorkflowInstanceExtensionManager extensions, TimeSpan timeout, SynchronizationContext syncContext, AsyncInvokeContext invokeContext, AsyncCallback callback, object state)
1292         {
1293             Fx.Assert(activity != null, "The activity must not be null.");
1294
1295             return new InvokeAsyncResult(activity, inputs, extensions, timeout, syncContext, invokeContext, callback, state);
1296         }
1297
1298         internal static IDictionary<string, object> EndInvoke(IAsyncResult result)
1299         {
1300             return InvokeAsyncResult.End(result);
1301         }
1302
1303         public void Run()
1304         {
1305             Run(ActivityDefaults.AcquireLockTimeout);
1306         }
1307
1308         public void Run(TimeSpan timeout)
1309         {
1310             InternalRun(timeout, true);
1311         }
1312
1313         void InternalRun(TimeSpan timeout, bool isUserRun)
1314         {
1315             ThrowIfHandlerThread();
1316
1317             TimeoutHelper.ThrowIfNegativeArgument(timeout);
1318
1319             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1320             InstanceOperation operation = null;
1321
1322             try
1323             {
1324                 operation = new InstanceOperation();
1325
1326                 WaitForTurn(operation, timeoutHelper.RemainingTime());
1327
1328                 ValidateStateForRun();
1329
1330                 if (isUserRun)
1331                 {
1332                     // We set this to true here so that idle is raised
1333                     // regardless of whether the call to Run resulted
1334                     // in execution.
1335                     this.hasExecutionOccurredSinceLastIdle = true;
1336                 }
1337
1338                 RunCore();
1339
1340                 this.Controller.FlushTrackingRecords(timeoutHelper.RemainingTime());
1341             }
1342             finally
1343             {
1344                 NotifyOperationComplete(operation);
1345             }
1346         }
1347
1348         void RunCore()
1349         {
1350             if (!this.hasCalledRun)
1351             {
1352                 this.hasCalledRun = true;
1353             }
1354
1355             this.state = WorkflowApplicationState.Runnable;
1356         }
1357
1358         public IAsyncResult BeginRun(AsyncCallback callback, object state)
1359         {
1360             return BeginRun(ActivityDefaults.AcquireLockTimeout, callback, state);
1361         }
1362
1363         public IAsyncResult BeginRun(TimeSpan timeout, AsyncCallback callback, object state)
1364         {
1365             return BeginInternalRun(timeout, true, callback, state);
1366         }
1367
1368         IAsyncResult BeginInternalRun(TimeSpan timeout, bool isUserRun, AsyncCallback callback, object state)
1369         {
1370             ThrowIfHandlerThread();
1371
1372             TimeoutHelper.ThrowIfNegativeArgument(timeout);
1373
1374             return RunAsyncResult.Create(this, isUserRun, timeout, callback, state);
1375         }
1376
1377         public void EndRun(IAsyncResult result)
1378         {
1379             RunAsyncResult.End(result);
1380         }
1381
1382         // shared by Load/BeginLoad
1383         bool IsLoadTransactionRequired()
1384         {
1385             return base.GetExtensions<IPersistencePipelineModule>().Any(module => module.IsLoadTransactionRequired);
1386         }
1387
1388         void CreatePersistenceManager()
1389         {
1390             PersistenceManager newManager = new PersistenceManager(this.InstanceStore, GetInstanceMetadata(), this.instanceId);
1391             SetPersistenceManager(newManager);
1392         }
1393
1394         // shared by Load(WorkflowApplicationInstance)/BeginLoad*
1395         void SetPersistenceManager(PersistenceManager newManager)
1396         {
1397             Fx.Assert(this.persistenceManager == null, "SetPersistenceManager should only be called once");
1398
1399             // first register our extensions since we'll need them to construct the pipeline
1400             base.RegisterExtensionManager(this.extensions);
1401             this.persistenceManager = newManager;
1402         }
1403
1404         // shared by Load/BeginLoad
1405         PersistencePipeline ProcessInstanceValues(IDictionary<XName, InstanceValue> values, out object deserializedRuntimeState)
1406         {
1407             PersistencePipeline result = null;
1408             deserializedRuntimeState = ExtractRuntimeState(values, this.persistenceManager.InstanceId);
1409
1410             if (HasPersistenceModule)
1411             {
1412                 IEnumerable<IPersistencePipelineModule> modules = base.GetExtensions<IPersistencePipelineModule>();
1413                 result = new PersistencePipeline(modules);
1414                 result.SetLoadedValues(values);
1415             }
1416
1417             return result;
1418         }
1419
1420         static ActivityExecutor ExtractRuntimeState(IDictionary<XName, InstanceValue> values, Guid instanceId)
1421         {
1422             InstanceValue value;
1423             if (values.TryGetValue(WorkflowNamespace.Workflow, out value))
1424             {
1425                 ActivityExecutor result = value.Value as ActivityExecutor;
1426                 if (result != null)
1427                 {
1428                     return result;
1429                 }
1430             }
1431             throw FxTrace.Exception.AsError(new InstancePersistenceException(SR.WorkflowInstanceNotFoundInStore(instanceId)));
1432         }
1433
1434         public static void CreateDefaultInstanceOwner(InstanceStore instanceStore, WorkflowIdentity definitionIdentity, WorkflowIdentityFilter identityFilter)
1435         {
1436             CreateDefaultInstanceOwner(instanceStore, definitionIdentity, identityFilter, ActivityDefaults.OpenTimeout);
1437         }
1438
1439         public static void CreateDefaultInstanceOwner(InstanceStore instanceStore, WorkflowIdentity definitionIdentity, WorkflowIdentityFilter identityFilter, TimeSpan timeout)
1440         {
1441             if (instanceStore == null)
1442             {
1443                 throw FxTrace.Exception.ArgumentNull("instanceStore");
1444             }
1445             if (instanceStore.DefaultInstanceOwner != null)
1446             {
1447                 throw FxTrace.Exception.Argument("instanceStore", SR.InstanceStoreHasDefaultOwner);
1448             }
1449
1450             CreateWorkflowOwnerWithIdentityCommand command = GetCreateOwnerCommand(definitionIdentity, identityFilter);
1451             InstanceView commandResult = ExecuteInstanceCommandWithTemporaryHandle(instanceStore, command, timeout);
1452             instanceStore.DefaultInstanceOwner = commandResult.InstanceOwner;
1453         }
1454
1455         public static IAsyncResult BeginCreateDefaultInstanceOwner(InstanceStore instanceStore, WorkflowIdentity definitionIdentity,
1456             WorkflowIdentityFilter identityFilter, AsyncCallback callback, object state)
1457         {
1458             return BeginCreateDefaultInstanceOwner(instanceStore, definitionIdentity, identityFilter, ActivityDefaults.OpenTimeout, callback, state);
1459         }
1460
1461         public static IAsyncResult BeginCreateDefaultInstanceOwner(InstanceStore instanceStore, WorkflowIdentity definitionIdentity,
1462             WorkflowIdentityFilter identityFilter, TimeSpan timeout, AsyncCallback callback, object state)
1463         {
1464             if (instanceStore == null)
1465             {
1466                 throw FxTrace.Exception.ArgumentNull("instanceStore");
1467             }
1468             if (instanceStore.DefaultInstanceOwner != null)
1469             {
1470                 throw FxTrace.Exception.Argument("instanceStore", SR.InstanceStoreHasDefaultOwner);
1471             }
1472
1473             CreateWorkflowOwnerWithIdentityCommand command = GetCreateOwnerCommand(definitionIdentity, identityFilter);
1474             return new InstanceCommandWithTemporaryHandleAsyncResult(instanceStore, command, timeout, callback, state);
1475         }
1476
1477         public static void EndCreateDefaultInstanceOwner(IAsyncResult asyncResult)
1478         {
1479             InstanceStore instanceStore;
1480             InstanceView commandResult;
1481             InstanceCommandWithTemporaryHandleAsyncResult.End(asyncResult, out instanceStore, out commandResult);
1482             instanceStore.DefaultInstanceOwner = commandResult.InstanceOwner;
1483         }
1484
1485         public static void DeleteDefaultInstanceOwner(InstanceStore instanceStore)
1486         {
1487             DeleteDefaultInstanceOwner(instanceStore, ActivityDefaults.CloseTimeout);
1488         }
1489
1490         public static void DeleteDefaultInstanceOwner(InstanceStore instanceStore, TimeSpan timeout)
1491         {
1492             if (instanceStore == null)
1493             {
1494                 throw FxTrace.Exception.ArgumentNull("instanceStore");
1495             }
1496             if (instanceStore.DefaultInstanceOwner == null)
1497             {
1498                 return;
1499             }
1500
1501             DeleteWorkflowOwnerCommand command = new DeleteWorkflowOwnerCommand();
1502             ExecuteInstanceCommandWithTemporaryHandle(instanceStore, command, timeout);
1503             instanceStore.DefaultInstanceOwner = null;
1504         }
1505
1506         public static IAsyncResult BeginDeleteDefaultInstanceOwner(InstanceStore instanceStore, AsyncCallback callback, object state)
1507         {
1508             return BeginDeleteDefaultInstanceOwner(instanceStore, ActivityDefaults.CloseTimeout, callback, state);
1509         }
1510
1511         public static IAsyncResult BeginDeleteDefaultInstanceOwner(InstanceStore instanceStore, TimeSpan timeout, AsyncCallback callback, object state)
1512         {
1513             if (instanceStore == null)
1514             {
1515                 throw FxTrace.Exception.ArgumentNull("instanceStore");
1516             }
1517             if (instanceStore.DefaultInstanceOwner == null)
1518             {
1519                 return new CompletedAsyncResult(callback, state);
1520             }
1521
1522             DeleteWorkflowOwnerCommand command = new DeleteWorkflowOwnerCommand();
1523             return new InstanceCommandWithTemporaryHandleAsyncResult(instanceStore, command, timeout, callback, state);
1524         }
1525
1526         public static void EndDeleteDefaultInstanceOwner(IAsyncResult asyncResult)
1527         {
1528             InstanceStore instanceStore;
1529             InstanceView commandResult;
1530
1531             if (asyncResult is CompletedAsyncResult)
1532             {
1533                 CompletedAsyncResult.End(asyncResult);
1534                 return;
1535             }
1536
1537             InstanceCommandWithTemporaryHandleAsyncResult.End(asyncResult, out instanceStore, out commandResult);            
1538             instanceStore.DefaultInstanceOwner = null;
1539         }
1540
1541         static InstanceView ExecuteInstanceCommandWithTemporaryHandle(InstanceStore instanceStore, InstancePersistenceCommand command, TimeSpan timeout)
1542         {
1543             InstanceHandle temporaryHandle = null;
1544             try
1545             {
1546                 temporaryHandle = instanceStore.CreateInstanceHandle();
1547                 return instanceStore.Execute(temporaryHandle, command, timeout);
1548             }
1549             finally
1550             {
1551                 if (temporaryHandle != null)
1552                 {
1553                     temporaryHandle.Free();
1554                 }
1555             }
1556         }
1557
1558         static CreateWorkflowOwnerWithIdentityCommand GetCreateOwnerCommand(WorkflowIdentity definitionIdentity, WorkflowIdentityFilter identityFilter)
1559         {
1560             if (!identityFilter.IsValid())
1561             {
1562                 throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("identityFilter"));
1563             }
1564             if (definitionIdentity == null && identityFilter != WorkflowIdentityFilter.Any)
1565             {
1566                 // This API isn't useful for null identity, because WFApp only adds a default WorkflowHostType
1567                 // to instances with non-null identity.
1568                 throw FxTrace.Exception.Argument("definitionIdentity", SR.CannotCreateOwnerWithoutIdentity);
1569             }
1570             return new CreateWorkflowOwnerWithIdentityCommand
1571             {
1572                 InstanceOwnerMetadata =
1573                 {
1574                     { WorkflowNamespace.WorkflowHostType, new InstanceValue(Workflow45Namespace.WorkflowApplication) },
1575                     { Workflow45Namespace.DefinitionIdentities, new InstanceValue(new Collection<WorkflowIdentity> { definitionIdentity }) },
1576                     { Workflow45Namespace.DefinitionIdentityFilter, new InstanceValue(identityFilter) },
1577                 }
1578             };
1579         }
1580
1581         public static WorkflowApplicationInstance GetRunnableInstance(InstanceStore instanceStore)
1582         {
1583             return GetRunnableInstance(instanceStore, ActivityDefaults.LoadTimeout);
1584         }
1585
1586         public static WorkflowApplicationInstance GetRunnableInstance(InstanceStore instanceStore, TimeSpan timeout)
1587         {
1588             if (instanceStore == null)
1589             {
1590                 throw FxTrace.Exception.ArgumentNull("instanceStore");
1591             }
1592             TimeoutHelper.ThrowIfNegativeArgument(timeout);
1593             if (instanceStore.DefaultInstanceOwner == null)
1594             {
1595                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.GetRunnableRequiresOwner));
1596             }
1597
1598             PersistenceManager newManager = new PersistenceManager(instanceStore, null);
1599             return LoadCore(timeout, true, newManager);
1600         }
1601
1602         public static IAsyncResult BeginGetRunnableInstance(InstanceStore instanceStore, AsyncCallback callback, object state)
1603         {
1604             return BeginGetRunnableInstance(instanceStore, ActivityDefaults.LoadTimeout, callback, state);
1605         }
1606
1607         public static IAsyncResult BeginGetRunnableInstance(InstanceStore instanceStore, TimeSpan timeout, AsyncCallback callback, object state)
1608         {
1609             if (instanceStore == null)
1610             {
1611                 throw FxTrace.Exception.ArgumentNull("instanceStore");
1612             }
1613             TimeoutHelper.ThrowIfNegativeArgument(timeout);
1614             if (instanceStore.DefaultInstanceOwner == null)
1615             {
1616                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.GetRunnableRequiresOwner));
1617             }
1618
1619             PersistenceManager newManager = new PersistenceManager(instanceStore, null);
1620             return new LoadAsyncResult(null, newManager, true, timeout, callback, state);
1621      }
1622
1623         public static WorkflowApplicationInstance EndGetRunnableInstance(IAsyncResult asyncResult)
1624         {
1625             return LoadAsyncResult.EndAndCreateInstance(asyncResult);
1626         }
1627
1628         public static WorkflowApplicationInstance GetInstance(Guid instanceId, InstanceStore instanceStore)
1629         {
1630             return GetInstance(instanceId, instanceStore, ActivityDefaults.LoadTimeout);
1631         }
1632
1633         public static WorkflowApplicationInstance GetInstance(Guid instanceId, InstanceStore instanceStore, TimeSpan timeout)
1634         {
1635             if (instanceId == Guid.Empty)
1636             {
1637                 throw FxTrace.Exception.ArgumentNullOrEmpty("instanceId");
1638             }
1639             if (instanceStore == null)
1640             {
1641                 throw FxTrace.Exception.ArgumentNull("instanceStore");
1642             }
1643             TimeoutHelper.ThrowIfNegativeArgument(timeout);
1644
1645             PersistenceManager newManager = new PersistenceManager(instanceStore, null, instanceId);
1646             return LoadCore(timeout, false, newManager);
1647         }
1648
1649         public static IAsyncResult BeginGetInstance(Guid instanceId, InstanceStore instanceStore, AsyncCallback callback, object state)
1650         {
1651             return BeginGetInstance(instanceId, instanceStore, ActivityDefaults.LoadTimeout, callback, state);
1652         }
1653
1654         public static IAsyncResult BeginGetInstance(Guid instanceId, InstanceStore instanceStore, TimeSpan timeout, AsyncCallback callback, object state)
1655         {
1656             if (instanceId == Guid.Empty)
1657             {
1658                 throw FxTrace.Exception.ArgumentNullOrEmpty("instanceId");
1659             }
1660             if (instanceStore == null)
1661             {
1662                 throw FxTrace.Exception.ArgumentNull("instanceStore");
1663             }
1664             TimeoutHelper.ThrowIfNegativeArgument(timeout);
1665
1666             PersistenceManager newManager = new PersistenceManager(instanceStore, null, instanceId);
1667             return new LoadAsyncResult(null, newManager, false, timeout, callback, state);
1668         }
1669
1670         public static WorkflowApplicationInstance EndGetInstance(IAsyncResult asyncResult)
1671         {
1672             return LoadAsyncResult.EndAndCreateInstance(asyncResult);
1673         }
1674
1675         public void Load(WorkflowApplicationInstance instance)
1676         {
1677             Load(instance, ActivityDefaults.LoadTimeout);
1678         }
1679
1680         public void Load(WorkflowApplicationInstance instance, TimeSpan timeout)
1681         {
1682             Load(instance, null, timeout);
1683         }
1684
1685         public void Load(WorkflowApplicationInstance instance, DynamicUpdateMap updateMap)
1686         {
1687             Load(instance, updateMap, ActivityDefaults.LoadTimeout);
1688         }
1689
1690         public void Load(WorkflowApplicationInstance instance, DynamicUpdateMap updateMap, TimeSpan timeout)
1691         {
1692             ThrowIfAborted();
1693             ThrowIfReadOnly(); // only allow a single Load() or Run()
1694             if (instance == null)
1695             {
1696                 throw FxTrace.Exception.ArgumentNull("instance");
1697             }
1698
1699             TimeoutHelper.ThrowIfNegativeArgument(timeout);
1700
1701             if (this.instanceIdSet)
1702             {
1703                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.WorkflowApplicationAlreadyHasId));
1704             }
1705             if (this.initialWorkflowArguments != null)
1706             {
1707                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CannotUseInputsWithLoad));
1708             }
1709             if (this.InstanceStore != null && this.InstanceStore != instance.InstanceStore)
1710             {
1711                 throw FxTrace.Exception.Argument("instance", SR.InstanceStoreDoesntMatchWorkflowApplication);
1712             }
1713
1714             instance.MarkAsLoaded();
1715
1716             InstanceOperation operation = new InstanceOperation { RequiresInitialized = false };
1717
1718             try
1719             {
1720                 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1721                 WaitForTurn(operation, timeoutHelper.RemainingTime());
1722
1723                 ValidateStateForLoad();
1724
1725                 this.instanceId = instance.InstanceId;
1726                 this.instanceIdSet = true;
1727                 if (this.instanceStore == null)
1728                 {
1729                     this.instanceStore = instance.InstanceStore;
1730                 }
1731
1732                 PersistenceManager newManager = (PersistenceManager)instance.PersistenceManager;
1733                 newManager.SetInstanceMetadata(GetInstanceMetadata());
1734                 SetPersistenceManager(newManager);
1735
1736                 LoadCore(updateMap, timeoutHelper, false, instance.Values);
1737             }
1738             finally
1739             {
1740                 NotifyOperationComplete(operation);
1741             }
1742         }
1743
1744         public void LoadRunnableInstance()
1745         {
1746             LoadRunnableInstance(ActivityDefaults.LoadTimeout);
1747         }
1748
1749         public void LoadRunnableInstance(TimeSpan timeout)
1750         {
1751             ThrowIfReadOnly(); // only allow a single Load() or Run()
1752
1753             TimeoutHelper.ThrowIfNegativeArgument(timeout);
1754
1755             if (this.InstanceStore == null)
1756             {
1757                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.LoadingWorkflowApplicationRequiresInstanceStore));
1758             }
1759             if (this.instanceIdSet)
1760             {
1761                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.WorkflowApplicationAlreadyHasId));
1762             }
1763             if (this.initialWorkflowArguments != null)
1764             {
1765                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CannotUseInputsWithLoad));
1766             }
1767             if (this.persistenceManager != null)
1768             {
1769                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.TryLoadRequiresOwner));
1770             }
1771
1772             InstanceOperation operation = new InstanceOperation { RequiresInitialized = false };
1773
1774             try
1775             {
1776                 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1777                 WaitForTurn(operation, timeoutHelper.RemainingTime());
1778
1779                 ValidateStateForLoad();
1780
1781                 RegisterExtensionManager(this.extensions);
1782                 this.persistenceManager = new PersistenceManager(InstanceStore, GetInstanceMetadata());
1783
1784                 if (!this.persistenceManager.IsInitialized)
1785                 {
1786                     throw FxTrace.Exception.AsError(new InvalidOperationException(SR.TryLoadRequiresOwner));
1787                 }
1788
1789                 LoadCore(null, timeoutHelper, true);
1790             }
1791             finally
1792             {
1793                 NotifyOperationComplete(operation);
1794             }
1795         }
1796
1797         public void Load(Guid instanceId)
1798         {
1799             Load(instanceId, ActivityDefaults.LoadTimeout);
1800         }
1801
1802         public void Load(Guid instanceId, TimeSpan timeout)
1803         {
1804             ThrowIfAborted();
1805             ThrowIfReadOnly(); // only allow a single Load() or Run()
1806             if (instanceId == Guid.Empty)
1807             {
1808                 throw FxTrace.Exception.ArgumentNullOrEmpty("instanceId");
1809             }
1810
1811             TimeoutHelper.ThrowIfNegativeArgument(timeout);
1812
1813             if (this.InstanceStore == null)
1814             {
1815                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.LoadingWorkflowApplicationRequiresInstanceStore));
1816             }
1817             if (this.instanceIdSet)
1818             {
1819                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.WorkflowApplicationAlreadyHasId));
1820             }
1821             if (this.initialWorkflowArguments != null)
1822             {
1823                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CannotUseInputsWithLoad));
1824             }
1825
1826             InstanceOperation operation = new InstanceOperation { RequiresInitialized = false };
1827
1828             try
1829             {
1830                 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1831                 WaitForTurn(operation, timeoutHelper.RemainingTime());
1832
1833                 ValidateStateForLoad();
1834
1835                 this.instanceId = instanceId;
1836                 this.instanceIdSet = true;
1837
1838                 CreatePersistenceManager();
1839                 LoadCore(null, timeoutHelper, false);
1840             }
1841             finally
1842             {
1843                 NotifyOperationComplete(operation);
1844             }
1845         }
1846
1847         void LoadCore(DynamicUpdateMap updateMap, TimeoutHelper timeoutHelper, bool loadAny, IDictionary<XName, InstanceValue> values = null)
1848         {
1849             if (values == null)
1850             {
1851                 if (!this.persistenceManager.IsInitialized)
1852                 {
1853                     this.persistenceManager.Initialize(this.DefinitionIdentity, timeoutHelper.RemainingTime());
1854                 }
1855             }
1856             else
1857             {
1858                 Fx.Assert(this.persistenceManager.IsInitialized, "Caller should have initialized Persistence Manager");
1859                 Fx.Assert(this.instanceIdSet, "Caller should have set InstanceId");
1860             }
1861
1862             PersistencePipeline pipeline = null;
1863             WorkflowPersistenceContext context = null;
1864             TransactionScope scope = null;
1865             bool success = false;
1866             Exception abortReasonInnerException = null;
1867             try
1868             {
1869                 InitializePersistenceContext(IsLoadTransactionRequired(), timeoutHelper, out context, out scope);
1870
1871                 if (values == null)
1872                 {
1873                     values = LoadValues(this.persistenceManager, timeoutHelper, loadAny);
1874                     if (loadAny)
1875                     {
1876                         if (this.instanceIdSet)
1877                         {
1878                             throw FxTrace.Exception.AsError(new InvalidOperationException(SR.WorkflowApplicationAlreadyHasId));
1879                         }
1880
1881                         this.instanceId = this.persistenceManager.InstanceId;
1882                         this.instanceIdSet = true;
1883                     }
1884                 }
1885                 object deserializedRuntimeState;
1886                 pipeline = ProcessInstanceValues(values, out deserializedRuntimeState);
1887
1888                 if (pipeline != null)
1889                 {
1890                     try
1891                     {
1892                         this.persistencePipelineInUse = pipeline;
1893
1894                         // Need to ensure that either we see the Aborted state, AbortInstance sees us, or both.
1895                         Thread.MemoryBarrier();
1896
1897                         if (this.state == WorkflowApplicationState.Aborted)
1898                         {
1899                             throw FxTrace.Exception.AsError(new OperationCanceledException(SR.DefaultAbortReason));
1900                         }
1901
1902                         pipeline.EndLoad(pipeline.BeginLoad(timeoutHelper.RemainingTime(), null, null));
1903                     }
1904                     finally
1905                     {
1906                         this.persistencePipelineInUse = null;
1907                     }
1908                 }
1909                 
1910                 try
1911                 {
1912                     base.Initialize(deserializedRuntimeState, updateMap);
1913                     if (updateMap != null)
1914                     {
1915                         UpdateInstanceMetadata();
1916                     }
1917                 }
1918                 catch (InstanceUpdateException e)
1919                 {
1920                     abortReasonInnerException = e;
1921                     throw;
1922                 }
1923                 catch (VersionMismatchException e)
1924                 {
1925                     abortReasonInnerException = e;
1926                     throw;
1927                 }
1928
1929                 success = true;
1930             }
1931             finally
1932             {
1933                 CompletePersistenceContext(context, scope, success);
1934                 if (!success)
1935                 {
1936                     this.AbortDueToException(abortReasonInnerException);
1937                 }
1938             }
1939
1940             if (pipeline != null)
1941             {
1942                 pipeline.Publish();
1943             }
1944         }
1945
1946         private void AbortDueToException(Exception e)
1947         {
1948             if (e is InstanceUpdateException)
1949             {
1950                 this.Abort(SR.AbortingDueToDynamicUpdateFailure, e);
1951             }
1952             else if (e is VersionMismatchException)
1953             {
1954                 this.Abort(SR.AbortingDueToVersionMismatch, e);
1955             }
1956             else
1957             {
1958                 this.Abort(SR.AbortingDueToLoadFailure);
1959             }
1960         }
1961
1962         static WorkflowApplicationInstance LoadCore(TimeSpan timeout, bool loadAny, PersistenceManager persistenceManager)
1963         {
1964             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1965
1966             if (!persistenceManager.IsInitialized)
1967             {
1968                 persistenceManager.Initialize(unknownIdentity, timeoutHelper.RemainingTime());
1969             }
1970
1971             WorkflowPersistenceContext context = null;
1972             TransactionScope scope = null;
1973             WorkflowApplicationInstance result = null;
1974             try
1975             {
1976                 InitializePersistenceContext(false, timeoutHelper, out context, out scope);
1977
1978                 IDictionary<XName, InstanceValue> values = LoadValues(persistenceManager, timeoutHelper, loadAny);
1979                 ActivityExecutor deserializedRuntimeState = ExtractRuntimeState(values, persistenceManager.InstanceId);
1980                 result = new WorkflowApplicationInstance(persistenceManager, values, deserializedRuntimeState.WorkflowIdentity);
1981             }
1982             finally
1983             {
1984                 bool success = (result != null);
1985                 CompletePersistenceContext(context, scope, success);
1986                 if (!success)
1987                 {
1988                     persistenceManager.Abort();
1989                 }
1990             }
1991
1992             return result;
1993         }
1994
1995         static void InitializePersistenceContext(bool isTransactionRequired, TimeoutHelper timeoutHelper,
1996             out WorkflowPersistenceContext context, out TransactionScope scope)
1997         {
1998             context = new WorkflowPersistenceContext(isTransactionRequired, timeoutHelper.OriginalTimeout);
1999             scope = TransactionHelper.CreateTransactionScope(context.PublicTransaction);
2000         }
2001
2002         static void CompletePersistenceContext(WorkflowPersistenceContext context, TransactionScope scope, bool success)
2003         {
2004             // Clean up the transaction scope regardless of failure
2005             TransactionHelper.CompleteTransactionScope(ref scope);
2006
2007             if (context != null)
2008             {
2009                 if (success)
2010                 {
2011                     context.Complete();
2012                 }
2013                 else
2014                 {
2015                     context.Abort();
2016                 }
2017             }
2018         }
2019
2020         static IDictionary<XName, InstanceValue> LoadValues(PersistenceManager persistenceManager, TimeoutHelper timeoutHelper, bool loadAny)
2021         {
2022             IDictionary<XName, InstanceValue> values;
2023             if (loadAny)
2024             {
2025                 if (!persistenceManager.TryLoad(timeoutHelper.RemainingTime(), out values))
2026                 {
2027                     throw FxTrace.Exception.AsError(new InstanceNotReadyException(SR.NoRunnableInstances));
2028                 }
2029             }
2030             else
2031             {
2032                 values = persistenceManager.Load(timeoutHelper.RemainingTime());
2033             }
2034
2035             return values;
2036         }
2037
2038         internal static void DiscardInstance(PersistenceManagerBase persistanceManager, TimeSpan timeout)
2039         {
2040             PersistenceManager manager = (PersistenceManager)persistanceManager;
2041             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
2042             UnlockInstance(manager, timeoutHelper);
2043         }
2044
2045         internal static IAsyncResult BeginDiscardInstance(PersistenceManagerBase persistanceManager, TimeSpan timeout, AsyncCallback callback, object state)
2046         {
2047             PersistenceManager manager = (PersistenceManager)persistanceManager;
2048             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
2049             return new UnlockInstanceAsyncResult(manager, timeoutHelper, callback, state);
2050         }
2051
2052         internal static void EndDiscardInstance(IAsyncResult asyncResult)
2053         {
2054             UnlockInstanceAsyncResult.End(asyncResult);
2055         }
2056
2057         static void UnlockInstance(PersistenceManager persistenceManager, TimeoutHelper timeoutHelper)
2058         {
2059             try
2060             {
2061                 if (persistenceManager.OwnerWasCreated)
2062                 {
2063                     // if the owner was created by this WorkflowApplication, delete it.
2064                     // This implicitly unlocks the instance.
2065                     persistenceManager.DeleteOwner(timeoutHelper.RemainingTime());
2066                 }
2067                 else
2068                 {
2069                     persistenceManager.Unlock(timeoutHelper.RemainingTime());
2070                 }
2071             }
2072             finally
2073             {
2074                 persistenceManager.Abort();
2075             }
2076         }
2077
2078         internal static IList<ActivityBlockingUpdate> GetActivitiesBlockingUpdate(WorkflowApplicationInstance instance, DynamicUpdateMap updateMap)
2079         {
2080             object deserializedRuntimeState = ExtractRuntimeState(instance.Values, instance.InstanceId);
2081             return WorkflowInstance.GetActivitiesBlockingUpdate(deserializedRuntimeState, updateMap);
2082         }
2083
2084         public IAsyncResult BeginLoadRunnableInstance(AsyncCallback callback, object state)
2085         {
2086             return BeginLoadRunnableInstance(ActivityDefaults.LoadTimeout, callback, state);
2087         }
2088
2089         public IAsyncResult BeginLoadRunnableInstance(TimeSpan timeout, AsyncCallback callback, object state)
2090         {
2091             ThrowIfReadOnly(); // only allow a single Load() or Run()
2092
2093             TimeoutHelper.ThrowIfNegativeArgument(timeout);
2094
2095             if (this.InstanceStore == null)
2096             {
2097                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.LoadingWorkflowApplicationRequiresInstanceStore));
2098             }
2099             if (this.instanceIdSet)
2100             {
2101                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.WorkflowApplicationAlreadyHasId));
2102             }
2103             if (this.initialWorkflowArguments != null)
2104             {
2105                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CannotUseInputsWithLoad));
2106             }
2107             if (this.persistenceManager != null)
2108             {
2109                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.TryLoadRequiresOwner));
2110             }
2111
2112             PersistenceManager newManager = new PersistenceManager(InstanceStore, GetInstanceMetadata());
2113             if (!newManager.IsInitialized)
2114             {
2115                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.TryLoadRequiresOwner));
2116             }
2117
2118             return new LoadAsyncResult(this, newManager, true, timeout, callback, state);
2119         }
2120
2121         public IAsyncResult BeginLoad(Guid instanceId, AsyncCallback callback, object state)
2122         {
2123             return BeginLoad(instanceId, ActivityDefaults.LoadTimeout, callback, state);
2124         }
2125
2126         public IAsyncResult BeginLoad(Guid instanceId, TimeSpan timeout, AsyncCallback callback, object state)
2127         {
2128             ThrowIfAborted();
2129             ThrowIfReadOnly(); // only allow a single Load() or Run()
2130             if (instanceId == Guid.Empty)
2131             {
2132                 throw FxTrace.Exception.ArgumentNullOrEmpty("instanceId");
2133             }
2134
2135             TimeoutHelper.ThrowIfNegativeArgument(timeout);
2136
2137             if (this.InstanceStore == null)
2138             {
2139                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.LoadingWorkflowApplicationRequiresInstanceStore));
2140             }
2141             if (this.instanceIdSet)
2142             {
2143                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.WorkflowApplicationAlreadyHasId));
2144             }
2145             if (this.initialWorkflowArguments != null)
2146             {
2147                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CannotUseInputsWithLoad));
2148             }
2149
2150             PersistenceManager newManager = new PersistenceManager(this.InstanceStore, GetInstanceMetadata(), instanceId);
2151
2152             return new LoadAsyncResult(this, newManager, false, timeout, callback, state);
2153         }
2154
2155         public IAsyncResult BeginLoad(WorkflowApplicationInstance instance, AsyncCallback callback, object state)
2156         {
2157             return BeginLoad(instance, null, ActivityDefaults.LoadTimeout, callback, state);
2158         }
2159
2160         public IAsyncResult BeginLoad(WorkflowApplicationInstance instance, TimeSpan timeout,
2161             AsyncCallback callback, object state)
2162         {
2163             return BeginLoad(instance, null, timeout, callback, state);
2164         }
2165
2166         public IAsyncResult BeginLoad(WorkflowApplicationInstance instance, DynamicUpdateMap updateMap,
2167             AsyncCallback callback, object state)
2168         {
2169             return BeginLoad(instance, updateMap, ActivityDefaults.LoadTimeout, callback, state);
2170         }
2171
2172         public IAsyncResult BeginLoad(WorkflowApplicationInstance instance, DynamicUpdateMap updateMap, TimeSpan timeout,
2173             AsyncCallback callback, object state)
2174         {
2175             ThrowIfAborted();
2176             ThrowIfReadOnly(); // only allow a single Load() or Run()
2177             if (instance == null)
2178             {
2179                 throw FxTrace.Exception.ArgumentNull("instance");
2180             }
2181
2182             TimeoutHelper.ThrowIfNegativeArgument(timeout);
2183
2184             if (this.instanceIdSet)
2185             {
2186                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.WorkflowApplicationAlreadyHasId));
2187             }
2188             if (this.initialWorkflowArguments != null)
2189             {
2190                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CannotUseInputsWithLoad));
2191             }
2192             if (this.InstanceStore != null && this.InstanceStore != instance.InstanceStore)
2193             {
2194                 throw FxTrace.Exception.Argument("instance", SR.InstanceStoreDoesntMatchWorkflowApplication);
2195             }
2196
2197             instance.MarkAsLoaded();
2198             PersistenceManager newManager = (PersistenceManager)instance.PersistenceManager;
2199             newManager.SetInstanceMetadata(GetInstanceMetadata());
2200
2201             return new LoadAsyncResult(this, newManager, instance.Values, updateMap, timeout, callback, state);
2202         }
2203
2204         public void EndLoad(IAsyncResult result)
2205         {
2206             LoadAsyncResult.End(result);
2207         }
2208
2209         public void EndLoadRunnableInstance(IAsyncResult result)
2210         {
2211             LoadAsyncResult.End(result);
2212         }
2213
2214         protected override void OnNotifyUnhandledException(Exception exception, Activity exceptionSource, string exceptionSourceInstanceId)
2215         {
2216             bool done = true;
2217
2218             try
2219             {
2220                 Exception abortException = null;
2221
2222                 try
2223                 {
2224                     if (unhandledExceptionHandler == null)
2225                     {
2226                         unhandledExceptionHandler = new UnhandledExceptionEventHandler();
2227                     }
2228
2229                     done = unhandledExceptionHandler.Run(this, exception, exceptionSource, exceptionSourceInstanceId);
2230                 }
2231                 catch (Exception e)
2232                 {
2233                     if (Fx.IsFatal(e))
2234                     {
2235                         throw;
2236                     }
2237
2238                     abortException = e;
2239                 }
2240
2241                 if (abortException != null)
2242                 {
2243                     AbortInstance(abortException, true);
2244                 }
2245             }
2246             finally
2247             {
2248                 if (done)
2249                 {
2250                     OnNotifyPaused();
2251                 }
2252             }
2253         }
2254
2255         IAsyncResult BeginInternalPersist(PersistenceOperation operation, TimeSpan timeout, bool isInternalPersist, AsyncCallback callback, object state)
2256         {
2257             return new UnloadOrPersistAsyncResult(this, timeout, operation, true, isInternalPersist, callback, state);
2258         }
2259
2260         void EndInternalPersist(IAsyncResult result)
2261         {
2262             UnloadOrPersistAsyncResult.End(result);
2263         }
2264
2265         void TrackPersistence(PersistenceOperation operation)
2266         {
2267             if (this.Controller.TrackingEnabled)
2268             {
2269                 if (operation == PersistenceOperation.Complete)
2270                 {
2271                     this.Controller.Track(new WorkflowInstanceRecord(this.Id, this.WorkflowDefinition.DisplayName, WorkflowInstanceStates.Deleted, this.DefinitionIdentity));
2272                 }
2273                 else if (operation == PersistenceOperation.Unload)
2274                 {
2275                     this.Controller.Track(new WorkflowInstanceRecord(this.Id, this.WorkflowDefinition.DisplayName, WorkflowInstanceStates.Unloaded, this.DefinitionIdentity));
2276                 }
2277                 else
2278                 {
2279                     this.Controller.Track(new WorkflowInstanceRecord(this.Id, this.WorkflowDefinition.DisplayName, WorkflowInstanceStates.Persisted, this.DefinitionIdentity));
2280                 }
2281             }
2282         }
2283
2284         void PersistCore(ref TimeoutHelper timeoutHelper, PersistenceOperation operation)
2285         {
2286             if (HasPersistenceProvider)
2287             {
2288                 if (!this.persistenceManager.IsInitialized)
2289                 {
2290                     this.persistenceManager.Initialize(this.DefinitionIdentity, timeoutHelper.RemainingTime());
2291                 }
2292                 if (!this.persistenceManager.IsLocked && Transaction.Current != null)
2293                 {
2294                     this.persistenceManager.EnsureReadyness(timeoutHelper.RemainingTime());
2295                 }
2296
2297                 // Do the tracking before preparing in case the tracking data is being pushed into
2298                 // an extension and persisted transactionally with the instance state.
2299                 TrackPersistence(operation);
2300
2301                 this.Controller.FlushTrackingRecords(timeoutHelper.RemainingTime());
2302             }
2303
2304             bool success = false;
2305             WorkflowPersistenceContext context = null;
2306             TransactionScope scope = null;
2307
2308             try
2309             {
2310                 IDictionary<XName, InstanceValue> data = null;
2311                 PersistencePipeline pipeline = null;
2312                 if (HasPersistenceModule)
2313                 {
2314                     IEnumerable<IPersistencePipelineModule> modules = base.GetExtensions<IPersistencePipelineModule>();
2315                     pipeline = new PersistencePipeline(modules, PersistenceManager.GenerateInitialData(this));
2316                     pipeline.Collect();
2317                     pipeline.Map();
2318                     data = pipeline.Values;
2319                 }
2320
2321                 if (HasPersistenceProvider)
2322                 {
2323                     if (data == null)
2324                     {
2325                         data = PersistenceManager.GenerateInitialData(this);
2326                     }
2327
2328                     if (context == null)
2329                     {
2330                         Fx.Assert(scope == null, "Should not have been able to set up a scope.");
2331                         InitializePersistenceContext(pipeline != null && pipeline.IsSaveTransactionRequired, timeoutHelper, out context, out scope);
2332                     }
2333
2334                     this.persistenceManager.Save(data, operation, timeoutHelper.RemainingTime());
2335                 }
2336
2337                 if (pipeline != null)
2338                 {
2339                     if (context == null)
2340                     {
2341                         Fx.Assert(scope == null, "Should not have been able to set up a scope if we had no context.");
2342                         InitializePersistenceContext(pipeline.IsSaveTransactionRequired, timeoutHelper, out context, out scope);
2343                     }
2344
2345                     try
2346                     {
2347                         this.persistencePipelineInUse = pipeline;
2348
2349                         // Need to ensure that either we see the Aborted state, AbortInstance sees us, or both.
2350                         Thread.MemoryBarrier();
2351
2352                         if (this.state == WorkflowApplicationState.Aborted)
2353                         {
2354                             throw FxTrace.Exception.AsError(new OperationCanceledException(SR.DefaultAbortReason));
2355                         }
2356
2357                         pipeline.EndSave(pipeline.BeginSave(timeoutHelper.RemainingTime(), null, null));
2358                     }
2359                     finally
2360                     {
2361                         this.persistencePipelineInUse = null;
2362                     }
2363                 }
2364
2365                 success = true;
2366             }
2367             finally
2368             {
2369                 CompletePersistenceContext(context, scope, success);
2370
2371                 if (success)
2372                 {
2373                     if (operation != PersistenceOperation.Save)
2374                     {
2375                         // Stop execution if we've given up the instance lock
2376                         this.state = WorkflowApplicationState.Paused;
2377
2378                         if (TD.WorkflowApplicationUnloadedIsEnabled())
2379                         {
2380                             TD.WorkflowApplicationUnloaded(this.Id.ToString());
2381                         }
2382                     }
2383                     else
2384                     {
2385                         if (TD.WorkflowApplicationPersistedIsEnabled())
2386                         {
2387                             TD.WorkflowApplicationPersisted(this.Id.ToString());
2388                         }
2389                     }
2390
2391                     if (operation == PersistenceOperation.Complete || operation == PersistenceOperation.Unload)
2392                     {
2393                         // We did a Delete or Unload, so if we have a persistence provider, tell it to delete the owner.
2394                         if (HasPersistenceProvider && this.persistenceManager.OwnerWasCreated)
2395                         {
2396                             // This will happen to be under the caller's transaction, if there is one.
2397                             // 
2398                             this.persistenceManager.DeleteOwner(timeoutHelper.RemainingTime());
2399                         }
2400
2401                         MarkUnloaded();
2402                     }
2403                 }
2404             }
2405         }
2406
2407         [Fx.Tag.InheritThrows(From = "Unload")]
2408         public void Persist()
2409         {
2410             Persist(ActivityDefaults.SaveTimeout);
2411         }
2412
2413         [Fx.Tag.InheritThrows(From = "Unload")]
2414         public void Persist(TimeSpan timeout)
2415         {
2416             ThrowIfHandlerThread();
2417
2418             TimeoutHelper.ThrowIfNegativeArgument(timeout);
2419
2420             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
2421
2422             RequiresPersistenceOperation operation = new RequiresPersistenceOperation();
2423
2424             try
2425             {
2426                 WaitForTurn(operation, timeoutHelper.RemainingTime());
2427
2428                 ValidateStateForPersist();
2429
2430                 PersistCore(ref timeoutHelper, PersistenceOperation.Save);
2431             }
2432             finally
2433             {
2434                 NotifyOperationComplete(operation);
2435             }
2436         }
2437
2438         [Fx.Tag.InheritThrows(From = "Unload")]
2439         public IAsyncResult BeginPersist(AsyncCallback callback, object state)
2440         {
2441             return BeginPersist(ActivityDefaults.SaveTimeout, callback, state);
2442         }
2443
2444         [Fx.Tag.InheritThrows(From = "Unload")]
2445         public IAsyncResult BeginPersist(TimeSpan timeout, AsyncCallback callback, object state)
2446         {
2447             ThrowIfHandlerThread();
2448
2449             TimeoutHelper.ThrowIfNegativeArgument(timeout);
2450
2451             return new UnloadOrPersistAsyncResult(this, timeout, PersistenceOperation.Save, false, false, callback, state);
2452         }
2453
2454         [Fx.Tag.InheritThrows(From = "Unload")]
2455         public void EndPersist(IAsyncResult result)
2456         {
2457             UnloadOrPersistAsyncResult.End(result);
2458         }
2459
2460         // called from WorkflowApplicationIdleEventArgs
2461         internal ReadOnlyCollection<BookmarkInfo> GetBookmarksForIdle()
2462         {
2463             return this.Controller.GetBookmarks();
2464         }
2465
2466         public ReadOnlyCollection<BookmarkInfo> GetBookmarks()
2467         {
2468             return GetBookmarks(ActivityDefaults.ResumeBookmarkTimeout);
2469         }
2470
2471         public ReadOnlyCollection<BookmarkInfo> GetBookmarks(TimeSpan timeout)
2472         {
2473             ThrowIfHandlerThread();
2474
2475             TimeoutHelper.ThrowIfNegativeArgument(timeout);
2476
2477             InstanceOperation operation = new InstanceOperation();
2478
2479             try
2480             {
2481                 WaitForTurn(operation, timeout);
2482
2483                 ValidateStateForGetAllBookmarks();
2484
2485                 return this.Controller.GetBookmarks();
2486             }
2487             finally
2488             {
2489                 NotifyOperationComplete(operation);
2490             }
2491         }
2492
2493         protected internal override IAsyncResult OnBeginPersist(AsyncCallback callback, object state)
2494         {
2495             return this.BeginInternalPersist(PersistenceOperation.Save, ActivityDefaults.InternalSaveTimeout, true, callback, state);
2496         }
2497
2498         protected internal override void OnEndPersist(IAsyncResult result)
2499         {
2500             this.EndInternalPersist(result);
2501         }
2502
2503         protected internal override IAsyncResult OnBeginAssociateKeys(ICollection<InstanceKey> keys, AsyncCallback callback, object state)
2504         {
2505             throw Fx.AssertAndThrow("WorkflowApplication is sealed with CanUseKeys as false, so WorkflowInstance should not call OnBeginAssociateKeys.");
2506         }
2507
2508         protected internal override void OnEndAssociateKeys(IAsyncResult result)
2509         {
2510             throw Fx.AssertAndThrow("WorkflowApplication is sealed with CanUseKeys as false, so WorkflowInstance should not call OnEndAssociateKeys.");
2511         }
2512
2513         protected internal override void OnDisassociateKeys(ICollection<InstanceKey> keys)
2514         {
2515             throw Fx.AssertAndThrow("WorkflowApplication is sealed with CanUseKeys as false, so WorkflowInstance should not call OnDisassociateKeys.");
2516         }
2517
2518         bool AreBookmarksInvalid(out BookmarkResumptionResult result)
2519         {
2520             if (this.hasRaisedCompleted)
2521             {
2522                 result = BookmarkResumptionResult.NotFound;
2523                 return true;
2524             }
2525             else if (this.state == WorkflowApplicationState.Unloaded || this.state == WorkflowApplicationState.Aborted)
2526             {
2527                 result = BookmarkResumptionResult.NotReady;
2528                 return true;
2529             }
2530
2531             result = BookmarkResumptionResult.Success;
2532             return false;
2533         }
2534
2535         [Fx.Tag.InheritThrows(From = "ResumeBookmark")]
2536         public BookmarkResumptionResult ResumeBookmark(string bookmarkName, object value)
2537         {
2538             if (string.IsNullOrEmpty(bookmarkName))
2539             {
2540                 throw FxTrace.Exception.ArgumentNullOrEmpty("bookmarkName");
2541             }
2542
2543             return ResumeBookmark(new Bookmark(bookmarkName), value);
2544         }
2545
2546         [Fx.Tag.InheritThrows(From = "ResumeBookmark")]
2547         public BookmarkResumptionResult ResumeBookmark(Bookmark bookmark, object value)
2548         {
2549             return ResumeBookmark(bookmark, value, ActivityDefaults.ResumeBookmarkTimeout);
2550         }
2551
2552         [Fx.Tag.InheritThrows(From = "ResumeBookmark")]
2553         public BookmarkResumptionResult ResumeBookmark(string bookmarkName, object value, TimeSpan timeout)
2554         {
2555             if (string.IsNullOrEmpty(bookmarkName))
2556             {
2557                 throw FxTrace.Exception.ArgumentNullOrEmpty("bookmarkName");
2558             }
2559
2560             return ResumeBookmark(new Bookmark(bookmarkName), value, timeout);
2561         }
2562
2563         [Fx.Tag.InheritThrows(From = "BeginResumeBookmark", FromDeclaringType = typeof(WorkflowInstance))]
2564         public BookmarkResumptionResult ResumeBookmark(Bookmark bookmark, object value, TimeSpan timeout)
2565         {
2566             TimeoutHelper.ThrowIfNegativeArgument(timeout);
2567             ThrowIfHandlerThread();
2568             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
2569
2570             InstanceOperation operation = new RequiresIdleOperation();
2571             BookmarkResumptionResult result;
2572             bool pendedUnenqueued = false;
2573
2574             try
2575             {
2576                 // This is a loose check, but worst case scenario we call
2577                 // an extra, unnecessary Run
2578                 if (!this.hasCalledRun)
2579                 {
2580                     // Increment the pending unenqueued count so we don't raise idle in the time between
2581                     // when the Run completes and when we enqueue our InstanceOperation.
2582                     pendedUnenqueued = true;
2583                     IncrementPendingUnenqueud();
2584
2585                     InternalRun(timeoutHelper.RemainingTime(), false);
2586                 }
2587
2588                 do
2589                 {
2590                     InstanceOperation nextOperation = null;
2591
2592                     try
2593                     {
2594                         // Need to enqueue and wait for turn as two separate steps, so that
2595                         // OnQueued always gets called and we make sure to decrement the pendingUnenqueued counter
2596                         WaitForTurn(operation, timeoutHelper.RemainingTime());
2597
2598                         if (pendedUnenqueued)
2599                         {
2600                             DecrementPendingUnenqueud();
2601                             pendedUnenqueued = false;
2602                         }
2603
2604                         if (AreBookmarksInvalid(out result))
2605                         {
2606                             return result;
2607                         }
2608
2609                         result = ResumeBookmarkCore(bookmark, value);
2610
2611                         if (result == BookmarkResumptionResult.Success)
2612                         {
2613                             this.Controller.FlushTrackingRecords(timeoutHelper.RemainingTime());
2614                         }
2615                         else if (result == BookmarkResumptionResult.NotReady)
2616                         {
2617                             nextOperation = new DeferredRequiresIdleOperation();
2618                         }
2619                     }
2620                     finally
2621                     {
2622                         NotifyOperationComplete(operation);
2623                     }
2624
2625                     operation = nextOperation;
2626                 } while (operation != null);
2627
2628                 return result;
2629             }
2630             finally
2631             {
2632                 if (pendedUnenqueued)
2633                 {
2634                     DecrementPendingUnenqueud();
2635                 }
2636             }
2637         }
2638
2639         [Fx.Tag.InheritThrows(From = "ResumeBookmark")]
2640         public IAsyncResult BeginResumeBookmark(string bookmarkName, object value, AsyncCallback callback, object state)
2641         {
2642             if (string.IsNullOrEmpty(bookmarkName))
2643             {
2644                 throw FxTrace.Exception.ArgumentNullOrEmpty("bookmarkName");
2645             }
2646
2647             return BeginResumeBookmark(new Bookmark(bookmarkName), value, callback, state);
2648         }
2649
2650         [Fx.Tag.InheritThrows(From = "ResumeBookmark")]
2651         public IAsyncResult BeginResumeBookmark(string bookmarkName, object value, TimeSpan timeout, AsyncCallback callback, object state)
2652         {
2653             if (string.IsNullOrEmpty(bookmarkName))
2654             {
2655                 throw FxTrace.Exception.ArgumentNullOrEmpty("bookmarkName");
2656             }
2657
2658             return BeginResumeBookmark(new Bookmark(bookmarkName), value, timeout, callback, state);
2659         }
2660
2661         [Fx.Tag.InheritThrows(From = "ResumeBookmark")]
2662         public IAsyncResult BeginResumeBookmark(Bookmark bookmark, object value, AsyncCallback callback, object state)
2663         {
2664             return BeginResumeBookmark(bookmark, value, ActivityDefaults.ResumeBookmarkTimeout, callback, state);
2665         }
2666
2667         [Fx.Tag.InheritThrows(From = "ResumeBookmark")]
2668         public IAsyncResult BeginResumeBookmark(Bookmark bookmark, object value, TimeSpan timeout, AsyncCallback callback, object state)
2669         {
2670             TimeoutHelper.ThrowIfNegativeArgument(timeout);
2671             ThrowIfHandlerThread();
2672
2673             return new ResumeBookmarkAsyncResult(this, bookmark, value, timeout, callback, state);
2674         }
2675
2676         [Fx.Tag.InheritThrows(From = "ResumeBookmark")]
2677         public BookmarkResumptionResult EndResumeBookmark(IAsyncResult result)
2678         {
2679             return ResumeBookmarkAsyncResult.End(result);
2680         }
2681
2682         protected internal override IAsyncResult OnBeginResumeBookmark(Bookmark bookmark, object value, TimeSpan timeout, AsyncCallback callback, object state)
2683         {
2684             ThrowIfHandlerThread();
2685             return new ResumeBookmarkAsyncResult(this, bookmark, value, true, timeout, callback, state);
2686         }
2687
2688         protected internal override BookmarkResumptionResult OnEndResumeBookmark(IAsyncResult result)
2689         {
2690             return ResumeBookmarkAsyncResult.End(result);
2691         }
2692
2693         BookmarkResumptionResult ResumeBookmarkCore(Bookmark bookmark, object value)
2694         {
2695             BookmarkResumptionResult result = this.Controller.ScheduleBookmarkResumption(bookmark, value);
2696
2697             if (result == BookmarkResumptionResult.Success)
2698             {
2699                 RunCore();
2700             }
2701
2702             return result;
2703         }
2704
2705         // Returns true if successful, false otherwise
2706         bool RaiseIdleEvent()
2707         {
2708             if (TD.WorkflowApplicationIdledIsEnabled())
2709             {
2710                 TD.WorkflowApplicationIdled(this.Id.ToString());
2711             }
2712
2713             Exception abortException = null;
2714
2715             try
2716             {
2717                 Action<WorkflowApplicationIdleEventArgs> idleHandler = this.Idle;
2718
2719                 if (idleHandler != null)
2720                 {
2721                     this.handlerThreadId = Thread.CurrentThread.ManagedThreadId;
2722                     this.isInHandler = true;
2723
2724                     idleHandler(new WorkflowApplicationIdleEventArgs(this));
2725                 }
2726             }
2727             catch (Exception e)
2728             {
2729                 if (Fx.IsFatal(e))
2730                 {
2731                     throw;
2732                 }
2733
2734                 abortException = e;
2735             }
2736             finally
2737             {
2738                 this.isInHandler = false;
2739             }
2740
2741             if (abortException != null)
2742             {
2743                 AbortInstance(abortException, true);
2744                 return false;
2745             }
2746
2747             return true;
2748         }
2749
2750         void MarkUnloaded()
2751         {
2752             this.state = WorkflowApplicationState.Unloaded;
2753
2754             // don't abort completed instances
2755             if (this.Controller.State != WorkflowInstanceState.Complete)
2756             {
2757                 this.Controller.Abort();
2758             }
2759             else
2760             {
2761                 base.DisposeExtensions();
2762             }
2763
2764             Exception abortException = null;
2765
2766             try
2767             {
2768                 Action<WorkflowApplicationEventArgs> handler = this.Unloaded;
2769
2770                 if (handler != null)
2771                 {
2772                     this.handlerThreadId = Thread.CurrentThread.ManagedThreadId;
2773                     this.isInHandler = true;
2774
2775                     handler(new WorkflowApplicationEventArgs(this));
2776                 }
2777             }
2778             catch (Exception e)
2779             {
2780                 if (Fx.IsFatal(e))
2781                 {
2782                     throw;
2783                 }
2784
2785                 abortException = e;
2786             }
2787             finally
2788             {
2789                 this.isInHandler = false;
2790             }
2791
2792             if (abortException != null)
2793             {
2794                 AbortInstance(abortException, true);
2795             }
2796         }
2797
2798         [Fx.Tag.Throws(typeof(WorkflowApplicationException), "The WorkflowApplication is in a state for which unloading is not valid.  The specific subclass denotes which state the instance is in.")]
2799         [Fx.Tag.Throws(typeof(InstancePersistenceException), "Something went wrong during persistence, but persistence can be retried.")]
2800         [Fx.Tag.Throws(typeof(TimeoutException), "The workflow could not be unloaded within the given timeout.")]
2801         public void Unload()
2802         {
2803             Unload(ActivityDefaults.SaveTimeout);
2804         }
2805
2806         [Fx.Tag.InheritThrows(From = "Unload")]
2807         public void Unload(TimeSpan timeout)
2808         {
2809             ThrowIfHandlerThread();
2810
2811             TimeoutHelper.ThrowIfNegativeArgument(timeout);
2812
2813             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
2814
2815             RequiresPersistenceOperation operation = new RequiresPersistenceOperation();
2816
2817             try
2818             {
2819                 WaitForTurn(operation, timeoutHelper.RemainingTime());
2820
2821                 ValidateStateForUnload();
2822                 if (this.state != WorkflowApplicationState.Unloaded) // Unload on unload is a no-op
2823                 {
2824                     PersistenceOperation persistenceOperation;
2825
2826                     if (this.Controller.State == WorkflowInstanceState.Complete)
2827                     {
2828                         persistenceOperation = PersistenceOperation.Complete;
2829                     }
2830                     else
2831                     {
2832                         persistenceOperation = PersistenceOperation.Unload;
2833                     }
2834
2835                     PersistCore(ref timeoutHelper, persistenceOperation);
2836                 }
2837             }
2838             finally
2839             {
2840                 NotifyOperationComplete(operation);
2841             }
2842         }
2843
2844         [Fx.Tag.InheritThrows(From = "Unload")]
2845         public IAsyncResult BeginUnload(AsyncCallback callback, object state)
2846         {
2847             return BeginUnload(ActivityDefaults.SaveTimeout, callback, state);
2848         }
2849
2850         [Fx.Tag.InheritThrows(From = "Unload")]
2851         public IAsyncResult BeginUnload(TimeSpan timeout, AsyncCallback callback, object state)
2852         {
2853             ThrowIfHandlerThread();
2854
2855             TimeoutHelper.ThrowIfNegativeArgument(timeout);
2856
2857             return new UnloadOrPersistAsyncResult(this, timeout, PersistenceOperation.Unload, false, false, callback, state);
2858         }
2859
2860         [Fx.Tag.InheritThrows(From = "Unload")]
2861         public void EndUnload(IAsyncResult result)
2862         {
2863             UnloadOrPersistAsyncResult.End(result);
2864         }
2865
2866         IDictionary<XName, InstanceValue> GetInstanceMetadata()
2867         {
2868             if (this.DefinitionIdentity != null)
2869             {
2870                 if (this.instanceMetadata == null)
2871                 {
2872                     this.instanceMetadata = new Dictionary<XName, InstanceValue>(2);
2873                 }
2874                 if (!this.instanceMetadata.ContainsKey(WorkflowNamespace.WorkflowHostType))
2875                 {
2876                     this.instanceMetadata.Add(WorkflowNamespace.WorkflowHostType, new InstanceValue(Workflow45Namespace.WorkflowApplication));
2877                 }
2878                 this.instanceMetadata[Workflow45Namespace.DefinitionIdentity] =
2879                     new InstanceValue(this.DefinitionIdentity, InstanceValueOptions.Optional);
2880             }
2881             return this.instanceMetadata;
2882         }
2883
2884         void UpdateInstanceMetadata()
2885         {
2886             // Update the metadata to reflect the new identity after a Dynamic Update
2887             this.persistenceManager.SetMutablemetadata(new Dictionary<XName, InstanceValue>
2888             {
2889                 { Workflow45Namespace.DefinitionIdentity, new InstanceValue(this.DefinitionIdentity, InstanceValueOptions.Optional) }
2890             });
2891         }
2892
2893         void ThrowIfMulticast(Delegate value)
2894         {
2895             if (value != null && value.GetInvocationList().Length > 1)
2896             {
2897                 throw FxTrace.Exception.Argument("value", SR.OnlySingleCastDelegatesAllowed);
2898             }
2899         }
2900
2901         void ThrowIfAborted()
2902         {
2903             if (this.state == WorkflowApplicationState.Aborted)
2904             {
2905                 throw FxTrace.Exception.AsError(new WorkflowApplicationAbortedException(SR.WorkflowApplicationAborted(this.Id), this.Id));
2906             }
2907         }
2908
2909         void ThrowIfTerminatedOrCompleted()
2910         {
2911             if (this.hasRaisedCompleted)
2912             {
2913                 Exception completionException;
2914                 this.Controller.GetCompletionState(out completionException);
2915                 if (completionException != null)
2916                 {
2917                     throw FxTrace.Exception.AsError(new WorkflowApplicationTerminatedException(SR.WorkflowApplicationTerminated(this.Id), this.Id, completionException));
2918                 }
2919                 else
2920                 {
2921                     throw FxTrace.Exception.AsError(new WorkflowApplicationCompletedException(SR.WorkflowApplicationCompleted(this.Id), this.Id));
2922                 }
2923             }
2924         }
2925
2926         void ThrowIfUnloaded()
2927         {
2928             if (this.state == WorkflowApplicationState.Unloaded)
2929             {
2930                 throw FxTrace.Exception.AsError(new WorkflowApplicationUnloadedException(SR.WorkflowApplicationUnloaded(this.Id), this.Id));
2931             }
2932         }
2933
2934         void ThrowIfNoInstanceStore()
2935         {
2936             if (!HasPersistenceProvider)
2937             {
2938                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InstanceStoreRequiredToPersist));
2939             }
2940         }
2941
2942         void ThrowIfHandlerThread()
2943         {
2944             if (this.IsHandlerThread)
2945             {
2946                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.CannotPerformOperationFromHandlerThread));
2947             }
2948         }
2949
2950         void ValidateStateForRun()
2951         {
2952             // WorkflowInstanceException validations
2953             ThrowIfAborted();
2954             ThrowIfTerminatedOrCompleted();
2955             ThrowIfUnloaded();
2956         }
2957
2958         void ValidateStateForGetAllBookmarks()
2959         {
2960             // WorkflowInstanceException validations
2961             ThrowIfAborted();
2962             ThrowIfTerminatedOrCompleted();
2963             ThrowIfUnloaded();
2964         }
2965
2966         void ValidateStateForCancel()
2967         {
2968             // WorkflowInstanceException validations
2969             ThrowIfAborted();
2970
2971             // We only validate that we aren't aborted and no-op otherwise.
2972             // This is because the scenario for calling cancel is for it to
2973             // be a best attempt from an unknown thread.  The less it throws
2974             // the easier it is to author a host.
2975         }
2976
2977         void ValidateStateForLoad()
2978         {
2979             ThrowIfAborted();
2980             ThrowIfReadOnly(); // only allow a single Load() or Run()
2981             if (this.instanceIdSet)
2982             {
2983                 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.WorkflowApplicationAlreadyHasId));
2984             }
2985         }
2986
2987         void ValidateStateForPersist()
2988         {
2989             // WorkflowInstanceException validations
2990             ThrowIfAborted();
2991             ThrowIfTerminatedOrCompleted();
2992             ThrowIfUnloaded();
2993
2994             // Other validations
2995             ThrowIfNoInstanceStore();
2996         }
2997
2998         void ValidateStateForUnload()
2999         {
3000             // WorkflowInstanceException validations
3001             ThrowIfAborted();
3002
3003             // Other validations
3004             if (this.Controller.State != WorkflowInstanceState.Complete)
3005             {
3006                 ThrowIfNoInstanceStore();
3007             }
3008         }
3009
3010         void ValidateStateForTerminate()
3011         {
3012             // WorkflowInstanceException validations
3013             ThrowIfAborted();
3014             ThrowIfTerminatedOrCompleted();
3015             ThrowIfUnloaded();
3016         }
3017
3018         enum PersistenceOperation : byte
3019         {
3020             Complete,
3021             Save,
3022             Unload
3023         }
3024
3025         enum WorkflowApplicationState : byte
3026         {
3027             Paused,
3028             Runnable,
3029             Unloaded,
3030             Aborted
3031         }
3032
3033         internal class SynchronousSynchronizationContext : SynchronizationContext
3034         {
3035             static SynchronousSynchronizationContext value;
3036
3037             SynchronousSynchronizationContext()
3038             {
3039             }
3040
3041             public static SynchronousSynchronizationContext Value
3042             {
3043                 get
3044                 {
3045                     if (value == null)
3046                     {
3047                         value = new SynchronousSynchronizationContext();
3048                     }
3049                     return value;
3050                 }
3051             }
3052
3053             public override void Post(SendOrPostCallback d, object state)
3054             {
3055                 d(state);
3056             }
3057
3058             public override void Send(SendOrPostCallback d, object state)
3059             {
3060                 d(state);
3061             }
3062         }
3063
3064         class InvokeAsyncResult : AsyncResult
3065         {
3066             static Action<object, TimeoutException> waitCompleteCallback;
3067             WorkflowApplication instance;
3068             AsyncWaitHandle completionWaiter;
3069             IDictionary<string, object> outputs;
3070             Exception completionException;
3071
3072             public InvokeAsyncResult(Activity activity, IDictionary<string, object> inputs, WorkflowInstanceExtensionManager extensions, TimeSpan timeout, SynchronizationContext syncContext, AsyncInvokeContext invokeContext, AsyncCallback callback, object state)
3073                 : base(callback, state)
3074             {
3075                 Fx.Assert(activity != null, "Need an activity");
3076
3077                 this.completionWaiter = new AsyncWaitHandle();
3078                 syncContext = syncContext ?? SynchronousSynchronizationContext.Value;
3079
3080                 this.instance = WorkflowApplication.StartInvoke(activity, inputs, extensions, syncContext, new Action(this.OnInvokeComplete), invokeContext);
3081
3082                 if (this.completionWaiter.WaitAsync(WaitCompleteCallback, this, timeout))
3083                 {
3084                     bool completeSelf = OnWorkflowCompletion();
3085
3086                     if (completeSelf)
3087                     {
3088                         if (this.completionException != null)
3089                         {
3090                             throw FxTrace.Exception.AsError(this.completionException);
3091                         }
3092                         else
3093                         {
3094                             Complete(true);
3095                         }
3096                     }
3097                 }
3098             }
3099
3100             static Action<object, TimeoutException> WaitCompleteCallback
3101             {
3102                 get
3103                 {
3104                     if (waitCompleteCallback == null)
3105                     {
3106                         waitCompleteCallback = new Action<object, TimeoutException>(OnWaitComplete);
3107                     }
3108
3109                     return waitCompleteCallback;
3110                 }
3111             }
3112
3113             public static IDictionary<string, object> End(IAsyncResult result)
3114             {
3115                 InvokeAsyncResult thisPtr = AsyncResult.End<InvokeAsyncResult>(result);
3116                 return thisPtr.outputs;
3117             }
3118
3119             void OnInvokeComplete()
3120             {
3121                 this.completionWaiter.Set();
3122             }
3123
3124             static void OnWaitComplete(object state, TimeoutException asyncException)
3125             {
3126                 InvokeAsyncResult thisPtr = (InvokeAsyncResult)state;
3127
3128                 if (asyncException != null)
3129                 {
3130                     thisPtr.instance.Abort(SR.AbortingDueToInstanceTimeout);
3131                     thisPtr.Complete(false, asyncException);
3132                     return;
3133                 }
3134
3135                 bool completeSelf = true;
3136
3137                 try
3138                 {
3139                     completeSelf = thisPtr.OnWorkflowCompletion();
3140                 }
3141                 catch (Exception e)
3142                 {
3143                     if (Fx.IsFatal(e))
3144                     {
3145                         throw;
3146                     }
3147
3148                     thisPtr.completionException = e;
3149                 }
3150
3151                 if (completeSelf)
3152                 {
3153                     thisPtr.Complete(false, thisPtr.completionException);
3154                 }
3155             }
3156
3157             bool OnWorkflowCompletion()
3158             {
3159                 if (this.instance.Controller.State == WorkflowInstanceState.Aborted)
3160                 {
3161                     this.completionException = new WorkflowApplicationAbortedException(SR.DefaultAbortReason, this.instance.Controller.GetAbortReason());
3162                 }
3163                 else
3164                 {
3165                     Fx.Assert(this.instance.Controller.State == WorkflowInstanceState.Complete, "We should only get here when we are completed.");
3166
3167                     this.instance.Controller.GetCompletionState(out this.outputs, out this.completionException);
3168                 }
3169
3170                 return true;
3171             }
3172
3173         }
3174
3175         class ResumeBookmarkAsyncResult : AsyncResult
3176         {
3177             static AsyncCompletion resumedCallback = new AsyncCompletion(OnResumed);
3178             static Action<object, TimeoutException> waitCompleteCallback = new Action<object, TimeoutException>(OnWaitComplete);
3179             static AsyncCompletion trackingCompleteCallback = new AsyncCompletion(OnTrackingComplete);
3180
3181             WorkflowApplication instance;
3182             Bookmark bookmark;
3183             object value;
3184             BookmarkResumptionResult resumptionResult;
3185             TimeoutHelper timeoutHelper;
3186             bool isFromExtension;
3187             bool pendedUnenqueued;
3188
3189             InstanceOperation currentOperation;
3190
3191             public ResumeBookmarkAsyncResult(WorkflowApplication instance, Bookmark bookmark, object value, TimeSpan timeout, AsyncCallback callback, object state)
3192                 : this(instance, bookmark, value, false, timeout, callback, state)
3193             {
3194             }
3195
3196             public ResumeBookmarkAsyncResult(WorkflowApplication instance, Bookmark bookmark, object value, bool isFromExtension, TimeSpan timeout, AsyncCallback callback, object state)
3197                 : base(callback, state)
3198             {
3199                 this.instance = instance;
3200                 this.bookmark = bookmark;
3201                 this.value = value;
3202                 this.isFromExtension = isFromExtension;
3203                 this.timeoutHelper = new TimeoutHelper(timeout);
3204
3205                 bool completeSelf = false;
3206                 bool success = false;
3207
3208                 this.OnCompleting = new Action<AsyncResult, Exception>(Finally);
3209
3210                 try
3211                 {
3212                     if (!this.instance.hasCalledRun && !this.isFromExtension)
3213                     {
3214                         // Increment the pending unenqueued count so we don't raise idle in the time between
3215                         // when the Run completes and when we enqueue our InstanceOperation.
3216                         this.pendedUnenqueued = true;
3217                         this.instance.IncrementPendingUnenqueud();
3218
3219                         IAsyncResult result = this.instance.BeginInternalRun(this.timeoutHelper.RemainingTime(), false, PrepareAsyncCompletion(resumedCallback), this);
3220                         if (result.CompletedSynchronously)
3221                         {
3222                             completeSelf = OnResumed(result);
3223                         }
3224                     }
3225                     else
3226                     {
3227                         completeSelf = StartResumptionLoop();
3228                     }
3229
3230                     success = true;
3231                 }
3232                 finally
3233                 {
3234                     // We only want to call this if we are throwing.  Otherwise OnCompleting will take care of it.
3235                     if (!success)
3236                     {
3237                         Finally(null, null);
3238                     }
3239                 }
3240
3241                 if (completeSelf)
3242                 {
3243                     Complete(true);
3244                 }
3245             }
3246
3247             public static BookmarkResumptionResult End(IAsyncResult result)
3248             {
3249                 ResumeBookmarkAsyncResult thisPtr = AsyncResult.End<ResumeBookmarkAsyncResult>(result);
3250
3251                 return thisPtr.resumptionResult;
3252             }
3253
3254             void ClearPendedUnenqueued()
3255             {
3256                 if (this.pendedUnenqueued)
3257                 {
3258                     this.pendedUnenqueued = false;
3259                     this.instance.DecrementPendingUnenqueud();
3260                 }
3261             }
3262
3263             void NotifyOperationComplete()
3264             {
3265                 InstanceOperation lastOperation = this.currentOperation;
3266                 this.currentOperation = null;
3267                 this.instance.NotifyOperationComplete(lastOperation);
3268             }
3269
3270             void Finally(AsyncResult result, Exception completionException)
3271             {
3272                 ClearPendedUnenqueued();
3273                 NotifyOperationComplete();
3274             }
3275
3276             static bool OnResumed(IAsyncResult result)
3277             {
3278                 ResumeBookmarkAsyncResult thisPtr = (ResumeBookmarkAsyncResult)result.AsyncState;
3279                 thisPtr.instance.EndRun(result);
3280                 return thisPtr.StartResumptionLoop();
3281             }
3282
3283             bool StartResumptionLoop()
3284             {
3285                 this.currentOperation = new RequiresIdleOperation(this.isFromExtension);
3286                 return WaitOnCurrentOperation();
3287             }            
3288
3289             bool WaitOnCurrentOperation()
3290             {
3291                 bool stillSync = true;
3292                 bool tryOneMore = true;
3293
3294                 while (tryOneMore)
3295                 {
3296                     tryOneMore = false;
3297
3298                     Fx.Assert(this.currentOperation != null, "We should always have a current operation here.");
3299
3300                     if (this.instance.WaitForTurnAsync(this.currentOperation, this.timeoutHelper.RemainingTime(), waitCompleteCallback, this))
3301                     {
3302                         ClearPendedUnenqueued();
3303
3304                         if (CheckIfBookmarksAreInvalid())
3305                         {
3306                             stillSync = true;
3307                         }
3308                         else
3309                         {
3310                             stillSync = ProcessResumption();
3311
3312                             tryOneMore = this.resumptionResult == BookmarkResumptionResult.NotReady;
3313                         }
3314                     }
3315                     else
3316                     {
3317                         stillSync = false;
3318                     }
3319                 }
3320
3321                 return stillSync;
3322             }
3323
3324             static void OnWaitComplete(object state, TimeoutException asyncException)
3325             {
3326                 ResumeBookmarkAsyncResult thisPtr = (ResumeBookmarkAsyncResult)state;
3327
3328                 if (asyncException != null)
3329                 {
3330                     thisPtr.Complete(false, asyncException);
3331                     return;
3332                 }
3333
3334                 Exception completionException = null;
3335                 bool completeSelf = false;
3336
3337                 try
3338                 {
3339                     thisPtr.ClearPendedUnenqueued();
3340
3341                     if (thisPtr.CheckIfBookmarksAreInvalid())
3342                     {
3343                         completeSelf = true;
3344                     }
3345                     else
3346                     {
3347                         completeSelf = thisPtr.ProcessResumption();
3348
3349                         if (thisPtr.resumptionResult == BookmarkResumptionResult.NotReady)
3350                         {
3351                             completeSelf = thisPtr.WaitOnCurrentOperation();
3352                         }
3353                     }
3354                 }
3355                 catch (Exception e)
3356                 {
3357                     if (Fx.IsFatal(e))
3358                     {
3359                         throw;
3360                     }
3361
3362                     completeSelf = true;
3363                     completionException = e;
3364                 }
3365
3366                 if (completeSelf)
3367                 {
3368                     thisPtr.Complete(false, completionException);
3369                 }
3370             }
3371
3372             bool CheckIfBookmarksAreInvalid()
3373             {
3374                 if (this.instance.AreBookmarksInvalid(out this.resumptionResult))
3375                 {
3376                     return true;
3377                 }
3378
3379                 return false;
3380             }
3381
3382             bool ProcessResumption()
3383             {
3384                 bool stillSync = true;
3385
3386                 this.resumptionResult = this.instance.ResumeBookmarkCore(this.bookmark, this.value);
3387
3388                 if (this.resumptionResult == BookmarkResumptionResult.Success)
3389                 {
3390                     if (this.instance.Controller.HasPendingTrackingRecords)
3391                     {
3392                         IAsyncResult result = this.instance.Controller.BeginFlushTrackingRecords(this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(trackingCompleteCallback), this);
3393
3394                         if (result.CompletedSynchronously)
3395                         {
3396                             stillSync = OnTrackingComplete(result);
3397                         }
3398                         else
3399                         {
3400                             stillSync = false;
3401                         }
3402                     }
3403                 }
3404                 else if (this.resumptionResult == BookmarkResumptionResult.NotReady)
3405                 {
3406                     NotifyOperationComplete();
3407                     this.currentOperation = new DeferredRequiresIdleOperation();
3408                 }
3409
3410                 return stillSync;
3411             }
3412
3413             static bool OnTrackingComplete(IAsyncResult result)
3414             {
3415                 ResumeBookmarkAsyncResult thisPtr = (ResumeBookmarkAsyncResult)result.AsyncState;
3416
3417                 thisPtr.instance.Controller.EndFlushTrackingRecords(result);
3418
3419                 return true;
3420             }
3421         }
3422
3423         class UnloadOrPersistAsyncResult : TransactedAsyncResult
3424         {
3425             static Action<object, TimeoutException> waitCompleteCallback = new Action<object, TimeoutException>(OnWaitComplete);
3426             static AsyncCompletion savedCallback = new AsyncCompletion(OnSaved);
3427             static AsyncCompletion persistedCallback = new AsyncCompletion(OnPersisted);
3428             static AsyncCompletion initializedCallback = new AsyncCompletion(OnProviderInitialized);
3429             static AsyncCompletion readynessEnsuredCallback = new AsyncCompletion(OnProviderReadynessEnsured);
3430             static AsyncCompletion trackingCompleteCallback = new AsyncCompletion(OnTrackingComplete);
3431             static AsyncCompletion deleteOwnerCompleteCallback = new AsyncCompletion(OnOwnerDeleted);
3432             static AsyncCompletion completeContextCallback = new AsyncCompletion(OnCompleteContext);
3433             static Action<AsyncResult, Exception> completeCallback = new Action<AsyncResult, Exception>(OnComplete);
3434
3435             DependentTransaction dependentTransaction;
3436             WorkflowApplication instance;
3437             bool isUnloaded;
3438             TimeoutHelper timeoutHelper;
3439             PersistenceOperation operation;
3440             RequiresPersistenceOperation instanceOperation;
3441             WorkflowPersistenceContext context;
3442             IDictionary<XName, InstanceValue> data;
3443             PersistencePipeline pipeline;
3444             bool isInternalPersist;
3445
3446             public UnloadOrPersistAsyncResult(WorkflowApplication instance, TimeSpan timeout, PersistenceOperation operation,
3447                 bool isWorkflowThread, bool isInternalPersist, AsyncCallback callback, object state)
3448                 : base(callback, state)
3449             {
3450                 this.instance = instance;
3451                 this.timeoutHelper = new TimeoutHelper(timeout);
3452                 this.operation = operation;
3453                 this.isInternalPersist = isInternalPersist;
3454                 this.isUnloaded = (operation == PersistenceOperation.Unload || operation == PersistenceOperation.Complete);
3455
3456                 this.OnCompleting = UnloadOrPersistAsyncResult.completeCallback;
3457
3458                 bool completeSelf;
3459                 bool success = false;
3460
3461                 // Save off the current transaction in case we have an async operation before we end up creating
3462                 // the WorkflowPersistenceContext and create it on another thread. Do a blocking dependent clone that
3463                 // we will complete when we are completed.
3464                 //
3465                 // This will throw TransactionAbortedException by design, if the transaction is already rolled back.
3466                 Transaction currentTransaction = Transaction.Current;
3467                 if (currentTransaction != null)
3468                 {
3469                     this.dependentTransaction = currentTransaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
3470                 }
3471
3472                 try
3473                 {
3474                     if (isWorkflowThread)
3475                     {
3476                         Fx.Assert(this.instance.Controller.IsPersistable, "The runtime won't schedule this work item unless we've passed the guard");
3477
3478                         // We're an internal persistence on the workflow thread which means
3479                         // that we are passed the guard already, we have the lock, and we know
3480                         // we aren't detached.
3481
3482                         completeSelf = InitializeProvider();
3483                         success = true;
3484                     }
3485                     else
3486                     {
3487                         this.instanceOperation = new RequiresPersistenceOperation();
3488                         try
3489                         {
3490                             if (this.instance.WaitForTurnAsync(this.instanceOperation, this.timeoutHelper.RemainingTime(), waitCompleteCallback, this))
3491                             {
3492                                 completeSelf = ValidateState();
3493                             }
3494                             else
3495                             {
3496                                 completeSelf = false;
3497                             }
3498                             success = true;
3499                         }
3500                         finally
3501                         {
3502                             if (!success)
3503                             {
3504                                 NotifyOperationComplete();
3505                             }
3506                         }
3507                     }
3508                 }
3509                 finally
3510                 {
3511                     // If we had an exception, we need to complete the dependent transaction.
3512                     if (!success)
3513                     {
3514                         if (this.dependentTransaction != null)
3515                         {
3516                             this.dependentTransaction.Complete();
3517                         }
3518                     }
3519                 }
3520
3521                 if (completeSelf)
3522                 {
3523                     Complete(true);
3524                 }
3525             }
3526
3527             bool ValidateState()
3528             {
3529                 bool alreadyUnloaded = false;
3530                 if (this.operation == PersistenceOperation.Unload)
3531                 {
3532                     this.instance.ValidateStateForUnload();
3533                     alreadyUnloaded = this.instance.state == WorkflowApplicationState.Unloaded;
3534                 }
3535                 else
3536                 {
3537                     this.instance.ValidateStateForPersist();
3538                 }
3539
3540                 if (alreadyUnloaded)
3541                 {
3542                     return true;
3543                 }
3544                 else
3545                 {
3546                     return InitializeProvider();
3547                 }
3548             }
3549
3550             static void OnWaitComplete(object state, TimeoutException asyncException)
3551             {
3552                 UnloadOrPersistAsyncResult thisPtr = (UnloadOrPersistAsyncResult)state;
3553                 if (asyncException != null)
3554                 {
3555                     thisPtr.Complete(false, asyncException);
3556                     return;
3557                 }
3558
3559                 bool completeSelf;
3560                 Exception completionException = null;
3561
3562                 try
3563                 {
3564                     completeSelf = thisPtr.ValidateState();
3565                 }
3566                 catch (Exception e)
3567                 {
3568                     if (Fx.IsFatal(e))
3569                     {
3570                         throw;
3571                     }
3572
3573                     completionException = e;
3574                     completeSelf = true;
3575                 }
3576
3577                 if (completeSelf)
3578                 {
3579                     thisPtr.Complete(false, completionException);
3580                 }
3581             }
3582
3583             bool InitializeProvider()
3584             {
3585                 // We finally have the lock and are passed the guard.  Let's update our operation if this is an Unload.
3586                 if (this.operation == PersistenceOperation.Unload && this.instance.Controller.State == WorkflowInstanceState.Complete)
3587                 {
3588                     this.operation = PersistenceOperation.Complete;
3589                 }
3590
3591                 if (this.instance.HasPersistenceProvider && !this.instance.persistenceManager.IsInitialized)
3592                 {
3593                     IAsyncResult result = this.instance.persistenceManager.BeginInitialize(this.instance.DefinitionIdentity, this.timeoutHelper.RemainingTime(),
3594                         PrepareAsyncCompletion(UnloadOrPersistAsyncResult.initializedCallback), this);
3595                     return SyncContinue(result);
3596                 }
3597                 else
3598                 {
3599                     return EnsureProviderReadyness();
3600                 }
3601             }
3602
3603             static bool OnProviderInitialized(IAsyncResult result)
3604             {
3605                 UnloadOrPersistAsyncResult thisPtr = (UnloadOrPersistAsyncResult)result.AsyncState;
3606                 thisPtr.instance.persistenceManager.EndInitialize(result);
3607                 return thisPtr.EnsureProviderReadyness();
3608             }
3609
3610             bool EnsureProviderReadyness()
3611             {
3612                 if (this.instance.HasPersistenceProvider && !this.instance.persistenceManager.IsLocked && this.dependentTransaction != null)
3613                 {
3614                     IAsyncResult result = this.instance.persistenceManager.BeginEnsureReadyness(this.timeoutHelper.RemainingTime(),
3615                         PrepareAsyncCompletion(UnloadOrPersistAsyncResult.readynessEnsuredCallback), this);
3616                     return SyncContinue(result);
3617                 }
3618                 else
3619                 {
3620                     return Track();
3621                 }
3622             }
3623
3624             static bool OnProviderReadynessEnsured(IAsyncResult result)
3625             {
3626                 UnloadOrPersistAsyncResult thisPtr = (UnloadOrPersistAsyncResult)result.AsyncState;
3627                 thisPtr.instance.persistenceManager.EndEnsureReadyness(result);
3628                 return thisPtr.Track();
3629             }
3630
3631             public static void End(IAsyncResult result)
3632             {
3633                 AsyncResult.End<UnloadOrPersistAsyncResult>(result);
3634             }
3635
3636             void NotifyOperationComplete()
3637             {
3638                 RequiresPersistenceOperation localInstanceOperation = this.instanceOperation;
3639                 this.instanceOperation = null;
3640                 this.instance.NotifyOperationComplete(localInstanceOperation);
3641             }
3642
3643             bool Track()
3644             {
3645                 // Do the tracking before preparing in case the tracking data is being pushed into
3646                 // an extension and persisted transactionally with the instance state.
3647
3648                 if (this.instance.HasPersistenceProvider)
3649                 {
3650                     // We only track the persistence operation if we actually
3651                     // are persisting (and not just hitting PersistenceParticipants)
3652                     this.instance.TrackPersistence(this.operation);
3653                 }
3654
3655                 if (this.instance.Controller.HasPendingTrackingRecords)
3656                 {
3657                     TimeSpan flushTrackingRecordsTimeout;
3658
3659                     if (this.isInternalPersist)
3660                     {
3661                         // If we're an internal persist we're using TimeSpan.MaxValue
3662                         // for our persistence and we want to use a smaller timeout
3663                         // for tracking
3664                         flushTrackingRecordsTimeout = ActivityDefaults.TrackingTimeout;
3665                     }
3666                     else
3667                     {
3668                         flushTrackingRecordsTimeout = this.timeoutHelper.RemainingTime();
3669                     }
3670
3671                     IAsyncResult result = this.instance.Controller.BeginFlushTrackingRecords(flushTrackingRecordsTimeout, PrepareAsyncCompletion(trackingCompleteCallback), this);
3672                     return SyncContinue(result);
3673                 }
3674
3675                 return CollectAndMap();
3676             }
3677
3678             static bool OnTrackingComplete(IAsyncResult result)
3679             {
3680                 UnloadOrPersistAsyncResult thisPtr = (UnloadOrPersistAsyncResult)result.AsyncState;
3681                 thisPtr.instance.Controller.EndFlushTrackingRecords(result);
3682                 return thisPtr.CollectAndMap();
3683             }
3684
3685             bool CollectAndMap()
3686             {
3687                 bool success = false;
3688                 try
3689                 {
3690                     if (this.instance.HasPersistenceModule)
3691                     {
3692                         IEnumerable<IPersistencePipelineModule> modules = this.instance.GetExtensions<IPersistencePipelineModule>();
3693                         this.pipeline = new PersistencePipeline(modules, PersistenceManager.GenerateInitialData(this.instance));
3694                         this.pipeline.Collect();
3695                         this.pipeline.Map();
3696                         this.data = this.pipeline.Values;
3697                     }
3698                     success = true;
3699                 }
3700                 finally
3701                 {
3702                     if (!success && this.context != null)
3703                     {
3704                         this.context.Abort();
3705                     }
3706                 }
3707
3708                 if (this.instance.HasPersistenceProvider)
3709                 {
3710                     return Persist();
3711                 }
3712                 else
3713                 {
3714                     return Save();
3715                 }
3716             }
3717
3718             bool Persist()
3719             {
3720                 IAsyncResult result = null;
3721                 try
3722                 {
3723                     if (this.data == null)
3724                     {
3725                         this.data = PersistenceManager.GenerateInitialData(this.instance);
3726                     }
3727
3728                     if (this.context == null)
3729                     {
3730                         this.context = new WorkflowPersistenceContext(this.pipeline != null && this.pipeline.IsSaveTransactionRequired,
3731                             this.dependentTransaction, this.timeoutHelper.OriginalTimeout);
3732                     }
3733
3734                     using (PrepareTransactionalCall(this.context.PublicTransaction))
3735                     {
3736                         result = this.instance.persistenceManager.BeginSave(this.data, this.operation, this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(persistedCallback), this);
3737                     }
3738                 }
3739                 finally
3740                 {
3741                     if (result == null && this.context != null)
3742                     {
3743                         this.context.Abort();
3744                     }
3745                 }
3746                 return SyncContinue(result);
3747             }
3748
3749             static bool OnPersisted(IAsyncResult result)
3750             {
3751                 UnloadOrPersistAsyncResult thisPtr = (UnloadOrPersistAsyncResult)result.AsyncState;
3752                 bool success = false;
3753                 try
3754                 {
3755                     thisPtr.instance.persistenceManager.EndSave(result);
3756                     success = true;
3757                 }
3758                 finally
3759                 {
3760                     if (!success)
3761                     {
3762                         thisPtr.context.Abort();
3763                     }
3764                 }
3765                 return thisPtr.Save();
3766             }
3767
3768             bool Save()
3769             {
3770                 if (this.pipeline != null)
3771                 {
3772                     IAsyncResult result = null;
3773                     try
3774                     {
3775                         if (this.context == null)
3776                         {
3777                             this.context = new WorkflowPersistenceContext(this.pipeline.IsSaveTransactionRequired,
3778                                 this.dependentTransaction, this.timeoutHelper.RemainingTime());
3779                         }
3780
3781                         this.instance.persistencePipelineInUse = this.pipeline;
3782                         Thread.MemoryBarrier();
3783                         if (this.instance.state == WorkflowApplicationState.Aborted)
3784                         {
3785                             throw FxTrace.Exception.AsError(new OperationCanceledException(SR.DefaultAbortReason));
3786                         }
3787
3788                         using (PrepareTransactionalCall(this.context.PublicTransaction))
3789                         {
3790                             result = this.pipeline.BeginSave(this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(savedCallback), this);
3791                         }
3792                     }
3793                     finally
3794                     {
3795                         if (result == null)
3796                         {
3797                             this.instance.persistencePipelineInUse = null;
3798                             if (this.context != null)
3799                             {
3800                                 this.context.Abort();
3801                             }
3802                         }
3803                     }
3804                     return SyncContinue(result);
3805                 }
3806                 else
3807                 {
3808                     return CompleteContext();
3809                 }
3810             }
3811
3812             static bool OnSaved(IAsyncResult result)
3813             {
3814                 UnloadOrPersistAsyncResult thisPtr = (UnloadOrPersistAsyncResult)result.AsyncState;
3815
3816                 bool success = false;
3817                 try
3818                 {
3819                     thisPtr.pipeline.EndSave(result);
3820                     success = true;
3821                 }
3822                 finally
3823                 {
3824                     thisPtr.instance.persistencePipelineInUse = null;
3825                     if (!success)
3826                     {
3827                         thisPtr.context.Abort();
3828                     }
3829                 }
3830
3831                 return thisPtr.CompleteContext();
3832             }
3833
3834             bool CompleteContext()
3835             {
3836                 bool wentAsync = false;
3837                 IAsyncResult completeResult = null;
3838
3839                 if (this.context != null)
3840                 {
3841                     wentAsync = this.context.TryBeginComplete(this.PrepareAsyncCompletion(completeContextCallback), this, out completeResult);
3842                 }
3843
3844                 if (wentAsync)
3845                 {
3846                     Fx.Assert(completeResult != null, "We shouldn't have null here because we would have rethrown or gotten false for went async.");
3847                     return SyncContinue(completeResult);
3848                 }
3849                 else
3850                 {
3851                     // We completed synchronously if we didn't get an async result out of
3852                     // TryBeginComplete
3853                     return DeleteOwner();
3854                 }
3855             }
3856
3857             static bool OnCompleteContext(IAsyncResult result)
3858             {
3859                 UnloadOrPersistAsyncResult thisPtr = (UnloadOrPersistAsyncResult)result.AsyncState;
3860                 thisPtr.context.EndComplete(result);
3861
3862                 return thisPtr.DeleteOwner();
3863             }
3864
3865             bool DeleteOwner()
3866             {
3867                 if (this.instance.HasPersistenceProvider && this.instance.persistenceManager.OwnerWasCreated &&
3868                     (this.operation == PersistenceOperation.Unload || this.operation == PersistenceOperation.Complete))
3869                 {
3870                     // This call uses the ambient transaction directly if there was one, to mimic the [....] case.
3871                     // 
3872                     IAsyncResult deleteOwnerResult = null;
3873                     using (PrepareTransactionalCall(this.dependentTransaction))
3874                     {
3875                         deleteOwnerResult = this.instance.persistenceManager.BeginDeleteOwner(this.timeoutHelper.RemainingTime(),
3876                             this.PrepareAsyncCompletion(UnloadOrPersistAsyncResult.deleteOwnerCompleteCallback), this);
3877                     }
3878                     return this.SyncContinue(deleteOwnerResult);
3879                 }
3880                 else
3881                 {
3882                     return CloseInstance();
3883                 }
3884             }
3885
3886             static bool OnOwnerDeleted(IAsyncResult result)
3887             {
3888                 UnloadOrPersistAsyncResult thisPtr = (UnloadOrPersistAsyncResult)result.AsyncState;
3889                 thisPtr.instance.persistenceManager.EndDeleteOwner(result);
3890                 return thisPtr.CloseInstance();
3891             }
3892
3893             bool CloseInstance()
3894             {
3895                 // NOTE: We need to make sure that any changes which occur
3896                 // here are appropriately ported to WorkflowApplication's
3897                 // CompletionHandler.OnStage1Complete method in the case
3898                 // where we don't call BeginPersist.
3899                 if (this.operation != PersistenceOperation.Save)
3900                 {
3901                     // Stop execution if we've given up the instance lock
3902                     this.instance.state = WorkflowApplicationState.Paused;
3903                 }
3904
3905                 if (this.isUnloaded)
3906                 {
3907                     this.instance.MarkUnloaded();
3908                 }
3909
3910                 return true;
3911             }
3912
3913             static void OnComplete(AsyncResult result, Exception exception)
3914             {
3915                 UnloadOrPersistAsyncResult thisPtr = (UnloadOrPersistAsyncResult)result;
3916                 try
3917                 {
3918                     thisPtr.NotifyOperationComplete();
3919                 }
3920                 finally
3921                 {
3922                     if (thisPtr.dependentTransaction != null)
3923                     {
3924                         thisPtr.dependentTransaction.Complete();
3925                     }
3926                 }
3927             }
3928         }
3929
3930         abstract class SimpleOperationAsyncResult : AsyncResult
3931         {
3932             static Action<object, TimeoutException> waitCompleteCallback = new Action<object, TimeoutException>(OnWaitComplete);
3933             static AsyncCallback trackingCompleteCallback = Fx.ThunkCallback(new AsyncCallback(OnTrackingComplete));
3934
3935             WorkflowApplication instance;
3936             TimeoutHelper timeoutHelper;
3937
3938             protected SimpleOperationAsyncResult(WorkflowApplication instance, AsyncCallback callback, object state)
3939                 : base(callback, state)
3940             {
3941                 this.instance = instance;
3942             }
3943
3944             protected WorkflowApplication Instance
3945             {
3946                 get
3947                 {
3948                     return this.instance;
3949                 }
3950             }
3951
3952             protected void Run(TimeSpan timeout)
3953             {
3954                 this.timeoutHelper = new TimeoutHelper(timeout);
3955
3956                 InstanceOperation operation = new InstanceOperation();
3957
3958                 bool completeSelf = true;
3959
3960                 try
3961                 {
3962                     completeSelf = this.instance.WaitForTurnAsync(operation, this.timeoutHelper.RemainingTime(), waitCompleteCallback, this);
3963
3964                     if (completeSelf)
3965                     {
3966                         this.ValidateState();
3967
3968                         completeSelf = PerformOperationAndTrack();
3969                     }
3970                 }
3971                 finally
3972                 {
3973                     if (completeSelf)
3974                     {
3975                         this.instance.NotifyOperationComplete(operation);
3976                     }
3977                 }
3978
3979                 if (completeSelf)
3980                 {
3981                     Complete(true);
3982                 }
3983             }
3984
3985             bool PerformOperationAndTrack()
3986             {
3987                 PerformOperation();
3988
3989                 bool completedSync = true;
3990
3991                 if (this.instance.Controller.HasPendingTrackingRecords)
3992                 {
3993                     IAsyncResult trackingResult = this.instance.Controller.BeginFlushTrackingRecords(this.timeoutHelper.RemainingTime(), trackingCompleteCallback, this);
3994
3995                     if (trackingResult.CompletedSynchronously)
3996                     {
3997                         this.instance.Controller.EndFlushTrackingRecords(trackingResult);
3998                     }
3999                     else
4000                     {
4001                         completedSync = false;
4002                     }
4003                 }
4004
4005                 return completedSync;
4006             }
4007
4008             static void OnWaitComplete(object state, TimeoutException asyncException)
4009             {
4010                 SimpleOperationAsyncResult thisPtr = (SimpleOperationAsyncResult)state;
4011
4012                 if (asyncException != null)
4013                 {
4014                     thisPtr.Complete(false, asyncException);
4015                 }
4016                 else
4017                 {
4018                     Exception completionException = null;
4019                     bool completeSelf = true;
4020
4021                     try
4022                     {
4023                         thisPtr.ValidateState();
4024
4025                         completeSelf = thisPtr.PerformOperationAndTrack();
4026                     }
4027                     catch (Exception e)
4028                     {
4029                         if (Fx.IsFatal(e))
4030                         {
4031                             throw;
4032                         }
4033
4034                         completionException = e;
4035                     }
4036                     finally
4037                     {
4038                         if (completeSelf)
4039                         {
4040                             thisPtr.instance.ForceNotifyOperationComplete();
4041                         }
4042                     }
4043
4044                     if (completeSelf)
4045                     {
4046                         thisPtr.Complete(false, completionException);
4047                     }
4048                 }
4049             }
4050
4051             static void OnTrackingComplete(IAsyncResult result)
4052             {
4053                 if (result.CompletedSynchronously)
4054                 {
4055                     return;
4056                 }
4057
4058                 SimpleOperationAsyncResult thisPtr = (SimpleOperationAsyncResult)result.AsyncState;
4059
4060                 Exception completionException = null;
4061
4062                 try
4063                 {
4064                     thisPtr.instance.Controller.EndFlushTrackingRecords(result);
4065                 }
4066                 catch (Exception e)
4067                 {
4068                     if (Fx.IsFatal(e))
4069                     {
4070                         throw;
4071                     }
4072
4073                     completionException = e;
4074                 }
4075                 finally
4076                 {
4077                     thisPtr.instance.ForceNotifyOperationComplete();
4078                 }
4079
4080                 thisPtr.Complete(false, completionException);
4081             }
4082
4083             protected abstract void ValidateState();
4084             protected abstract void PerformOperation();
4085         }
4086
4087         class TerminateAsyncResult : SimpleOperationAsyncResult
4088         {
4089             Exception reason;
4090
4091             TerminateAsyncResult(WorkflowApplication instance, Exception reason, AsyncCallback callback, object state)
4092                 : base(instance, callback, state)
4093             {
4094                 this.reason = reason;
4095             }
4096
4097             public static TerminateAsyncResult Create(WorkflowApplication instance, Exception reason, TimeSpan timeout, AsyncCallback callback, object state)
4098             {
4099                 TerminateAsyncResult result = new TerminateAsyncResult(instance, reason, callback, state);
4100                 result.Run(timeout);
4101                 return result;
4102             }
4103
4104             public static void End(IAsyncResult result)
4105             {
4106                 AsyncResult.End<TerminateAsyncResult>(result);
4107             }
4108
4109             protected override void ValidateState()
4110             {
4111                 this.Instance.ValidateStateForTerminate();
4112             }
4113
4114             protected override void PerformOperation()
4115             {
4116                 this.Instance.TerminateCore(this.reason);
4117             }
4118         }
4119
4120         class CancelAsyncResult : SimpleOperationAsyncResult
4121         {
4122             CancelAsyncResult(WorkflowApplication instance, AsyncCallback callback, object state)
4123                 : base(instance, callback, state)
4124             {
4125             }
4126
4127             public static CancelAsyncResult Create(WorkflowApplication instance, TimeSpan timeout, AsyncCallback callback, object state)
4128             {
4129                 CancelAsyncResult result = new CancelAsyncResult(instance, callback, state);
4130                 result.Run(timeout);
4131                 return result;
4132             }
4133
4134             public static void End(IAsyncResult result)
4135             {
4136                 AsyncResult.End<CancelAsyncResult>(result);
4137             }
4138
4139             protected override void ValidateState()
4140             {
4141                 this.Instance.ValidateStateForCancel();
4142             }
4143
4144             protected override void PerformOperation()
4145             {
4146                 this.Instance.CancelCore();
4147             }
4148         }
4149
4150         class RunAsyncResult : SimpleOperationAsyncResult
4151         {
4152             bool isUserRun;
4153
4154             RunAsyncResult(WorkflowApplication instance, bool isUserRun, AsyncCallback callback, object state)
4155                 : base(instance, callback, state)
4156             {
4157                 this.isUserRun = isUserRun;
4158             }
4159
4160             public static RunAsyncResult Create(WorkflowApplication instance, bool isUserRun, TimeSpan timeout, AsyncCallback callback, object state)
4161             {
4162                 RunAsyncResult result = new RunAsyncResult(instance, isUserRun, callback, state);
4163                 result.Run(timeout);
4164                 return result;
4165             }
4166
4167             public static void End(IAsyncResult result)
4168             {
4169                 AsyncResult.End<RunAsyncResult>(result);
4170             }
4171
4172             protected override void ValidateState()
4173             {
4174                 this.Instance.ValidateStateForRun();
4175             }
4176
4177             protected override void PerformOperation()
4178             {
4179                 if (this.isUserRun)
4180                 {
4181                     // We set this to true here so that idle will be raised
4182                     // regardless of whether any work is performed.
4183                     this.Instance.hasExecutionOccurredSinceLastIdle = true;
4184                 }
4185
4186                 this.Instance.RunCore();
4187             }
4188         }
4189
4190         class UnlockInstanceAsyncResult : TransactedAsyncResult
4191         {
4192             static AsyncCompletion instanceUnlockedCallback = new AsyncCompletion(OnInstanceUnlocked);
4193             static AsyncCompletion ownerDeletedCallback = new AsyncCompletion(OnOwnerDeleted);
4194             static Action<AsyncResult, Exception> completeCallback = new Action<AsyncResult, Exception>(OnComplete);
4195
4196             readonly PersistenceManager persistenceManager;
4197             readonly TimeoutHelper timeoutHelper;
4198
4199             DependentTransaction dependentTransaction;
4200
4201             public UnlockInstanceAsyncResult(PersistenceManager persistenceManager, TimeoutHelper timeoutHelper, AsyncCallback callback, object state)
4202                 : base(callback, state)
4203             {
4204                 this.persistenceManager = persistenceManager;
4205                 this.timeoutHelper = timeoutHelper;
4206
4207                 Transaction currentTransaction = Transaction.Current;
4208                 if (currentTransaction != null)
4209                 {
4210                     this.dependentTransaction = currentTransaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
4211                 }
4212
4213                 OnCompleting = UnlockInstanceAsyncResult.completeCallback;
4214
4215                 bool success = false;
4216                 try
4217                 {
4218                     IAsyncResult result;
4219                     using (this.PrepareTransactionalCall(this.dependentTransaction))
4220                     {
4221                         if (this.persistenceManager.OwnerWasCreated)
4222                         {
4223                             // if the owner was created by this WorkflowApplication, delete it.
4224                             // This implicitly unlocks the instance.
4225                             result = this.persistenceManager.BeginDeleteOwner(this.timeoutHelper.RemainingTime(), this.PrepareAsyncCompletion(ownerDeletedCallback), this);
4226                         }
4227                         else
4228                         {
4229                             result = this.persistenceManager.BeginUnlock(this.timeoutHelper.RemainingTime(), this.PrepareAsyncCompletion(instanceUnlockedCallback), this);
4230                         }
4231                     }
4232
4233                     if (SyncContinue(result))
4234                     {
4235                         Complete(true);
4236                     }
4237
4238                     success = true;
4239                 }
4240                 finally
4241                 {
4242                     if (!success)
4243                     {
4244                         this.persistenceManager.Abort();
4245                     }
4246                 }
4247             }
4248
4249             public static void End(IAsyncResult result)
4250             {
4251                 AsyncResult.End<UnlockInstanceAsyncResult>(result);
4252             }
4253
4254             static bool OnInstanceUnlocked(IAsyncResult result)
4255             {
4256                 UnlockInstanceAsyncResult thisPtr = (UnlockInstanceAsyncResult)result.AsyncState;
4257                 thisPtr.persistenceManager.EndUnlock(result);
4258                 return true;
4259             }
4260
4261             static bool OnOwnerDeleted(IAsyncResult result)
4262             {
4263                 UnlockInstanceAsyncResult thisPtr = (UnlockInstanceAsyncResult)result.AsyncState;
4264                 thisPtr.persistenceManager.EndDeleteOwner(result);
4265                 return true;
4266             }
4267
4268             static void OnComplete(AsyncResult result, Exception exception)
4269             {
4270                 UnlockInstanceAsyncResult thisPtr = (UnlockInstanceAsyncResult)result;
4271                 if (thisPtr.dependentTransaction != null)
4272                 {
4273                     thisPtr.dependentTransaction.Complete();
4274                 }
4275                 thisPtr.persistenceManager.Abort();
4276             }
4277         }
4278
4279         class LoadAsyncResult : TransactedAsyncResult
4280         {
4281             static Action<object, TimeoutException> waitCompleteCallback = new Action<object, TimeoutException>(OnWaitComplete);
4282             static AsyncCompletion providerRegisteredCallback = new AsyncCompletion(OnProviderRegistered);
4283             static AsyncCompletion loadCompleteCallback = new AsyncCompletion(OnLoadComplete);
4284             static AsyncCompletion loadPipelineCallback = new AsyncCompletion(OnLoadPipeline);
4285             static AsyncCompletion completeContextCallback = new AsyncCompletion(OnCompleteContext);
4286             static Action<AsyncResult, Exception> completeCallback = new Action<AsyncResult, Exception>(OnComplete);
4287
4288             readonly WorkflowApplication application;
4289             readonly PersistenceManager persistenceManager;
4290             readonly TimeoutHelper timeoutHelper;
4291             readonly bool loadAny;
4292
4293             object deserializedRuntimeState;
4294             PersistencePipeline pipeline;
4295             WorkflowPersistenceContext context;
4296             DependentTransaction dependentTransaction;
4297             IDictionary<XName, InstanceValue> values;
4298             DynamicUpdateMap updateMap;
4299             InstanceOperation instanceOperation;
4300
4301             public LoadAsyncResult(WorkflowApplication application, PersistenceManager persistenceManager,
4302                 IDictionary<XName, InstanceValue> values, DynamicUpdateMap updateMap, TimeSpan timeout, 
4303                 AsyncCallback callback, object state)
4304                 : base(callback, state)
4305             {
4306                 this.application = application;
4307                 this.persistenceManager = persistenceManager;
4308                 this.values = values;
4309                 this.timeoutHelper = new TimeoutHelper(timeout);
4310                 this.updateMap = updateMap;
4311
4312                 Initialize();
4313             }
4314
4315             public LoadAsyncResult(WorkflowApplication application, PersistenceManager persistenceManager,
4316                 bool loadAny, TimeSpan timeout, AsyncCallback callback, object state)
4317                 : base(callback, state)
4318             {
4319                 this.application = application;
4320                 this.persistenceManager = persistenceManager;
4321                 this.loadAny = loadAny;
4322                 this.timeoutHelper = new TimeoutHelper(timeout);
4323
4324                 Initialize();
4325             }
4326
4327             void Initialize()
4328             {
4329                 OnCompleting = LoadAsyncResult.completeCallback;
4330
4331                 // Save off the current transaction in case we have an async operation before we end up creating
4332                 // the WorkflowPersistenceContext and create it on another thread. Do a simple clone here to prevent
4333                 // the object referenced by Transaction.Current from disposing before we get around to referencing it
4334                 // when we create the WorkflowPersistenceContext.
4335                 //
4336                 // This will throw TransactionAbortedException by design, if the transaction is already rolled back.
4337                 Transaction currentTransaction = Transaction.Current;
4338                 if (currentTransaction != null)
4339                 {
4340                     this.dependentTransaction = currentTransaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
4341                 }
4342
4343                 bool completeSelf;
4344                 bool success = false;
4345                 Exception updateException = null;
4346                 try
4347                 {
4348                     if (this.application == null)
4349                     {
4350                         completeSelf = RegisterProvider();
4351                     }
4352                     else
4353                     {
4354                         completeSelf = WaitForTurn();
4355                     }
4356                     success = true;
4357                 }
4358                 catch (InstanceUpdateException e)
4359                 {
4360                     updateException = e;
4361                     throw;
4362                 }
4363                 catch (VersionMismatchException e)
4364                 {
4365                     updateException = e;
4366                     throw;
4367                 }
4368                 finally
4369                 {
4370                     if (!success)
4371                     {
4372                         if (this.dependentTransaction != null)
4373                         {
4374                             this.dependentTransaction.Complete();
4375                         }
4376                         Abort(this, updateException);
4377                     }
4378                 }
4379
4380                 if (completeSelf)
4381                 {
4382                     Complete(true);
4383                 }
4384             }
4385
4386             public static void End(IAsyncResult result)
4387             {
4388                 AsyncResult.End<LoadAsyncResult>(result);
4389             }
4390
4391             public static WorkflowApplicationInstance EndAndCreateInstance(IAsyncResult result)
4392             {
4393                 LoadAsyncResult thisPtr = AsyncResult.End<LoadAsyncResult>(result);
4394                 Fx.AssertAndThrow(thisPtr.application == null, "Should not create a WorkflowApplicationInstance if we already have a WorkflowApplication");
4395
4396                 ActivityExecutor deserializedRuntimeState = WorkflowApplication.ExtractRuntimeState(thisPtr.values, thisPtr.persistenceManager.InstanceId);
4397                 return new WorkflowApplicationInstance(thisPtr.persistenceManager, thisPtr.values, deserializedRuntimeState.WorkflowIdentity);
4398             }
4399
4400             bool WaitForTurn()
4401             {
4402                 bool completeSelf;
4403                 bool success = false;
4404                 this.instanceOperation = new InstanceOperation { RequiresInitialized = false };
4405                 try
4406                 {
4407                     if (this.application.WaitForTurnAsync(this.instanceOperation, this.timeoutHelper.RemainingTime(), waitCompleteCallback, this))
4408                     {
4409                         completeSelf = ValidateState();
4410                     }
4411                     else
4412                     {
4413                         completeSelf = false;
4414                     }
4415                     success = true;
4416                 }
4417                 finally
4418                 {
4419                     if (!success)
4420                     {
4421                         NotifyOperationComplete();
4422                     }
4423                 }
4424
4425                 return completeSelf;
4426             }
4427
4428             static void OnWaitComplete(object state, TimeoutException asyncException)
4429             {
4430                 LoadAsyncResult thisPtr = (LoadAsyncResult)state;
4431                 if (asyncException != null)
4432                 {
4433                     thisPtr.Complete(false, asyncException);
4434                     return;
4435                 }
4436
4437                 bool completeSelf;
4438                 Exception completionException = null;
4439
4440                 try
4441                 {
4442                     completeSelf = thisPtr.ValidateState();
4443                 }
4444                 catch (Exception e)
4445                 {
4446                     if (Fx.IsFatal(e))
4447                     {
4448                         throw;
4449                     }
4450
4451                     completionException = e;
4452                     completeSelf = true;
4453                 }
4454
4455                 if (completeSelf)
4456                 {
4457                     thisPtr.Complete(false, completionException);
4458                 }
4459             }
4460
4461             bool ValidateState()
4462             {
4463                 this.application.ValidateStateForLoad();
4464
4465                 this.application.SetPersistenceManager(this.persistenceManager);
4466                 if (!this.loadAny)
4467                 {
4468                     this.application.instanceId = this.persistenceManager.InstanceId;
4469                     this.application.instanceIdSet = true;
4470                 }
4471                 if (this.application.InstanceStore == null)
4472                 {
4473                     this.application.InstanceStore = this.persistenceManager.InstanceStore;
4474                 }
4475
4476                 return RegisterProvider();
4477             }
4478
4479             bool RegisterProvider()
4480             {
4481                 if (!this.persistenceManager.IsInitialized)
4482                 {
4483                     WorkflowIdentity definitionIdentity = this.application != null ? this.application.DefinitionIdentity : WorkflowApplication.unknownIdentity;
4484                     IAsyncResult result = this.persistenceManager.BeginInitialize(definitionIdentity, this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(providerRegisteredCallback), this);
4485                     return SyncContinue(result);
4486                 }
4487                 else
4488                 {
4489                     return Load();
4490                 }
4491             }
4492
4493             static bool OnProviderRegistered(IAsyncResult result)
4494             {
4495                 LoadAsyncResult thisPtr = (LoadAsyncResult)result.AsyncState;
4496                 thisPtr.persistenceManager.EndInitialize(result);
4497                 return thisPtr.Load();
4498             }
4499
4500             bool Load()
4501             {
4502                 bool success = false;
4503                 IAsyncResult result = null;
4504                 try
4505                 {
4506                     bool transactionRequired = this.application != null ? this.application.IsLoadTransactionRequired() : false;
4507                     this.context = new WorkflowPersistenceContext(transactionRequired,
4508                         this.dependentTransaction, this.timeoutHelper.OriginalTimeout);
4509
4510                     // Values is null if this is an initial load from the database.
4511                     // It is non-null if we already loaded values into a WorkflowApplicationInstance,
4512                     // and are now loading from that WAI.
4513                     if (this.values == null)
4514                     {
4515                         using (PrepareTransactionalCall(this.context.PublicTransaction))
4516                         {
4517                             if (this.loadAny)
4518                             {
4519                                 result = this.persistenceManager.BeginTryLoad(this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(loadCompleteCallback), this);
4520                             }
4521                             else
4522                             {
4523                                 result = this.persistenceManager.BeginLoad(this.timeoutHelper.RemainingTime(), PrepareAsyncCompletion(loadCompleteCallback), this);
4524                             }
4525                         }
4526                     }
4527                     success = true;
4528                 }
4529                 finally
4530                 {
4531                     if (!success && this.context != null)
4532                     {
4533                         this.context.Abort();
4534                     }
4535                 }
4536
4537                 if (result == null)
4538                 {
4539                     return LoadValues(null);
4540                 }
4541                 else
4542                 {
4543                     return SyncContinue(result);
4544                 }
4545             }
4546
4547             static bool OnLoadComplete(IAsyncResult result)
4548             {
4549                 LoadAsyncResult thisPtr = (LoadAsyncResult)result.AsyncState;
4550                 return thisPtr.LoadValues(result);
4551             }
4552
4553             bool LoadValues(IAsyncResult result)
4554             {
4555                 IAsyncResult loadResult = null;
4556                 bool success = false;
4557                 try
4558                 {
4559                     Fx.Assert((result == null) != (this.values == null), "We should either have values already retrieved, or an IAsyncResult to retrieve them");
4560
4561                     if (result != null)
4562                     {
4563                         if (this.loadAny)
4564                         {
4565                             if (!this.persistenceManager.EndTryLoad(result, out this.values))
4566                             {
4567                                 throw FxTrace.Exception.AsError(new InstanceNotReadyException(SR.NoRunnableInstances));
4568                             }
4569                             if (this.application != null)
4570                             {
4571                                 if (this.application.instanceIdSet)
4572                                 {
4573                                     throw FxTrace.Exception.AsError(new InvalidOperationException(SR.WorkflowApplicationAlreadyHasId));
4574                                 }
4575
4576                                 this.application.instanceId = this.persistenceManager.InstanceId;
4577                                 this.application.instanceIdSet = true;
4578                             }
4579                         }
4580                         else
4581                         {
4582                             this.values = this.persistenceManager.EndLoad(result);
4583                         }
4584                     }
4585
4586                     if (this.application != null)
4587                     {
4588                         this.pipeline = this.application.ProcessInstanceValues(this.values, out this.deserializedRuntimeState);
4589
4590                         if (this.pipeline != null)
4591                         {
4592                             this.pipeline.SetLoadedValues(this.values);
4593
4594                             this.application.persistencePipelineInUse = this.pipeline;
4595                             Thread.MemoryBarrier();
4596                             if (this.application.state == WorkflowApplicationState.Aborted)
4597                             {
4598                                 throw FxTrace.Exception.AsError(new OperationCanceledException(SR.DefaultAbortReason));
4599                             }
4600
4601                             using (this.PrepareTransactionalCall(this.context.PublicTransaction))
4602                             {
4603                                 loadResult = this.pipeline.BeginLoad(this.timeoutHelper.RemainingTime(), this.PrepareAsyncCompletion(loadPipelineCallback), this);
4604                             }
4605                         }
4606                     }
4607
4608                     success = true;
4609                 }
4610                 finally
4611                 {
4612                     if (!success)
4613                     {
4614                         this.context.Abort();
4615                     }
4616                 }
4617
4618                 if (this.pipeline != null)
4619                 {
4620                     return this.SyncContinue(loadResult);
4621                 }
4622                 else
4623                 {
4624                     return this.CompleteContext();
4625                 }
4626             }
4627
4628             static bool OnLoadPipeline(IAsyncResult result)
4629             {
4630                 LoadAsyncResult thisPtr = (LoadAsyncResult)result.AsyncState;
4631
4632                 bool success = false;
4633                 try
4634                 {
4635                     thisPtr.pipeline.EndLoad(result);
4636                     success = true;
4637                 }
4638                 finally
4639                 {
4640                     if (!success)
4641                     {
4642                         thisPtr.context.Abort();
4643                     }
4644                 }
4645                 return thisPtr.CompleteContext();
4646             }
4647
4648             bool CompleteContext()
4649             {
4650                 if (this.application != null)
4651                 {
4652                     this.application.Initialize(this.deserializedRuntimeState, this.updateMap);
4653                     if (this.updateMap != null)
4654                     {
4655                         this.application.UpdateInstanceMetadata();
4656                     }
4657                 }
4658
4659                 IAsyncResult completeResult;
4660                 if (this.context.TryBeginComplete(PrepareAsyncCompletion(completeContextCallback), this, out completeResult))
4661                 {
4662                     Fx.Assert(completeResult != null, "We shouldn't have null here.");
4663                     return SyncContinue(completeResult);
4664                 }
4665                 else
4666                 {
4667                     return Finish();
4668                 }
4669             }
4670
4671             static bool OnCompleteContext(IAsyncResult result)
4672             {
4673                 LoadAsyncResult thisPtr = (LoadAsyncResult)result.AsyncState;
4674                 thisPtr.context.EndComplete(result);
4675                 return thisPtr.Finish();
4676             }
4677
4678             bool Finish()
4679             {
4680                 if (this.pipeline != null)
4681                 {
4682                     this.pipeline.Publish();
4683                 }
4684                 return true;
4685             }
4686
4687             void NotifyOperationComplete()
4688             {
4689                 if (this.application != null)
4690                 {
4691                     InstanceOperation localInstanceOperation = this.instanceOperation;
4692                     this.instanceOperation = null;
4693                     this.application.NotifyOperationComplete(localInstanceOperation);
4694                 }
4695             }
4696
4697             static void OnComplete(AsyncResult result, Exception exception)
4698             {
4699                 LoadAsyncResult thisPtr = (LoadAsyncResult)result;
4700                 try
4701                 {
4702                     if (thisPtr.dependentTransaction != null)
4703                     {
4704                         thisPtr.dependentTransaction.Complete();
4705                     }
4706
4707                     if (exception != null)
4708                     {
4709                         Abort(thisPtr, exception);
4710                     }
4711                 }
4712                 finally
4713                 {
4714                     thisPtr.NotifyOperationComplete();
4715                 }
4716             }
4717
4718             static void Abort(LoadAsyncResult thisPtr, Exception exception)
4719             {
4720                 if (thisPtr.application == null)
4721                 {
4722                     thisPtr.persistenceManager.Abort();
4723                 }
4724                 else
4725                 {
4726                     thisPtr.application.AbortDueToException(exception);
4727                 }
4728             }
4729         }
4730
4731         // this class is not a general purpose SyncContext and is only meant to work for workflow scenarios, where the scheduler ensures 
4732         // at most one work item pending. The scheduler ensures that Invoke must run before Post is called on a different thread.
4733         class PumpBasedSynchronizationContext : SynchronizationContext
4734         {
4735             // The waitObject is cached per thread so that we can avoid the cost of creating
4736             // events for multiple synchronous invokes.
4737             [ThreadStatic]
4738             static AutoResetEvent waitObject;
4739             AutoResetEvent queueWaiter;
4740             WorkItem currentWorkItem;
4741             object thisLock;
4742             TimeoutHelper timeoutHelper;
4743
4744             public PumpBasedSynchronizationContext(TimeSpan timeout)
4745             {
4746                 this.timeoutHelper = new TimeoutHelper(timeout);
4747                 this.thisLock = new object();
4748             }
4749
4750             bool IsInvokeCompleted
4751             {
4752                 get;
4753                 set;
4754             }
4755
4756             public void DoPump()
4757             {
4758                 Fx.Assert(this.currentWorkItem != null, "the work item cannot be null");
4759                 WorkItem workItem;
4760
4761                 lock (this.thisLock)
4762                 {
4763                     if (PumpBasedSynchronizationContext.waitObject == null)
4764                     {
4765                         PumpBasedSynchronizationContext.waitObject = new AutoResetEvent(false);
4766                     }
4767                     this.queueWaiter = PumpBasedSynchronizationContext.waitObject;
4768
4769                     workItem = this.currentWorkItem;
4770                     this.currentWorkItem = null;
4771                     workItem.Invoke();
4772                 }
4773
4774                 Fx.Assert(this.queueWaiter != null, "queue waiter cannot be null");
4775
4776                 while (this.WaitForNextItem())
4777                 {
4778                     Fx.Assert(this.currentWorkItem != null, "the work item cannot be null");
4779                     workItem = this.currentWorkItem;
4780                     this.currentWorkItem = null;
4781                     workItem.Invoke();
4782                 }
4783             }
4784
4785             public override void Post(SendOrPostCallback d, object state)
4786             {
4787                 ScheduleWorkItem(new WorkItem(d, state));
4788             }
4789
4790             public override void Send(SendOrPostCallback d, object state)
4791             {
4792                 throw FxTrace.Exception.AsError(new NotSupportedException(SR.SendNotSupported));
4793             }
4794
4795             // Since tracking can go async this may or may not be called directly
4796             // under a call to workItem.Invoke.  Also, the scheduler may call
4797             // OnNotifyPaused or OnNotifyUnhandledException from any random thread
4798             // if runtime goes async (post-work item tracking, AsyncCodeActivity).
4799             public void OnInvokeCompleted()
4800             {
4801                 Fx.AssertAndFailFast(this.currentWorkItem == null, "There can be no pending work items when complete");
4802
4803                 this.IsInvokeCompleted = true;
4804
4805                 lock (this.thisLock)
4806                 {
4807                     if (this.queueWaiter != null)
4808                     {
4809                         // Since we don't know which thread this is being called
4810                         // from we just set the waiter directly rather than
4811                         // doing our SetWaiter cleanup.
4812                         this.queueWaiter.Set();
4813                     }
4814                 }
4815             }
4816
4817             void ScheduleWorkItem(WorkItem item)
4818             {
4819                 lock (this.thisLock)
4820                 {
4821                     Fx.AssertAndFailFast(this.currentWorkItem == null, "There cannot be more than 1 work item at a given time");
4822                     this.currentWorkItem = item;
4823                     if (this.queueWaiter != null)
4824                     {
4825                         // Since we don't know which thread this is being called
4826                         // from we just set the waiter directly rather than
4827                         // doing our SetWaiter cleanup.
4828                         this.queueWaiter.Set();
4829                     }
4830                 }
4831             }
4832
4833             bool WaitOne(AutoResetEvent waiter, TimeSpan timeout)
4834             {
4835                 bool success = false;
4836                 try
4837                 {
4838                     bool result = TimeoutHelper.WaitOne(waiter, timeout);
4839                     // if the wait timed out, reset the thread static
4840                     success = result;
4841                     return result;
4842                 }
4843                 finally
4844                 {
4845                     if (!success)
4846                     {
4847                         PumpBasedSynchronizationContext.waitObject = null;
4848                     }
4849                 }
4850             }
4851
4852             bool WaitForNextItem()
4853             {
4854                 if (!WaitOne(this.queueWaiter, timeoutHelper.RemainingTime()))
4855                 {
4856                     throw FxTrace.Exception.AsError(new TimeoutException(SR.TimeoutOnOperation(timeoutHelper.OriginalTimeout)));
4857                 }
4858
4859                 // We need to check this after the wait as well in 
4860                 // case the notification came in asynchronously
4861                 if (this.IsInvokeCompleted)
4862                 {
4863                     return false;
4864                 }
4865
4866                 return true;
4867             }
4868
4869             class WorkItem
4870             {
4871                 SendOrPostCallback callback;
4872                 object state;
4873
4874                 public WorkItem(SendOrPostCallback callback, object state)
4875                 {
4876                     this.callback = callback;
4877                     this.state = state;
4878                 }
4879
4880                 public void Invoke()
4881                 {
4882                     this.callback(this.state);
4883                 }
4884             }
4885         }
4886
4887         class WorkflowEventData
4888         {
4889             public WorkflowEventData(WorkflowApplication instance)
4890             {
4891                 this.Instance = instance;
4892             }
4893
4894             public WorkflowApplication Instance
4895             {
4896                 get;
4897                 private set;
4898             }
4899
4900             public Func<IAsyncResult, WorkflowApplication, bool, bool> NextCallback
4901             {
4902                 get;
4903                 set;
4904             }
4905
4906             public Exception UnhandledException
4907             {
4908                 get;
4909                 set;
4910             }
4911
4912             public Activity UnhandledExceptionSource
4913             {
4914                 get;
4915                 set;
4916             }
4917
4918             public string UnhandledExceptionSourceInstance
4919             {
4920                 get;
4921                 set;
4922             }
4923         }
4924
4925         class IdleEventHandler
4926         {
4927             Func<IAsyncResult, WorkflowApplication, bool, bool> stage1Callback;
4928             Func<IAsyncResult, WorkflowApplication, bool, bool> stage2Callback;
4929
4930             public IdleEventHandler()
4931             {
4932             }
4933
4934             Func<IAsyncResult, WorkflowApplication, bool, bool> Stage1Callback
4935             {
4936                 get
4937                 {
4938                     if (this.stage1Callback == null)
4939                     {
4940                         this.stage1Callback = new Func<IAsyncResult, WorkflowApplication, bool, bool>(OnStage1Complete);
4941                     }
4942
4943                     return this.stage1Callback;
4944                 }
4945             }
4946
4947             Func<IAsyncResult, WorkflowApplication, bool, bool> Stage2Callback
4948             {
4949                 get
4950                 {
4951                     if (this.stage2Callback == null)
4952                     {
4953                         this.stage2Callback = new Func<IAsyncResult, WorkflowApplication, bool, bool>(OnStage2Complete);
4954                     }
4955
4956                     return this.stage2Callback;
4957                 }
4958             }
4959
4960             public bool Run(WorkflowApplication instance)
4961             {
4962                 IAsyncResult result = null;
4963
4964                 if (instance.Controller.TrackingEnabled)
4965                 {
4966                     instance.Controller.Track(new WorkflowInstanceRecord(instance.Id, instance.WorkflowDefinition.DisplayName, WorkflowInstanceStates.Idle, instance.DefinitionIdentity));
4967
4968                     instance.EventData.NextCallback = this.Stage1Callback;
4969                     result = instance.Controller.BeginFlushTrackingRecords(ActivityDefaults.TrackingTimeout, EventFrameCallback, instance.EventData);
4970
4971                     if (!result.CompletedSynchronously)
4972                     {
4973                         return false;
4974                     }
4975                 }
4976
4977                 return OnStage1Complete(result, instance, true);
4978             }
4979
4980             bool OnStage1Complete(IAsyncResult lastResult, WorkflowApplication application, bool isStillSync)
4981             {
4982                 if (lastResult != null)
4983                 {
4984                     application.Controller.EndFlushTrackingRecords(lastResult);
4985                 }
4986
4987                 IAsyncResult result = null;
4988
4989                 if (application.RaiseIdleEvent())
4990                 {
4991                     if (application.Controller.IsPersistable && application.persistenceManager != null)
4992                     {
4993                         Func<WorkflowApplicationIdleEventArgs, PersistableIdleAction> persistableIdleHandler = application.PersistableIdle;
4994
4995                         if (persistableIdleHandler != null)
4996                         {
4997                             PersistableIdleAction action = PersistableIdleAction.None;
4998
4999                             application.handlerThreadId = Thread.CurrentThread.ManagedThreadId;
5000
5001                             try
5002                             {
5003                                 application.isInHandler = true;
5004                                 action = persistableIdleHandler(new WorkflowApplicationIdleEventArgs(application));
5005                             }
5006                             finally
5007                             {
5008                                 application.isInHandler = false;
5009                             }
5010
5011                             if (TD.WorkflowApplicationPersistableIdleIsEnabled())
5012                             {
5013                                 TD.WorkflowApplicationPersistableIdle(application.Id.ToString(), action.ToString());
5014                             }
5015
5016                             if (action != PersistableIdleAction.None)
5017                             {
5018                                 PersistenceOperation operation = PersistenceOperation.Unload;
5019
5020                                 if (action == PersistableIdleAction.Persist)
5021                                 {
5022                                     operation = PersistenceOperation.Save;
5023                                 }
5024                                 else if (action != PersistableIdleAction.Unload)
5025                                 {
5026                                     throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidIdleAction));
5027                                 }
5028
5029                                 application.EventData.NextCallback = this.Stage2Callback;
5030                                 result = application.BeginInternalPersist(operation, ActivityDefaults.InternalSaveTimeout, true, EventFrameCallback, application.EventData);
5031
5032                                 if (!result.CompletedSynchronously)
5033                                 {
5034                                     return false;
5035                                 }
5036                             }
5037                         }
5038                         else
5039                         {
5040                             // Trace the default action
5041                             if (TD.WorkflowApplicationPersistableIdleIsEnabled())
5042                             {
5043                                 TD.WorkflowApplicationPersistableIdle(application.Id.ToString(), PersistableIdleAction.None.ToString());
5044                             }
5045                         }
5046                     }
5047                 }
5048
5049                 return OnStage2Complete(result, application, isStillSync);
5050             }
5051
5052             bool OnStage2Complete(IAsyncResult lastResult, WorkflowApplication instance, bool isStillSync)
5053             {
5054                 if (lastResult != null)
5055                 {
5056                     instance.EndInternalPersist(lastResult);
5057                 }
5058
5059                 return true;
5060             }
5061         }
5062
5063         class CompletedEventHandler
5064         {
5065             Func<IAsyncResult, WorkflowApplication, bool, bool> stage1Callback;
5066             Func<IAsyncResult, WorkflowApplication, bool, bool> stage2Callback;
5067
5068             public CompletedEventHandler()
5069             {
5070             }
5071
5072             Func<IAsyncResult, WorkflowApplication, bool, bool> Stage1Callback
5073             {
5074                 get
5075                 {
5076                     if (this.stage1Callback == null)
5077                     {
5078                         this.stage1Callback = new Func<IAsyncResult, WorkflowApplication, bool, bool>(OnStage1Complete);
5079                     }
5080
5081                     return this.stage1Callback;
5082                 }
5083             }
5084
5085             Func<IAsyncResult, WorkflowApplication, bool, bool> Stage2Callback
5086             {
5087                 get
5088                 {
5089                     if (this.stage2Callback == null)
5090                     {
5091                         this.stage2Callback = new Func<IAsyncResult, WorkflowApplication, bool, bool>(OnStage2Complete);
5092                     }
5093
5094                     return this.stage2Callback;
5095                 }
5096             }
5097
5098             public bool Run(WorkflowApplication instance)
5099             {
5100                 IAsyncResult result = null;
5101                 if (instance.Controller.HasPendingTrackingRecords)
5102                 {
5103                     instance.EventData.NextCallback = this.Stage1Callback;
5104                     result = instance.Controller.BeginFlushTrackingRecords(ActivityDefaults.TrackingTimeout, EventFrameCallback, instance.EventData);
5105
5106                     if (!result.CompletedSynchronously)
5107                     {
5108                         return false;
5109                     }
5110                 }
5111
5112                 return OnStage1Complete(result, instance, true);
5113             }
5114
5115             bool OnStage1Complete(IAsyncResult lastResult, WorkflowApplication instance, bool isStillSync)
5116             {
5117                 if (lastResult != null)
5118                 {
5119                     instance.Controller.EndFlushTrackingRecords(lastResult);
5120                 }
5121
5122                 IDictionary<string, object> outputs;
5123                 Exception completionException;
5124                 ActivityInstanceState completionState = instance.Controller.GetCompletionState(out outputs, out completionException);
5125
5126                 if (instance.invokeCompletedCallback == null)
5127                 {
5128                     Action<WorkflowApplicationCompletedEventArgs> handler = instance.Completed;
5129
5130                     if (handler != null)
5131                     {
5132                         instance.handlerThreadId = Thread.CurrentThread.ManagedThreadId;
5133
5134                         try
5135                         {
5136                             instance.isInHandler = true;
5137                             handler(new WorkflowApplicationCompletedEventArgs(instance, completionException, completionState, outputs));
5138                         }
5139                         finally
5140                         {
5141                             instance.isInHandler = false;
5142                         }
5143                     }
5144                 }
5145
5146                 switch (completionState)
5147                 {
5148                     case ActivityInstanceState.Closed:
5149                         if (TD.WorkflowApplicationCompletedIsEnabled())
5150                         {
5151                             TD.WorkflowApplicationCompleted(instance.Id.ToString());
5152                         }
5153                         break;
5154                     case ActivityInstanceState.Canceled:
5155                         if (TD.WorkflowInstanceCanceledIsEnabled())
5156                         {
5157                             TD.WorkflowInstanceCanceled(instance.Id.ToString());
5158                         }
5159                         break;
5160                     case ActivityInstanceState.Faulted:
5161                         if (TD.WorkflowApplicationTerminatedIsEnabled())
5162                         {
5163                             TD.WorkflowApplicationTerminated(instance.Id.ToString(), completionException);
5164                         }
5165                         break;
5166                 }
5167
5168                 IAsyncResult result = null;
5169                 Fx.Assert(instance.Controller.IsPersistable, "Should not be in a No Persist Zone once the instance is complete.");
5170                 if (instance.persistenceManager != null || instance.HasPersistenceModule)
5171                 {
5172                     instance.EventData.NextCallback = this.Stage2Callback;
5173                     result = instance.BeginInternalPersist(PersistenceOperation.Unload, ActivityDefaults.InternalSaveTimeout, true, EventFrameCallback, instance.EventData);
5174
5175                     if (!result.CompletedSynchronously)
5176                     {
5177                         return false;
5178                     }
5179                 }
5180                 else
5181                 {
5182                     instance.MarkUnloaded();
5183                 }
5184
5185                 return OnStage2Complete(result, instance, isStillSync);
5186             }
5187
5188             bool OnStage2Complete(IAsyncResult lastResult, WorkflowApplication instance, bool isStillSync)
5189             {
5190                 if (lastResult != null)
5191                 {
5192                     instance.EndInternalPersist(lastResult);
5193                 }
5194
5195                 if (instance.invokeCompletedCallback != null)
5196                 {
5197                     instance.invokeCompletedCallback();
5198                 }
5199
5200                 return true;
5201             }
5202         }
5203
5204         class UnhandledExceptionEventHandler
5205         {
5206             Func<IAsyncResult, WorkflowApplication, bool, bool> stage1Callback;
5207
5208             public UnhandledExceptionEventHandler()
5209             {
5210             }
5211
5212             Func<IAsyncResult, WorkflowApplication, bool, bool> Stage1Callback
5213             {
5214                 get
5215                 {
5216                     if (this.stage1Callback == null)
5217                     {
5218                         this.stage1Callback = new Func<IAsyncResult, WorkflowApplication, bool, bool>(OnStage1Complete);
5219                     }
5220
5221                     return this.stage1Callback;
5222                 }
5223             }
5224
5225             public bool Run(WorkflowApplication instance, Exception exception, Activity exceptionSource, string exceptionSourceInstanceId)
5226             {
5227                 IAsyncResult result = null;
5228
5229                 if (instance.Controller.HasPendingTrackingRecords)
5230                 {
5231                     instance.EventData.NextCallback = this.Stage1Callback;
5232                     instance.EventData.UnhandledException = exception;
5233                     instance.EventData.UnhandledExceptionSource = exceptionSource;
5234                     instance.EventData.UnhandledExceptionSourceInstance = exceptionSourceInstanceId;
5235                     result = instance.Controller.BeginFlushTrackingRecords(ActivityDefaults.TrackingTimeout, EventFrameCallback, instance.EventData);
5236
5237                     if (!result.CompletedSynchronously)
5238                     {
5239                         return false;
5240                     }
5241                 }
5242
5243                 return OnStage1Complete(result, instance, exception, exceptionSource, exceptionSourceInstanceId);
5244             }
5245
5246             bool OnStage1Complete(IAsyncResult lastResult, WorkflowApplication instance, bool isStillSync)
5247             {
5248                 return OnStage1Complete(lastResult, instance, instance.EventData.UnhandledException, instance.EventData.UnhandledExceptionSource, instance.EventData.UnhandledExceptionSourceInstance);
5249             }
5250
5251             bool OnStage1Complete(IAsyncResult lastResult, WorkflowApplication instance, Exception exception, Activity source, string sourceInstanceId)
5252             {
5253                 if (lastResult != null)
5254                 {
5255                     instance.Controller.EndFlushTrackingRecords(lastResult);
5256                 }
5257
5258                 Func<WorkflowApplicationUnhandledExceptionEventArgs, UnhandledExceptionAction> handler = instance.OnUnhandledException;
5259
5260                 UnhandledExceptionAction action = UnhandledExceptionAction.Terminate;
5261
5262                 if (handler != null)
5263                 {
5264                     try
5265                     {
5266                         instance.isInHandler = true;
5267                         instance.handlerThreadId = Thread.CurrentThread.ManagedThreadId;
5268
5269                         action = handler(new WorkflowApplicationUnhandledExceptionEventArgs(instance, exception, source, sourceInstanceId));
5270                     }
5271                     finally
5272                     {
5273                         instance.isInHandler = false;
5274                     }
5275                 }
5276
5277                 if (instance.invokeCompletedCallback != null)
5278                 {
5279                     action = UnhandledExceptionAction.Terminate;
5280                 }
5281
5282                 if (TD.WorkflowApplicationUnhandledExceptionIsEnabled())
5283                 {
5284                     TD.WorkflowApplicationUnhandledException(instance.Id.ToString(), source.GetType().ToString(), source.DisplayName, action.ToString(), exception);
5285                 }
5286
5287                 switch (action)
5288                 {
5289                     case UnhandledExceptionAction.Abort:
5290                         instance.AbortInstance(exception, true);
5291                         break;
5292                     case UnhandledExceptionAction.Cancel:
5293                         instance.Controller.ScheduleCancel();
5294                         break;
5295                     case UnhandledExceptionAction.Terminate:
5296                         instance.TerminateCore(exception);
5297                         break;
5298                     default:
5299                         throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidUnhandledExceptionAction));
5300                 }
5301
5302                 return true;
5303             }
5304         }
5305
5306         class InstanceCommandWithTemporaryHandleAsyncResult : TransactedAsyncResult
5307         {
5308             static AsyncCompletion commandCompletedCallback = new AsyncCompletion(OnCommandCompleted);
5309             static Action<AsyncResult, Exception> completeCallback = new Action<AsyncResult, Exception>(OnComplete);
5310
5311             InstancePersistenceCommand command;
5312             DependentTransaction dependentTransaction;
5313             InstanceStore instanceStore;
5314             InstanceHandle temporaryHandle;
5315             InstanceView commandResult;
5316
5317             public InstanceCommandWithTemporaryHandleAsyncResult(InstanceStore instanceStore, InstancePersistenceCommand command,
5318                 TimeSpan timeout, AsyncCallback callback, object state)
5319                 : base(callback, state)
5320             {
5321                 this.instanceStore = instanceStore;
5322                 this.command = command;
5323                 this.temporaryHandle = instanceStore.CreateInstanceHandle();
5324
5325                 Transaction currentTransaction = Transaction.Current;
5326                 if (currentTransaction != null)
5327                 {
5328                     this.dependentTransaction = currentTransaction.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
5329                 }
5330
5331                 OnCompleting = completeCallback;
5332
5333                 IAsyncResult result;
5334                 using (this.PrepareTransactionalCall(this.dependentTransaction))
5335                 {
5336                     result = instanceStore.BeginExecute(this.temporaryHandle, command, timeout, PrepareAsyncCompletion(commandCompletedCallback), this);
5337                 }
5338
5339                 if (SyncContinue(result))
5340                 {
5341                     Complete(true);
5342                 }
5343             }
5344
5345             public static void End(IAsyncResult result, out InstanceStore instanceStore, out InstanceView commandResult)
5346             {
5347                 InstanceCommandWithTemporaryHandleAsyncResult thisPtr = AsyncResult.End<InstanceCommandWithTemporaryHandleAsyncResult>(result);
5348                 instanceStore = thisPtr.instanceStore;
5349                 commandResult = thisPtr.commandResult;
5350             }
5351
5352             static bool OnCommandCompleted(IAsyncResult result)
5353             {
5354                 InstanceCommandWithTemporaryHandleAsyncResult thisPtr = (InstanceCommandWithTemporaryHandleAsyncResult)result.AsyncState;
5355                 thisPtr.commandResult = thisPtr.instanceStore.EndExecute(result);
5356                 return true;
5357             }
5358
5359             static void OnComplete(AsyncResult result, Exception exception)
5360             {
5361                 InstanceCommandWithTemporaryHandleAsyncResult thisPtr = (InstanceCommandWithTemporaryHandleAsyncResult)result;
5362                 if (thisPtr.dependentTransaction != null)
5363                 {
5364                     thisPtr.dependentTransaction.Complete();
5365                 }
5366                 thisPtr.temporaryHandle.Free();
5367             }
5368         }
5369
5370         class InstanceOperation
5371         {
5372             AsyncWaitHandle waitHandle;
5373
5374             public InstanceOperation()
5375             {
5376                 this.InterruptsScheduler = true;
5377                 this.RequiresInitialized = true;
5378             }
5379
5380             public bool Notified
5381             {
5382                 get;
5383                 set;
5384             }
5385
5386             public int ActionId
5387             {
5388                 get;
5389                 set;
5390             }
5391
5392             public bool InterruptsScheduler
5393             {
5394                 get;
5395                 protected set;
5396             }
5397
5398             public bool RequiresInitialized
5399             {
5400                 get;
5401                 set;
5402             }
5403
5404             public void OnEnqueued()
5405             {
5406                 this.waitHandle = new AsyncWaitHandle();
5407             }
5408
5409             public virtual bool CanRun(WorkflowApplication instance)
5410             {
5411                 return true;
5412             }
5413
5414             public void NotifyTurn()
5415             {
5416                 Fx.Assert(this.waitHandle != null, "We must have a wait handle.");
5417
5418                 waitHandle.Set();
5419             }
5420
5421             public bool WaitForTurn(TimeSpan timeout)
5422             {
5423                 if (this.waitHandle != null)
5424                 {
5425                     return this.waitHandle.Wait(timeout);
5426                 }
5427
5428                 return true;
5429             }
5430
5431             public bool WaitForTurnAsync(TimeSpan timeout, Action<object, TimeoutException> callback, object state)
5432             {
5433                 if (this.waitHandle != null)
5434                 {
5435                     return this.waitHandle.WaitAsync(callback, state, timeout);
5436                 }
5437
5438                 return true;
5439             }
5440         }
5441
5442         class RequiresIdleOperation : InstanceOperation
5443         {
5444             bool requiresRunnableInstance;
5445
5446             public RequiresIdleOperation()
5447                 : this(false)
5448             {
5449             }
5450
5451             public RequiresIdleOperation(bool requiresRunnableInstance)
5452             {
5453                 this.InterruptsScheduler = false;
5454                 this.requiresRunnableInstance = requiresRunnableInstance;
5455             }
5456
5457             public override bool CanRun(WorkflowApplication instance)
5458             {
5459                 if (requiresRunnableInstance && instance.state != WorkflowApplicationState.Runnable)
5460                 {
5461                     return false;
5462                 }
5463
5464                 return instance.Controller.State == WorkflowInstanceState.Idle || instance.Controller.State == WorkflowInstanceState.Complete;
5465             }
5466         }
5467
5468         class DeferredRequiresIdleOperation : InstanceOperation
5469         {
5470             public DeferredRequiresIdleOperation()
5471             {
5472                 this.InterruptsScheduler = false;
5473             }
5474
5475             public override bool CanRun(WorkflowApplication instance)
5476             {
5477                 return (this.ActionId != instance.actionCount && instance.Controller.State == WorkflowInstanceState.Idle) || instance.Controller.State == WorkflowInstanceState.Complete;
5478             }
5479         }
5480
5481         class RequiresPersistenceOperation : InstanceOperation
5482         {
5483             public override bool CanRun(WorkflowApplication instance)
5484             {
5485                 if (!instance.Controller.IsPersistable && instance.Controller.State != WorkflowInstanceState.Complete)
5486                 {
5487                     instance.Controller.PauseWhenPersistable();
5488                     return false;
5489                 }
5490                 else
5491                 {
5492                     return true;
5493                 }
5494             }
5495         }
5496
5497         class WaitForTurnData
5498         {
5499             public WaitForTurnData(Action<object, TimeoutException> callback, object state, InstanceOperation operation, WorkflowApplication instance)
5500             {
5501                 this.Callback = callback;
5502                 this.State = state;
5503                 this.Operation = operation;
5504                 this.Instance = instance;
5505             }
5506
5507             public Action<object, TimeoutException> Callback
5508             {
5509                 get;
5510                 private set;
5511             }
5512
5513             public object State
5514             {
5515                 get;
5516                 private set;
5517             }
5518
5519             public InstanceOperation Operation
5520             {
5521                 get;
5522                 private set;
5523             }
5524
5525             public WorkflowApplication Instance
5526             {
5527                 get;
5528                 private set;
5529             }
5530         }
5531
5532         // This is a thin shell of PersistenceManager functionality so that WorkflowApplicationInstance
5533         // can hold onto a PM without exposing the entire persistence functionality
5534         internal abstract class PersistenceManagerBase
5535         {
5536             public abstract InstanceStore InstanceStore { get; }
5537             public abstract Guid InstanceId { get; }
5538         }
5539
5540         class PersistenceManager : PersistenceManagerBase
5541         {
5542             InstanceHandle handle;
5543             InstanceHandle temporaryHandle;
5544             InstanceOwner owner;
5545             bool ownerWasCreated;
5546             bool isLocked;
5547             bool aborted;
5548             bool isTryLoad;
5549             Guid instanceId;
5550             InstanceStore store;
5551             // Initializing metadata, used when instance is created
5552             IDictionary<XName, InstanceValue> instanceMetadata;
5553             // Updateable metadata, used when instance is saved
5554             IDictionary<XName, InstanceValue> mutableMetadata;
5555
5556             public PersistenceManager(InstanceStore store, IDictionary<XName, InstanceValue> instanceMetadata, Guid instanceId)
5557             {
5558                 Fx.Assert(store != null, "We should never gets here without a store.");
5559
5560                 this.instanceId = instanceId;
5561                 this.instanceMetadata = instanceMetadata;
5562
5563                 InitializeInstanceMetadata();
5564
5565                 this.owner = store.DefaultInstanceOwner;
5566                 if (this.owner != null)
5567                 {
5568                     this.handle = store.CreateInstanceHandle(this.owner, instanceId);
5569                 }
5570
5571                 this.store = store;
5572             }
5573
5574             public PersistenceManager(InstanceStore store, IDictionary<XName, InstanceValue> instanceMetadata)
5575             {
5576                 Fx.Assert(store != null, "We should never get here without a store.");
5577
5578                 this.isTryLoad = true;
5579                 this.instanceMetadata = instanceMetadata;
5580
5581                 InitializeInstanceMetadata();
5582
5583                 this.owner = store.DefaultInstanceOwner;
5584                 if (this.owner != null)
5585                 {
5586                     this.handle = store.CreateInstanceHandle(this.owner);
5587                 }
5588
5589                 this.store = store;
5590             }
5591
5592             public sealed override Guid InstanceId
5593             {
5594                 get
5595                 {
5596                     return this.instanceId;
5597                 }
5598             }
5599
5600             public sealed override InstanceStore InstanceStore
5601             {
5602                 get
5603                 {
5604                     return this.store;
5605                 }
5606             }
5607
5608             public bool IsInitialized
5609             {
5610                 get
5611                 {
5612                     return (this.handle != null);
5613                 }
5614             }
5615
5616             public bool IsLocked
5617             {
5618                 get
5619                 {
5620                     return this.isLocked;
5621                 }
5622             }
5623
5624             public bool OwnerWasCreated
5625             {
5626                 get
5627                 {
5628                     return this.ownerWasCreated;
5629                 }
5630             }
5631
5632             void InitializeInstanceMetadata()
5633             {
5634                 if (this.instanceMetadata == null)
5635                 {
5636                     this.instanceMetadata = new Dictionary<XName, InstanceValue>(1);
5637                 }
5638
5639                 // We always set this key explicitly so that users can't override
5640                 // this metadata value
5641                 this.instanceMetadata[PersistenceMetadataNamespace.InstanceType] = new InstanceValue(WorkflowNamespace.WorkflowHostType, InstanceValueOptions.WriteOnly);
5642             }
5643
5644             public void SetInstanceMetadata(IDictionary<XName, InstanceValue> metadata)
5645             {
5646                 Fx.Assert(this.instanceMetadata.Count == 1, "We should only have the default metadata from InitializeInstanceMetadata");
5647                 if (metadata != null)
5648                 {
5649                     this.instanceMetadata = metadata;
5650                     InitializeInstanceMetadata();
5651                 }
5652             }
5653
5654             public void SetMutablemetadata(IDictionary<XName, InstanceValue> metadata)
5655             {
5656                 this.mutableMetadata = metadata;
5657             }
5658
5659             public void Initialize(WorkflowIdentity definitionIdentity, TimeSpan timeout)
5660             {
5661                 Fx.Assert(this.handle == null, "We are already initialized by now");
5662
5663                 using (new TransactionScope(TransactionScopeOption.Suppress))
5664                 {
5665                     try
5666                     {
5667                         CreateTemporaryHandle(null);
5668                         this.owner = this.store.Execute(this.temporaryHandle, GetCreateOwnerCommand(definitionIdentity), timeout).InstanceOwner;
5669                         this.ownerWasCreated = true;
5670                     }
5671                     finally
5672                     {
5673                         FreeTemporaryHandle();
5674                     }
5675
5676                     this.handle = this.isTryLoad ? this.store.CreateInstanceHandle(this.owner) : this.store.CreateInstanceHandle(this.owner, InstanceId);
5677
5678                     Thread.MemoryBarrier();
5679                     if (this.aborted)
5680                     {
5681                         this.handle.Free();
5682                     }
5683                 }
5684             }
5685
5686             void CreateTemporaryHandle(InstanceOwner owner)
5687             {
5688                 this.temporaryHandle = this.store.CreateInstanceHandle(owner);
5689
5690                 Thread.MemoryBarrier();
5691
5692                 if (this.aborted)
5693                 {
5694                     FreeTemporaryHandle();
5695                 }
5696             }
5697
5698             void FreeTemporaryHandle()
5699             {
5700                 InstanceHandle handle = this.temporaryHandle;
5701
5702                 if (handle != null)
5703                 {
5704                     handle.Free();
5705                 }
5706             }
5707
5708             public IAsyncResult BeginInitialize(WorkflowIdentity definitionIdentity, TimeSpan timeout, AsyncCallback callback, object state)
5709             {
5710                 Fx.Assert(this.handle == null, "We are already initialized by now");
5711
5712                 using (new TransactionScope(TransactionScopeOption.Suppress))
5713                 {
5714                     IAsyncResult result = null;
5715
5716                     try
5717                     {
5718                         CreateTemporaryHandle(null);
5719                         result = this.store.BeginExecute(this.temporaryHandle, GetCreateOwnerCommand(definitionIdentity), timeout, callback, state);
5720                     }
5721                     finally
5722                     {
5723                         // We've encountered an exception
5724                         if (result == null)
5725                         {
5726                             FreeTemporaryHandle();
5727                         }
5728                     }
5729                     return result;
5730                 }
5731             }
5732
5733             public void EndInitialize(IAsyncResult result)
5734             {
5735                 try
5736                 {
5737                     this.owner = this.store.EndExecute(result).InstanceOwner;
5738                     this.ownerWasCreated = true;
5739                 }
5740                 finally
5741                 {
5742                     FreeTemporaryHandle();
5743                 }
5744
5745                 this.handle = this.isTryLoad ? this.store.CreateInstanceHandle(this.owner) : this.store.CreateInstanceHandle(this.owner, InstanceId);
5746                 Thread.MemoryBarrier();
5747                 if (this.aborted)
5748                 {
5749                     this.handle.Free();
5750                 }
5751             }
5752
5753             public void DeleteOwner(TimeSpan timeout)
5754             {
5755                 try
5756                 {
5757                     CreateTemporaryHandle(this.owner);
5758                     this.store.Execute(this.temporaryHandle, new DeleteWorkflowOwnerCommand(), timeout);
5759                 }
5760                 // Ignore some exceptions because DeleteWorkflowOwner is best effort.
5761                 catch (InstancePersistenceCommandException) { }
5762                 catch (InstanceOwnerException) { }
5763                 catch (OperationCanceledException) { }
5764                 finally
5765                 {
5766                     FreeTemporaryHandle();
5767                 }
5768             }
5769
5770             public IAsyncResult BeginDeleteOwner(TimeSpan timeout, AsyncCallback callback, object state)
5771             {
5772                 IAsyncResult result = null;
5773                 try
5774                 {
5775                     CreateTemporaryHandle(this.owner);
5776                     result = this.store.BeginExecute(this.temporaryHandle, new DeleteWorkflowOwnerCommand(), timeout, callback, state);
5777                 }
5778                 // Ignore some exceptions because DeleteWorkflowOwner is best effort.
5779                 catch (InstancePersistenceCommandException) { }
5780                 catch (InstanceOwnerException) { }
5781                 catch (OperationCanceledException) { }
5782                 finally
5783                 {
5784                     if (result == null)
5785                     {
5786                         FreeTemporaryHandle();
5787                     }
5788                 }
5789                 return result;
5790             }
5791
5792             public void EndDeleteOwner(IAsyncResult result)
5793             {
5794                 try
5795                 {
5796                     this.store.EndExecute(result);
5797                 }
5798                 // Ignore some exceptions because DeleteWorkflowOwner is best effort.
5799                 catch (InstancePersistenceCommandException) { }
5800                 catch (InstanceOwnerException) { }
5801                 catch (OperationCanceledException) { }
5802                 finally
5803                 {
5804                     FreeTemporaryHandle();
5805                 }
5806             }
5807
5808             public void EnsureReadyness(TimeSpan timeout)
5809             {
5810                 Fx.Assert(this.handle != null, "We should already be initialized by now");
5811                 Fx.Assert(!IsLocked, "We are already ready for persistence; why are we being called?");
5812                 Fx.Assert(!this.isTryLoad, "Should not be on an initial save path if we tried load.");
5813
5814                 using (new TransactionScope(TransactionScopeOption.Suppress))
5815                 {
5816                     this.store.Execute(this.handle, CreateSaveCommand(null, this.instanceMetadata, PersistenceOperation.Save), timeout);
5817                     this.isLocked = true;
5818                 }
5819             }
5820
5821             public IAsyncResult BeginEnsureReadyness(TimeSpan timeout, AsyncCallback callback, object state)
5822             {
5823                 Fx.Assert(this.handle != null, "We should already be initialized by now");
5824                 Fx.Assert(!IsLocked, "We are already ready for persistence; why are we being called?");
5825                 Fx.Assert(!this.isTryLoad, "Should not be on an initial save path if we tried load.");
5826
5827                 using (new TransactionScope(TransactionScopeOption.Suppress))
5828                 {
5829                     return this.store.BeginExecute(this.handle, CreateSaveCommand(null, this.instanceMetadata, PersistenceOperation.Save), timeout, callback, state);
5830                 }
5831             }
5832
5833             public void EndEnsureReadyness(IAsyncResult result)
5834             {
5835                 this.store.EndExecute(result);
5836                 this.isLocked = true;
5837             }
5838
5839             public static Dictionary<XName, InstanceValue> GenerateInitialData(WorkflowApplication instance)
5840             {
5841                 Dictionary<XName, InstanceValue> data = new Dictionary<XName, InstanceValue>(10);
5842                 data[WorkflowNamespace.Bookmarks] = new InstanceValue(instance.Controller.GetBookmarks(), InstanceValueOptions.WriteOnly | InstanceValueOptions.Optional);
5843                 data[WorkflowNamespace.LastUpdate] = new InstanceValue(DateTime.UtcNow, InstanceValueOptions.WriteOnly | InstanceValueOptions.Optional);
5844
5845                 foreach (KeyValuePair<string, LocationInfo> mappedVariable in instance.Controller.GetMappedVariables())
5846                 {
5847                     data[WorkflowNamespace.VariablesPath.GetName(mappedVariable.Key)] = new InstanceValue(mappedVariable.Value, InstanceValueOptions.WriteOnly | InstanceValueOptions.Optional);
5848                 }
5849
5850                 Fx.AssertAndThrow(instance.Controller.State != WorkflowInstanceState.Aborted, "Cannot generate data for an aborted instance.");
5851                 if (instance.Controller.State != WorkflowInstanceState.Complete)
5852                 {
5853                     data[WorkflowNamespace.Workflow] = new InstanceValue(instance.Controller.PrepareForSerialization());
5854                     data[WorkflowNamespace.Status] = new InstanceValue(instance.Controller.State == WorkflowInstanceState.Idle ? "Idle" : "Executing", InstanceValueOptions.WriteOnly);
5855                 }
5856                 else
5857                 {
5858                     data[WorkflowNamespace.Workflow] = new InstanceValue(instance.Controller.PrepareForSerialization(), InstanceValueOptions.Optional);
5859
5860                     Exception completionException;
5861                     IDictionary<string, object> outputs;
5862                     ActivityInstanceState completionState = instance.Controller.GetCompletionState(out outputs, out completionException);
5863
5864                     if (completionState == ActivityInstanceState.Faulted)
5865                     {
5866                         data[WorkflowNamespace.Status] = new InstanceValue("Faulted", InstanceValueOptions.WriteOnly);
5867                         data[WorkflowNamespace.Exception] = new InstanceValue(completionException, InstanceValueOptions.WriteOnly | InstanceValueOptions.Optional);
5868                     }
5869                     else if (completionState == ActivityInstanceState.Closed)
5870                     {
5871                         data[WorkflowNamespace.Status] = new InstanceValue("Closed", InstanceValueOptions.WriteOnly);
5872                         if (outputs != null)
5873                         {
5874                             foreach (KeyValuePair<string, object> output in outputs)
5875                             {
5876                                 data[WorkflowNamespace.OutputPath.GetName(output.Key)] = new InstanceValue(output.Value, InstanceValueOptions.WriteOnly | InstanceValueOptions.Optional);
5877                             }
5878                         }
5879                     }
5880                     else
5881                     {
5882                         Fx.AssertAndThrow(completionState == ActivityInstanceState.Canceled, "Cannot be executing when WorkflowState was completed.");
5883                         data[WorkflowNamespace.Status] = new InstanceValue("Canceled", InstanceValueOptions.WriteOnly);
5884                     }
5885                 }
5886                 return data;
5887             }
5888
5889             static InstancePersistenceCommand GetCreateOwnerCommand(WorkflowIdentity definitionIdentity)
5890             {
5891                 // Technically, we only need to pass the owner identity when doing LoadRunnable.
5892                 // However, if we create an instance with identity on a store that doesn't recognize it,
5893                 // the identity metadata might be stored in a way which makes it unqueryable if the store
5894                 // is later upgraded to support identity (e.g. SWIS 4.0 -> 4.5 upgrade). So to be on the
5895                 // safe side, if we're using identity, we require the store to explicitly support it.
5896                 if (definitionIdentity != null)
5897                 {
5898                     CreateWorkflowOwnerWithIdentityCommand result = new CreateWorkflowOwnerWithIdentityCommand();
5899                     if (!object.ReferenceEquals(definitionIdentity, WorkflowApplication.unknownIdentity))
5900                     {
5901                         result.InstanceOwnerMetadata.Add(Workflow45Namespace.DefinitionIdentities,
5902                             new InstanceValue(new Collection<WorkflowIdentity> { definitionIdentity }));
5903                     }
5904                     return result;
5905                 }
5906                 else
5907                 {
5908                     return new CreateWorkflowOwnerCommand();
5909                 }
5910             }
5911
5912             static SaveWorkflowCommand CreateSaveCommand(IDictionary<XName, InstanceValue> instance, IDictionary<XName, InstanceValue> instanceMetadata, PersistenceOperation operation)
5913             {
5914                 SaveWorkflowCommand saveCommand = new SaveWorkflowCommand()
5915                 {
5916                     CompleteInstance = operation == PersistenceOperation.Complete,
5917                     UnlockInstance = operation != PersistenceOperation.Save,
5918                 };
5919
5920                 if (instance != null)
5921                 {
5922                     foreach (KeyValuePair<XName, InstanceValue> value in instance)
5923                     {
5924                         saveCommand.InstanceData.Add(value);
5925                     }
5926                 }
5927
5928                 if (instanceMetadata != null)
5929                 {
5930                     foreach (KeyValuePair<XName, InstanceValue> value in instanceMetadata)
5931                     {
5932                         saveCommand.InstanceMetadataChanges.Add(value);
5933                     }
5934                 }
5935
5936                 return saveCommand;
5937             }
5938
5939             bool TryLoadHelper(InstanceView view, out IDictionary<XName, InstanceValue> data)
5940             {
5941                 if (!view.IsBoundToLock)
5942                 {
5943                     data = null;
5944                     return false;
5945                 }
5946                 this.instanceId = view.InstanceId;
5947                 this.isLocked = true;
5948
5949                 if (!this.handle.IsValid)
5950                 {
5951                     throw FxTrace.Exception.AsError(new OperationCanceledException(SR.WorkflowInstanceAborted(InstanceId)));
5952                 }
5953
5954                 data = view.InstanceData;
5955                 return true;
5956             }
5957
5958             public void Save(IDictionary<XName, InstanceValue> instance, PersistenceOperation operation, TimeSpan timeout)
5959             {
5960                 this.store.Execute(this.handle, CreateSaveCommand(instance, (this.isLocked ? this.mutableMetadata : this.instanceMetadata), operation), timeout);
5961                 this.isLocked = true;
5962             }
5963
5964             public IDictionary<XName, InstanceValue> Load(TimeSpan timeout)
5965             {
5966                 InstanceView view = this.store.Execute(this.handle, new LoadWorkflowCommand(), timeout);
5967                 this.isLocked = true;
5968
5969                 if (!this.handle.IsValid)
5970                 {
5971                     throw FxTrace.Exception.AsError(new OperationCanceledException(SR.WorkflowInstanceAborted(InstanceId)));
5972                 }
5973
5974                 return view.InstanceData;
5975             }
5976
5977             public bool TryLoad(TimeSpan timeout, out IDictionary<XName, InstanceValue> data)
5978             {
5979                 InstanceView view = this.store.Execute(this.handle, new TryLoadRunnableWorkflowCommand(), timeout);
5980                 return TryLoadHelper(view, out data);
5981             }
5982
5983             public IAsyncResult BeginSave(IDictionary<XName, InstanceValue> instance, PersistenceOperation operation, TimeSpan timeout, AsyncCallback callback, object state)
5984             {
5985                 return this.store.BeginExecute(this.handle, CreateSaveCommand(instance, (this.isLocked ? this.mutableMetadata : this.instanceMetadata), operation), timeout, callback, state);
5986             }
5987
5988             public void EndSave(IAsyncResult result)
5989             {
5990                 this.store.EndExecute(result);
5991                 this.isLocked = true;
5992             }
5993
5994             public IAsyncResult BeginLoad(TimeSpan timeout, AsyncCallback callback, object state)
5995             {
5996                 return this.store.BeginExecute(this.handle, new LoadWorkflowCommand(), timeout, callback, state);
5997             }
5998
5999             public IDictionary<XName, InstanceValue> EndLoad(IAsyncResult result)
6000             {
6001                 InstanceView view = this.store.EndExecute(result);
6002                 this.isLocked = true;
6003
6004                 if (!this.handle.IsValid)
6005                 {
6006                     throw FxTrace.Exception.AsError(new OperationCanceledException(SR.WorkflowInstanceAborted(InstanceId)));
6007                 }
6008
6009                 return view.InstanceData;
6010             }
6011
6012             public IAsyncResult BeginTryLoad(TimeSpan timeout, AsyncCallback callback, object state)
6013             {
6014                 return this.store.BeginExecute(this.handle, new TryLoadRunnableWorkflowCommand(), timeout, callback, state);
6015             }
6016
6017             public bool EndTryLoad(IAsyncResult result, out IDictionary<XName, InstanceValue> data)
6018             {
6019                 InstanceView view = this.store.EndExecute(result);
6020                 return TryLoadHelper(view, out data);
6021             }
6022
6023             public void Abort()
6024             {
6025                 this.aborted = true;
6026
6027                 // Make sure the setter of handle sees aborted, or v.v., or both.
6028                 Thread.MemoryBarrier();
6029
6030                 InstanceHandle handle = this.handle;
6031                 if (handle != null)
6032                 {
6033                     handle.Free();
6034                 }
6035
6036                 FreeTemporaryHandle();
6037             }
6038
6039             public void Unlock(TimeSpan timeout)
6040             {
6041                 SaveWorkflowCommand saveCmd = new SaveWorkflowCommand()
6042                 {
6043                     UnlockInstance = true,
6044                 };
6045
6046                 this.store.Execute(this.handle, saveCmd, timeout);
6047             }
6048
6049             public IAsyncResult BeginUnlock(TimeSpan timeout, AsyncCallback callback, object state)
6050             {
6051                 SaveWorkflowCommand saveCmd = new SaveWorkflowCommand()
6052                 {
6053                     UnlockInstance = true,
6054                 };
6055
6056                 return this.store.BeginExecute(this.handle, saveCmd, timeout, callback, state);
6057             }
6058
6059             public void EndUnlock(IAsyncResult result)
6060             {
6061                 this.store.EndExecute(result);
6062             }
6063         }
6064     }
6065 }