You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			1935 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			1935 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //----------------------------------------------------------------
 | |
| // Copyright (c) Microsoft Corporation.  All rights reserved.
 | |
| //----------------------------------------------------------------
 | |
| 
 | |
| namespace System.Activities.Statements
 | |
| {
 | |
|     using System.Activities;
 | |
|     using System.Activities.Expressions;
 | |
|     using System.Activities.Persistence;
 | |
|     using System.Activities.Tracking;
 | |
|     using System.Activities.Validation;
 | |
|     using System.Collections;
 | |
|     using System.Collections.Generic;
 | |
|     using System.Collections.ObjectModel;
 | |
|     using System.ComponentModel;
 | |
|     using System.Diagnostics;
 | |
|     using System.Diagnostics.CodeAnalysis;
 | |
|     using System.Globalization;
 | |
|     using System.Linq;
 | |
|     using System.Reflection;
 | |
|     using System.Threading;
 | |
|     using System.Transactions;
 | |
|     using System.Xml.Linq;
 | |
|     using System.Workflow.Runtime;
 | |
|     using System.Workflow.ComponentModel.Compiler;
 | |
|     using ValidationError = System.Activities.Validation.ValidationError;
 | |
|     using System.Workflow.Runtime.Hosting;
 | |
|     using System.Workflow.Activities;
 | |
|     using System.Runtime.Serialization;
 | |
| 
 | |
|     [SuppressMessage("Microsoft.Naming", "CA1724:TypeNamesShouldNotMatchNamespaces",
 | |
|         Justification = "The type name 'Interop' conflicts in whole or in part with the namespace name 'System.Web.Services.Interop' - not common usage")]
 | |
|     [Obsolete("The WF3 Types are deprecated. Instead, please use the new WF4 Types from System.Activities.*")] 
 | |
|     public sealed class Interop : NativeActivity, ICustomTypeDescriptor
 | |
|     {
 | |
|         static Func<TimerExtension> getDefaultTimerExtension = new Func<TimerExtension>(GetDefaultTimerExtension);
 | |
|         static Func<InteropPersistenceParticipant> getInteropPersistenceParticipant = new Func<InteropPersistenceParticipant>(GetInteropPersistenceParticipant);
 | |
|         Dictionary<string, Argument> properties;
 | |
|         Dictionary<string, object> metaProperties;
 | |
|         System.Workflow.ComponentModel.Activity v1Activity;
 | |
|         IList<PropertyInfo> outputPropertyDefinitions;
 | |
|         HashSet<string> extraDynamicArguments;
 | |
|         bool exposedBodyPropertiesCacheIsValid;
 | |
|         IList<InteropProperty> exposedBodyProperties;
 | |
|         Variable<InteropExecutor> interopActivityExecutor;
 | |
|         Variable<RuntimeTransactionHandle> runtimeTransactionHandle;
 | |
|         BookmarkCallback onResumeBookmark;
 | |
|         CompletionCallback onPersistComplete;
 | |
|         BookmarkCallback onTransactionComplete;
 | |
|         Type activityType;
 | |
|         Persist persistActivity;
 | |
| 
 | |
|         internal const string InArgumentSuffix = "In";
 | |
|         internal const string OutArgumentSuffix = "Out";
 | |
|         Variable<bool> persistOnClose;
 | |
|         Variable<InteropEnlistment> interopEnlistment;
 | |
|         Variable<Exception> outstandingException;
 | |
| 
 | |
|         object thisLock;
 | |
|         // true if the body type is a valid activity. used so we can have delayed validation support in the designer
 | |
|         bool hasValidBody;
 | |
|         // true if the V3 activity property names will conflict with our generated argument names
 | |
|         bool hasNameCollision;
 | |
| 
 | |
|         public Interop()
 | |
|             : base()
 | |
|         {
 | |
|             this.interopActivityExecutor = new Variable<InteropExecutor>();
 | |
|             this.runtimeTransactionHandle = new Variable<RuntimeTransactionHandle>();
 | |
|             this.persistOnClose = new Variable<bool>();
 | |
|             this.interopEnlistment = new Variable<InteropEnlistment>();
 | |
|             this.outstandingException = new Variable<Exception>();
 | |
|             this.onResumeBookmark = new BookmarkCallback(this.OnResumeBookmark);
 | |
|             this.persistActivity = new Persist();
 | |
|             this.thisLock = new object();
 | |
|             base.Constraints.Add(ProcessAdvancedConstraints());
 | |
|         }
 | |
| 
 | |
|         [DefaultValue(null)]
 | |
|         public Type ActivityType
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 return this.activityType;
 | |
|             }
 | |
|             set
 | |
|             {
 | |
|                 if (value != this.activityType)
 | |
|                 {
 | |
|                     this.hasValidBody = false;
 | |
|                     if (value != null)
 | |
|                     {
 | |
|                         if (typeof(System.Workflow.ComponentModel.Activity).IsAssignableFrom(value)
 | |
|                             && value.GetConstructor(Type.EmptyTypes) != null)
 | |
|                         {
 | |
|                             this.hasValidBody = true;
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     this.activityType = value;
 | |
| 
 | |
|                     if (this.metaProperties != null)
 | |
|                     {
 | |
|                         this.metaProperties.Clear();
 | |
|                     }
 | |
|                     if (this.outputPropertyDefinitions != null)
 | |
|                     {
 | |
|                         this.outputPropertyDefinitions.Clear();
 | |
|                     }
 | |
|                     if (this.properties != null)
 | |
|                     {
 | |
|                         this.properties.Clear();
 | |
|                     }
 | |
|                     if (this.exposedBodyProperties != null)
 | |
|                     {
 | |
|                         for (int i = 0; i < this.exposedBodyProperties.Count; i++)
 | |
|                         {
 | |
|                             this.exposedBodyProperties[i].Invalidate();
 | |
|                         }
 | |
|                         this.exposedBodyProperties.Clear();
 | |
|                     }
 | |
|                     this.exposedBodyPropertiesCacheIsValid = false;
 | |
| 
 | |
|                     this.v1Activity = null;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         [Browsable(false)]
 | |
|         public IDictionary<string, Argument> ActivityProperties
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 if (this.properties == null)
 | |
|                 {
 | |
|                     this.properties = new Dictionary<string, Argument>();
 | |
|                 }
 | |
| 
 | |
|                 return this.properties;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         [Browsable(false)]
 | |
|         public IDictionary<string, object> ActivityMetaProperties
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 if (this.metaProperties == null)
 | |
|                 {
 | |
|                     this.metaProperties = new Dictionary<string, object>();
 | |
|                 }
 | |
|                 return this.metaProperties;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected override bool CanInduceIdle
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         internal System.Workflow.ComponentModel.Activity ComponentModelActivity
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 if (this.v1Activity == null && this.ActivityType != null)
 | |
|                 {
 | |
|                     Debug.Assert(this.hasValidBody, "should only be called when we have a valid body");
 | |
|                     this.v1Activity = CreateActivity();
 | |
|                 }
 | |
|                 return this.v1Activity;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         internal IList<PropertyInfo> OutputPropertyDefinitions
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 return this.outputPropertyDefinitions;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         internal bool HasNameCollision
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 return this.hasNameCollision;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected override void CacheMetadata(NativeActivityMetadata metadata)
 | |
|         {
 | |
|             if (this.extraDynamicArguments != null)
 | |
|             {
 | |
|                 this.extraDynamicArguments.Clear();
 | |
|             }
 | |
| 
 | |
|             this.v1Activity = null;
 | |
| 
 | |
|             if (this.hasValidBody)
 | |
|             {
 | |
|                 //Cache the output properties prop info for look up.
 | |
|                 this.outputPropertyDefinitions = new List<PropertyInfo>();
 | |
| 
 | |
|                 //Cache the extra property definitions for look up in OnOpen
 | |
|                 if (this.properties != null)
 | |
|                 {
 | |
|                     if (this.extraDynamicArguments == null)
 | |
|                     {
 | |
|                         this.extraDynamicArguments = new HashSet<string>();
 | |
|                     }
 | |
| 
 | |
|                     foreach (string name in properties.Keys)
 | |
|                     {
 | |
|                         this.extraDynamicArguments.Add(name);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 //Create matched pair of RuntimeArguments for every property: Property (InArgument) & PropertyOut (Argument)
 | |
|                 PropertyInfo[] bodyProperties = this.ActivityType.GetProperties();
 | |
|                 // recheck for name collisions
 | |
|                 this.hasNameCollision = InteropEnvironment.ParameterHelper.HasPropertyNameCollision(bodyProperties);
 | |
|                 foreach (PropertyInfo propertyInfo in bodyProperties)
 | |
|                 {
 | |
|                     if (InteropEnvironment.ParameterHelper.IsBindable(propertyInfo))
 | |
|                     {
 | |
|                         string propertyInName;
 | |
|                         //If there are any Property/PropertyOut name pairs already extant, we fall back to renaming the InArgument half of the pair as well
 | |
|                         if (this.hasNameCollision)
 | |
|                         {
 | |
|                             propertyInName = propertyInfo.Name + Interop.InArgumentSuffix;
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             propertyInName = propertyInfo.Name;
 | |
|                         }
 | |
|                         //We always rename the OutArgument half of the pair
 | |
|                         string propertyOutName = propertyInfo.Name + Interop.OutArgumentSuffix;
 | |
| 
 | |
|                         RuntimeArgument inArgument = new RuntimeArgument(propertyInName, propertyInfo.PropertyType, ArgumentDirection.In);
 | |
|                         RuntimeArgument outArgument = new RuntimeArgument(propertyOutName, propertyInfo.PropertyType, ArgumentDirection.Out);
 | |
| 
 | |
|                         if (this.properties != null)
 | |
|                         {
 | |
|                             Argument inBinding = null;
 | |
|                             if (this.properties.TryGetValue(propertyInName, out inBinding))
 | |
|                             {
 | |
|                                 if (inBinding.Direction != ArgumentDirection.In)
 | |
|                                 {
 | |
|                                     throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, ExecutionStringManager.InteropArgumentDirectionMismatch, propertyInName, propertyOutName));
 | |
|                                 }
 | |
| 
 | |
|                                 this.extraDynamicArguments.Remove(propertyInName);
 | |
|                                 metadata.Bind(inBinding, inArgument);
 | |
|                             }
 | |
| 
 | |
|                             Argument outBinding = null;
 | |
|                             if (this.properties.TryGetValue(propertyOutName, out outBinding))
 | |
|                             {
 | |
|                                 this.extraDynamicArguments.Remove(propertyOutName);
 | |
|                                 metadata.Bind(outBinding, outArgument);
 | |
|                             }
 | |
|                         }
 | |
|                         metadata.AddArgument(inArgument);
 | |
|                         metadata.AddArgument(outArgument);
 | |
| 
 | |
|                         this.outputPropertyDefinitions.Add(propertyInfo);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             metadata.SetImplementationVariablesCollection(
 | |
|                 new Collection<Variable>
 | |
|                 {
 | |
|                     this.interopActivityExecutor,
 | |
|                     this.runtimeTransactionHandle,
 | |
|                     this.persistOnClose,
 | |
|                     this.interopEnlistment,
 | |
|                     this.outstandingException
 | |
|                 });
 | |
| 
 | |
|             metadata.AddImplementationChild(this.persistActivity);
 | |
| 
 | |
|             if (!this.hasValidBody)
 | |
|             {
 | |
|                 if (this.ActivityType == null)
 | |
|                 {
 | |
|                     metadata.AddValidationError(string.Format(CultureInfo.CurrentCulture, ExecutionStringManager.InteropBodyNotSet, this.DisplayName));
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     // Body needs to be a WF 3.0 activity
 | |
|                     if (!typeof(System.Workflow.ComponentModel.Activity).IsAssignableFrom(this.ActivityType))
 | |
|                     {
 | |
|                         metadata.AddValidationError(string.Format(CultureInfo.CurrentCulture, ExecutionStringManager.InteropWrongBody, this.DisplayName));
 | |
|                     }
 | |
| 
 | |
|                     // and have a default ctor
 | |
|                     if (this.ActivityType.GetConstructor(Type.EmptyTypes) == null)
 | |
|                     {
 | |
|                         metadata.AddValidationError(string.Format(CultureInfo.CurrentCulture, ExecutionStringManager.InteropBodyMustHavePublicDefaultConstructor, this.DisplayName));
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (this.extraDynamicArguments != null && this.extraDynamicArguments.Count > 0)
 | |
|                 {
 | |
|                     metadata.AddValidationError(string.Format(CultureInfo.CurrentCulture, ExecutionStringManager.AttemptToBindUnknownProperties, this.DisplayName, this.extraDynamicArguments.First()));
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     try
 | |
|                     {
 | |
|                         InitializeMetaProperties(this.ComponentModelActivity);
 | |
|                         // We call InitializeDefinitionForRuntime in the first call to execute to 
 | |
|                         // make sure it only happens once.
 | |
|                     }
 | |
|                     catch (InvalidOperationException e)
 | |
|                     {
 | |
|                         metadata.AddValidationError(e.Message);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             metadata.AddDefaultExtensionProvider(getDefaultTimerExtension);
 | |
|             metadata.AddDefaultExtensionProvider(getInteropPersistenceParticipant);
 | |
|         }
 | |
| 
 | |
|         static TimerExtension GetDefaultTimerExtension()
 | |
|         {
 | |
|             return new DurableTimerExtension();
 | |
|         }
 | |
| 
 | |
|         static InteropPersistenceParticipant GetInteropPersistenceParticipant()
 | |
|         {
 | |
|             return new InteropPersistenceParticipant();
 | |
|         }
 | |
| 
 | |
|         protected override void Execute(NativeActivityContext context)
 | |
|         {
 | |
|             // 
 | |
| 
 | |
| 
 | |
|             WorkflowRuntimeService workflowRuntimeService = context.GetExtension<WorkflowRuntimeService>();
 | |
|             if (workflowRuntimeService != null && !(workflowRuntimeService is ExternalDataExchangeService))
 | |
|             {
 | |
|                 throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ExecutionStringManager.InteropWorkflowRuntimeServiceNotSupported));
 | |
|             }
 | |
| 
 | |
|             lock (this.thisLock)
 | |
|             {
 | |
|                 ((System.Workflow.ComponentModel.IDependencyObjectAccessor)this.ComponentModelActivity).InitializeDefinitionForRuntime(null);
 | |
|             }
 | |
|             if (!this.ComponentModelActivity.Enabled)
 | |
|             {
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             System.Workflow.ComponentModel.Activity activityInstance = CreateActivity();
 | |
|             InitializeMetaProperties(activityInstance);
 | |
|             activityInstance.SetValue(WorkflowExecutor.WorkflowInstanceIdProperty, context.WorkflowInstanceId);
 | |
| 
 | |
|             InteropExecutor interopExecutor = new InteropExecutor(context.WorkflowInstanceId, activityInstance, this.OutputPropertyDefinitions, this.ComponentModelActivity);
 | |
| 
 | |
|             if (!interopExecutor.HasCheckedForTrackingParticipant)
 | |
|             {
 | |
|                 interopExecutor.TrackingEnabled = (context.GetExtension<TrackingParticipant>() != null);
 | |
|                 interopExecutor.HasCheckedForTrackingParticipant = true;
 | |
|             }
 | |
| 
 | |
|             this.interopActivityExecutor.Set(context, interopExecutor);
 | |
| 
 | |
|             //Register the Handle as an execution property so that we can call GetCurrentTransaction or
 | |
|             //RequestTransactionContext on it later
 | |
|             RuntimeTransactionHandle runtimeTransactionHandle = this.runtimeTransactionHandle.Get(context);
 | |
|             context.Properties.Add(runtimeTransactionHandle.ExecutionPropertyName, runtimeTransactionHandle);
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 using (new ServiceEnvironment(activityInstance))
 | |
|                 {
 | |
|                     using (InteropEnvironment interopEnvironment = new InteropEnvironment(
 | |
|                         interopExecutor, context,
 | |
|                         this.onResumeBookmark,
 | |
|                         this,
 | |
|                         runtimeTransactionHandle.GetCurrentTransaction(context)))
 | |
|                     {
 | |
|                         interopEnvironment.Execute(this.ComponentModelActivity, context);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             catch (Exception exception)
 | |
|             {
 | |
|                 if (WorkflowExecutor.IsIrrecoverableException(exception) || !this.persistOnClose.Get(context))
 | |
|                 {
 | |
|                     throw;
 | |
|                 }
 | |
| 
 | |
|                 // We are not ----ing the exception.  The exception is saved in this.outstandingException.  
 | |
|                 // We will throw the exception from OnPersistComplete.
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected override void Cancel(NativeActivityContext context)
 | |
|         {
 | |
|             InteropExecutor interopExecutor = this.interopActivityExecutor.Get(context);
 | |
| 
 | |
|             if (!interopExecutor.HasCheckedForTrackingParticipant)
 | |
|             {
 | |
|                 interopExecutor.TrackingEnabled = (context.GetExtension<TrackingParticipant>() != null);
 | |
|                 interopExecutor.HasCheckedForTrackingParticipant = true;
 | |
|             }
 | |
| 
 | |
|             interopExecutor.EnsureReload(this);
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 using (InteropEnvironment interopEnvironment = new InteropEnvironment(
 | |
|                     interopExecutor, context,
 | |
|                     this.onResumeBookmark,
 | |
|                     this,
 | |
|                     this.runtimeTransactionHandle.Get(context).GetCurrentTransaction(context)))
 | |
|                 {
 | |
|                     interopEnvironment.Cancel();
 | |
|                 }
 | |
|             }
 | |
|             catch (Exception exception)
 | |
|             {
 | |
|                 if (WorkflowExecutor.IsIrrecoverableException(exception) || !this.persistOnClose.Get(context))
 | |
|                 {
 | |
|                     throw;
 | |
|                 }
 | |
| 
 | |
|                 // We are not ----ing the exception.  The exception is saved in this.outstandingException.  
 | |
|                 // We will throw the exception from OnPersistComplete.
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         internal void SetOutputArgumentValues(IDictionary<string, object> outputs, NativeActivityContext context)
 | |
|         {
 | |
|             if ((this.properties != null) && (outputs != null))
 | |
|             {
 | |
|                 foreach (KeyValuePair<string, object> output in outputs)
 | |
|                 {
 | |
|                     Argument argument;
 | |
|                     if (this.properties.TryGetValue(output.Key, out argument) && argument != null)
 | |
|                     {
 | |
|                         if (argument.Direction == ArgumentDirection.Out)
 | |
|                         {
 | |
|                             argument.Set(context, output.Value);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         internal IDictionary<string, object> GetInputArgumentValues(NativeActivityContext context)
 | |
|         {
 | |
|             Dictionary<string, object> arguments = null;
 | |
| 
 | |
|             if (this.properties != null)
 | |
|             {
 | |
|                 foreach (KeyValuePair<string, Argument> parameter in this.properties)
 | |
|                 {
 | |
|                     Argument argument = parameter.Value;
 | |
| 
 | |
|                     if (argument.Direction == ArgumentDirection.In)
 | |
|                     {
 | |
|                         if (arguments == null)
 | |
|                         {
 | |
|                             arguments = new Dictionary<string, object>();
 | |
|                         }
 | |
| 
 | |
|                         arguments.Add(parameter.Key, argument.Get<object>(context));
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return arguments;
 | |
|         }
 | |
| 
 | |
|         System.Workflow.ComponentModel.Activity CreateActivity()
 | |
|         {
 | |
|             Debug.Assert(this.ActivityType != null, "ActivityType must be set by the time we get here");
 | |
| 
 | |
|             System.Workflow.ComponentModel.Activity activity = Activator.CreateInstance(this.ActivityType) as System.Workflow.ComponentModel.Activity;
 | |
|             Debug.Assert(activity != null, "We should have validated that the type has a default ctor() and derives from System.Workflow.ComponentModel.Activity.");
 | |
| 
 | |
|             return activity;
 | |
|         }
 | |
| 
 | |
|         void InitializeMetaProperties(System.Workflow.ComponentModel.Activity activity)
 | |
|         {
 | |
|             Debug.Assert((activity.GetType() == this.ActivityType), "activity must be the same type as this.ActivityType");
 | |
|             if (this.metaProperties != null && this.metaProperties.Count > 0)
 | |
|             {
 | |
|                 foreach (string name in this.metaProperties.Keys)
 | |
|                 {
 | |
|                     PropertyInfo property = this.ActivityType.GetProperty(name);
 | |
|                     if (property == null)
 | |
|                     {
 | |
|                         throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ExecutionStringManager.MetaPropertyDoesNotExist, name, this.ActivityType.FullName));
 | |
|                     }
 | |
|                     property.SetValue(activity, this.metaProperties[name], null);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void OnResumeBookmark(NativeActivityContext context, Bookmark bookmark, object state)
 | |
|         {
 | |
|             InteropExecutor interopExecutor = this.interopActivityExecutor.Get(context);
 | |
| 
 | |
|             if (!interopExecutor.HasCheckedForTrackingParticipant)
 | |
|             {
 | |
|                 interopExecutor.TrackingEnabled = (context.GetExtension<TrackingParticipant>() != null);
 | |
|                 interopExecutor.HasCheckedForTrackingParticipant = true;
 | |
|             }
 | |
| 
 | |
|             interopExecutor.EnsureReload(this);
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 using (InteropEnvironment interopEnvironment = new InteropEnvironment(
 | |
|                     interopExecutor, context,
 | |
|                     this.onResumeBookmark,
 | |
|                     this,
 | |
|                     this.runtimeTransactionHandle.Get(context).GetCurrentTransaction(context)))
 | |
|                 {
 | |
|                     IComparable queueName = interopExecutor.BookmarkQueueMap[bookmark];
 | |
|                     interopEnvironment.EnqueueEvent(queueName, state);
 | |
|                 }
 | |
|             }
 | |
|             catch (Exception exception)
 | |
|             {
 | |
|                 if (WorkflowExecutor.IsIrrecoverableException(exception) || !this.persistOnClose.Get(context))
 | |
|                 {
 | |
|                     throw;
 | |
|                 }
 | |
| 
 | |
|                 // We are not ----ing the exception.  The exception is saved in this.outstandingException.  
 | |
|                 // We will throw the exception from OnPersistComplete.
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         AttributeCollection ICustomTypeDescriptor.GetAttributes()
 | |
|         {
 | |
|             return TypeDescriptor.GetAttributes(this, true);
 | |
|         }
 | |
| 
 | |
|         string ICustomTypeDescriptor.GetClassName()
 | |
|         {
 | |
|             return TypeDescriptor.GetClassName(this, true);
 | |
|         }
 | |
| 
 | |
|         string ICustomTypeDescriptor.GetComponentName()
 | |
|         {
 | |
|             return TypeDescriptor.GetComponentName(this, true);
 | |
|         }
 | |
| 
 | |
|         TypeConverter ICustomTypeDescriptor.GetConverter()
 | |
|         {
 | |
|             return TypeDescriptor.GetConverter(this, true);
 | |
|         }
 | |
| 
 | |
|         EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
 | |
|         {
 | |
|             return TypeDescriptor.GetDefaultEvent(this, true);
 | |
|         }
 | |
| 
 | |
|         PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
 | |
|         {
 | |
|             return TypeDescriptor.GetDefaultProperty(this, true);
 | |
|         }
 | |
| 
 | |
|         object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
 | |
|         {
 | |
|             return TypeDescriptor.GetEditor(this, editorBaseType, true);
 | |
|         }
 | |
| 
 | |
|         EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
 | |
|         {
 | |
|             return TypeDescriptor.GetEvents(this, attributes, true);
 | |
|         }
 | |
| 
 | |
|         EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
 | |
|         {
 | |
|             return TypeDescriptor.GetEvents(this, true);
 | |
|         }
 | |
| 
 | |
|         PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
 | |
|         {
 | |
|             List<PropertyDescriptor> properties = new List<PropertyDescriptor>();
 | |
| 
 | |
|             PropertyDescriptorCollection interopProperties;
 | |
|             if (attributes != null)
 | |
|             {
 | |
|                 interopProperties = TypeDescriptor.GetProperties(this, attributes, true);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 interopProperties = TypeDescriptor.GetProperties(this, true);
 | |
|             }
 | |
|             for (int i = 0; i < interopProperties.Count; i++)
 | |
|             {
 | |
|                 properties.Add(interopProperties[i]);
 | |
|             }
 | |
| 
 | |
|             if (this.hasValidBody)
 | |
|             {
 | |
|                 // First, cache the full set of body properties
 | |
|                 if (!this.exposedBodyPropertiesCacheIsValid)
 | |
|                 {
 | |
|                     //Create matched pair of RuntimeArguments for every property: Property (InArgument) & PropertyOut (Argument)
 | |
|                     PropertyInfo[] bodyProperties = this.ActivityType.GetProperties();
 | |
|                     // recheck for name collisions
 | |
|                     this.hasNameCollision = InteropEnvironment.ParameterHelper.HasPropertyNameCollision(bodyProperties);
 | |
|                     for (int i = 0; i < bodyProperties.Length; i++)
 | |
|                     {
 | |
|                         PropertyInfo property = bodyProperties[i];
 | |
|                         bool isMetaProperty;
 | |
|                         if (InteropEnvironment.ParameterHelper.IsBindableOrMetaProperty(property, out isMetaProperty))
 | |
|                         {
 | |
|                             // Propagate the attributes to the PropertyDescriptor, appending a DesignerSerializationVisibility attribute
 | |
|                             Attribute[] customAttributes = Attribute.GetCustomAttributes(property, true);
 | |
|                             Attribute[] newAttributes = new Attribute[customAttributes.Length + 1];
 | |
|                             customAttributes.CopyTo(newAttributes, 0);
 | |
|                             newAttributes[customAttributes.Length] = new DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden);
 | |
| 
 | |
|                             if (this.exposedBodyProperties == null)
 | |
|                             {
 | |
|                                 this.exposedBodyProperties = new List<InteropProperty>(bodyProperties.Length);
 | |
|                             }
 | |
|                             if (isMetaProperty)
 | |
|                             {
 | |
|                                 InteropProperty descriptor = new LiteralProperty(this, property.Name, property.PropertyType, newAttributes);
 | |
|                                 this.exposedBodyProperties.Add(descriptor);
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 InteropProperty inDescriptor;
 | |
|                                 //If there are any Property/PropertyOut name pairs already extant, we fall back to renaming the InArgument half of the pair as well
 | |
|                                 if (this.hasNameCollision)
 | |
|                                 {
 | |
|                                     inDescriptor = new ArgumentProperty(this, property.Name + InArgumentSuffix, Argument.Create(property.PropertyType, ArgumentDirection.In), newAttributes);
 | |
|                                 }
 | |
|                                 else
 | |
|                                 {
 | |
|                                     inDescriptor = new ArgumentProperty(this, property.Name, Argument.Create(property.PropertyType, ArgumentDirection.In), newAttributes);
 | |
|                                 }
 | |
|                                 this.exposedBodyProperties.Add(inDescriptor);
 | |
|                                 //We always rename the OutArgument half of the pair
 | |
|                                 InteropProperty outDescriptor = new ArgumentProperty(this, property.Name + OutArgumentSuffix, Argument.Create(property.PropertyType, ArgumentDirection.Out), newAttributes);
 | |
|                                 this.exposedBodyProperties.Add(outDescriptor);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                     this.exposedBodyPropertiesCacheIsValid = true;
 | |
|                 }
 | |
|                 // Now adds body properties, complying with the filter:
 | |
|                 if (this.exposedBodyProperties != null)
 | |
|                 {
 | |
|                     for (int i = 0; i < this.exposedBodyProperties.Count; i++)
 | |
|                     {
 | |
|                         PropertyDescriptor descriptor = this.exposedBodyProperties[i];
 | |
|                         if (attributes == null || !ShouldFilterProperty(descriptor, attributes))
 | |
|                         {
 | |
|                             properties.Add(descriptor);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return new PropertyDescriptorCollection(properties.ToArray());
 | |
|         }
 | |
| 
 | |
|         static bool ShouldFilterProperty(PropertyDescriptor property, Attribute[] attributes)
 | |
|         {
 | |
|             if (attributes == null || attributes.Length == 0)
 | |
|             {
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             for (int i = 0; i < attributes.Length; i++)
 | |
|             {
 | |
|                 Attribute filterAttribute = attributes[i];
 | |
|                 Attribute propertyAttribute = property.Attributes[filterAttribute.GetType()];
 | |
|                 if (propertyAttribute == null)
 | |
|                 {
 | |
|                     if (!filterAttribute.IsDefaultAttribute())
 | |
|                     {
 | |
|                         return true;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     if (!filterAttribute.Match(propertyAttribute))
 | |
|                     {
 | |
|                         return true;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
 | |
|         {
 | |
|             return ((ICustomTypeDescriptor)this).GetProperties(null);
 | |
|         }
 | |
| 
 | |
|         object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
 | |
|         {
 | |
|             InteropProperty intProp = pd as InteropProperty;
 | |
|             if (intProp != null)
 | |
|             {
 | |
|                 return intProp.Owner;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 return this;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         internal void OnClose(NativeActivityContext context, Exception exception)
 | |
|         {
 | |
|             if (this.persistOnClose.Get(context))
 | |
|             {
 | |
|                 if (exception == null)
 | |
|                 {
 | |
|                     context.ScheduleActivity(this.persistActivity);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     // The V1 workflow faulted and there is an uncaught exception. We cannot throw
 | |
|                     // the exception right away because we must Persist in order to process the WorkBatch.
 | |
|                     // So we are saving the uncaught exception and scheduling the Persist activity with a completion callback.
 | |
|                     // We will throw the exception from OnPersistComplete.
 | |
|                     this.outstandingException.Set(context, exception);
 | |
| 
 | |
|                     if (this.onPersistComplete == null)
 | |
|                     {
 | |
|                         this.onPersistComplete = new CompletionCallback(this.OnPersistComplete);
 | |
|                     }
 | |
| 
 | |
|                     context.ScheduleActivity(this.persistActivity, this.onPersistComplete);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             this.interopEnlistment.Set(context, null);
 | |
|         }
 | |
| 
 | |
|         internal void Persist(NativeActivityContext context)
 | |
|         {
 | |
|             if (this.onPersistComplete == null)
 | |
|             {
 | |
|                 this.onPersistComplete = new CompletionCallback(this.OnPersistComplete);
 | |
|             }
 | |
| 
 | |
|             // If Persist fails for any reason, the workflow aborts
 | |
|             context.ScheduleActivity(this.persistActivity, this.onPersistComplete);
 | |
|         }
 | |
| 
 | |
|         internal void OnPersistComplete(NativeActivityContext context, ActivityInstance completedInstance)
 | |
|         {
 | |
|             this.persistOnClose.Set(context, false);
 | |
|             Exception exception = this.outstandingException.Get(context);
 | |
|             if (exception != null)
 | |
|             {
 | |
|                 this.outstandingException.Set(context, null);
 | |
|                 throw exception;
 | |
|             }
 | |
| 
 | |
|             this.Resume(context, null);
 | |
|         }
 | |
| 
 | |
|         internal void CreateTransaction(NativeActivityContext context, TransactionOptions txOptions)
 | |
|         {
 | |
|             RuntimeTransactionHandle transactionHandle = this.runtimeTransactionHandle.Get(context);
 | |
|             Debug.Assert(transactionHandle != null, "RuntimeTransactionHandle is null");
 | |
| 
 | |
|             transactionHandle.RequestTransactionContext(context, OnTransactionContextAcquired, txOptions);
 | |
|         }
 | |
| 
 | |
|         void OnTransactionContextAcquired(NativeActivityTransactionContext context, object state)
 | |
|         {
 | |
|             Debug.Assert(context != null, "ActivityTransactionContext was null");
 | |
|             TransactionOptions txOptions = (TransactionOptions)state;
 | |
|             CommittableTransaction transaction = new CommittableTransaction(txOptions);
 | |
|             context.SetRuntimeTransaction(transaction);
 | |
|             this.Resume(context, transaction);
 | |
|         }
 | |
| 
 | |
|         internal void CommitTransaction(NativeActivityContext context)
 | |
|         {
 | |
|             if (this.onTransactionComplete == null)
 | |
|             {
 | |
|                 this.onTransactionComplete = new BookmarkCallback(this.OnTransactionComplete);
 | |
|             }
 | |
| 
 | |
|             RuntimeTransactionHandle transactionHandle = this.runtimeTransactionHandle.Get(context);
 | |
|             transactionHandle.CompleteTransaction(context, this.onTransactionComplete);
 | |
|         }
 | |
| 
 | |
|         void OnTransactionComplete(NativeActivityContext context, Bookmark bookmark, object state)
 | |
|         {
 | |
|             this.Resume(context, null);
 | |
|         }
 | |
| 
 | |
|         void Resume(NativeActivityContext context, Transaction transaction)
 | |
|         {
 | |
|             InteropExecutor interopExecutor = this.interopActivityExecutor.Get(context);
 | |
| 
 | |
|             if (!interopExecutor.HasCheckedForTrackingParticipant)
 | |
|             {
 | |
|                 interopExecutor.TrackingEnabled = (context.GetExtension<TrackingParticipant>() != null);
 | |
|                 interopExecutor.HasCheckedForTrackingParticipant = true;
 | |
|             }
 | |
| 
 | |
|             interopExecutor.EnsureReload(this);
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 using (InteropEnvironment interopEnvironment = new InteropEnvironment(
 | |
|                     interopExecutor, context,
 | |
|                     this.onResumeBookmark,
 | |
|                     this,
 | |
|                     transaction))
 | |
|                 {
 | |
|                     interopEnvironment.Resume();
 | |
|                 }
 | |
|             }
 | |
|             catch (Exception exception)
 | |
|             {
 | |
|                 if (WorkflowExecutor.IsIrrecoverableException(exception) || !this.persistOnClose.Get(context))
 | |
|                 {
 | |
|                     throw;
 | |
|                 }
 | |
| 
 | |
|                 // We are not ----ing the exception.  The exception is saved in this.outstandingException.  
 | |
|                 // We will throw the exception from OnPersistComplete.
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         internal void AddResourceManager(NativeActivityContext context, VolatileResourceManager resourceManager)
 | |
|         {
 | |
|             if (Transaction.Current != null &&
 | |
|                 Transaction.Current.TransactionInformation.Status == TransactionStatus.Active)
 | |
|             {
 | |
|                 InteropEnlistment enlistment = this.interopEnlistment.Get(context);
 | |
|                 if (enlistment == null || !enlistment.IsValid)
 | |
|                 {
 | |
|                     enlistment = new InteropEnlistment(Transaction.Current, resourceManager);
 | |
|                     Transaction.Current.EnlistVolatile(enlistment, EnlistmentOptions.EnlistDuringPrepareRequired);
 | |
|                     this.interopEnlistment.Set(context, enlistment);
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 InteropPersistenceParticipant persistenceParticipant = context.GetExtension<InteropPersistenceParticipant>();
 | |
|                 persistenceParticipant.Add(this.Id, resourceManager);
 | |
|                 this.persistOnClose.Set(context, true);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         Constraint ProcessAdvancedConstraints()
 | |
|         {
 | |
|             DelegateInArgument<Interop> element = new DelegateInArgument<Interop>() { Name = "element" };
 | |
|             DelegateInArgument<ValidationContext> validationContext = new DelegateInArgument<ValidationContext>() { Name = "validationContext" };
 | |
|             DelegateInArgument<Activity> parent = new DelegateInArgument<Activity>() { Name = "parent" };
 | |
| 
 | |
|             //This will accumulate all potential violations at the root level. See the use case DIRECT of the Interop spec
 | |
|             Variable<HashSet<InteropValidationEnum>> rootValidationDataVar = new Variable<HashSet<InteropValidationEnum>>(context => new HashSet<InteropValidationEnum>());
 | |
| 
 | |
|             //This will accumulate all violations at the nested level. See the use case NESTED of the Interop spec
 | |
|             Variable<HashSet<InteropValidationEnum>> nestedChildrenValidationDataVar = new Variable<HashSet<InteropValidationEnum>>(context => new HashSet<InteropValidationEnum>());
 | |
| 
 | |
|             return new Constraint<Interop>
 | |
|             {
 | |
|                 Body = new ActivityAction<Interop, ValidationContext>
 | |
|                 {
 | |
|                     Argument1 = element,
 | |
|                     Argument2 = validationContext,
 | |
|                     Handler = new If
 | |
|                     {
 | |
|                         Condition = new InArgument<bool>(env => element.Get(env).hasValidBody),
 | |
|                         Then = new Sequence
 | |
|                         {
 | |
|                             Variables = { rootValidationDataVar, nestedChildrenValidationDataVar },
 | |
|                             Activities = 
 | |
|                              {
 | |
|                                 //First traverse the interop body and collect all available data for validation. This is done at all levels, DIRECT and NESTED
 | |
|                                 new WalkInteropBodyAndGatherData()
 | |
|                                 {
 | |
|                                      RootLevelValidationData = new InArgument<HashSet<InteropValidationEnum>>(rootValidationDataVar),
 | |
|                                      NestedChildrenValidationData = new InArgument<HashSet<InteropValidationEnum>>(nestedChildrenValidationDataVar),
 | |
|                                      InteropActivity = element
 | |
|                                 },
 | |
|                                 //This is based off the table in the Interop spec.
 | |
|                                 new ValidateAtRootAndNestedLevels()
 | |
|                                 {
 | |
|                                      RootLevelValidationData = rootValidationDataVar,
 | |
|                                      NestedChildrenValidationData = nestedChildrenValidationDataVar,
 | |
|                                      Interop = element,
 | |
|                                 },
 | |
|                                 //Traverse the parent chain of the Interop activity to look for specifc violations regarding composition of 3.0 activities within 4.0 activities.
 | |
|                                 //Specifically, 
 | |
|                                 //  - 3.0 TransactionScope within a 4.0 TransactionScope
 | |
|                                 //  - 3.0 PersistOnClose within a 4.0 TransactionScope
 | |
|                                 //
 | |
|                                 new ForEach<Activity>
 | |
|                                 {
 | |
|                                     Values = new GetParentChain
 | |
|                                     {
 | |
|                                         ValidationContext = validationContext,
 | |
|                                     },
 | |
|                                     Body = new ActivityAction<Activity>
 | |
|                                     {
 | |
|                                         Argument = parent,
 | |
|                                         Handler = new Sequence                                   
 | |
|                                         {
 | |
|                                             Activities = 
 | |
|                                             {
 | |
|                                                 new If()
 | |
|                                                 {
 | |
|                                                     Condition = new Or<bool, bool, bool>
 | |
|                                                     { 
 | |
|                                                         Left = new Equal<Type, Type, bool>
 | |
|                                                         {
 | |
|                                                             Left = new ObtainType
 | |
|                                                             {
 | |
|                                                                 Input = parent,
 | |
|                                                             },
 | |
|                                                             Right = new InArgument<Type>(context => typeof(System.Activities.Statements.TransactionScope))
 | |
|                                                         },
 | |
|                                                         Right = new Equal<string, string, bool>
 | |
|                                                         {
 | |
|                                                             Left = new InArgument<string>(env => parent.Get(env).GetType().FullName),
 | |
|                                                             Right = "System.ServiceModel.Activities.TransactedReceiveScope"
 | |
|                                                         }
 | |
|                                                     },
 | |
|                                                     Then = new Sequence
 | |
|                                                     {
 | |
|                                                         Activities = 
 | |
|                                                         {
 | |
|                                                             new AssertValidation
 | |
|                                                             {
 | |
|                                                                 //Here we only pass the NestedChildrenValidationData since root level use 
 | |
|                                                                 //of TransactionScope would have already been flagged as an error
 | |
|                                                                 Assertion = new CheckForTransactionScope()
 | |
|                                                                 {
 | |
|                                                                      ValidationResults = nestedChildrenValidationDataVar
 | |
|                                                                 },
 | |
|                                                                 Message = new InArgument<string>(ExecutionStringManager.InteropBodyNestedTransactionScope)
 | |
|                                                             },
 | |
|                                                             new AssertValidation
 | |
|                                                             {
 | |
|                                                                 Assertion = new CheckForPersistOnClose()
 | |
|                                                                 {
 | |
|                                                                      NestedChildrenValidationData = nestedChildrenValidationDataVar,
 | |
|                                                                      RootLevelValidationData = rootValidationDataVar
 | |
|                                                                 },
 | |
|                                                                 Message = new InArgument<string>(ExecutionStringManager.InteropBodyNestedPersistOnCloseWithinTransactionScope)
 | |
|                                                             },
 | |
| 
 | |
|                                                         }
 | |
|                                                     },
 | |
|                                                 },
 | |
|                                             }
 | |
|                                         }                                   
 | |
|                                     }
 | |
|                                 },
 | |
|                                 new ActivityTreeValidation()
 | |
|                                 {
 | |
|                                     Interop = element
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         class ActivityTreeValidation : NativeActivity
 | |
|         {
 | |
|             public ActivityTreeValidation()
 | |
|             {
 | |
|             }
 | |
| 
 | |
|             public InArgument<Interop> Interop
 | |
|             {
 | |
|                 get;
 | |
|                 set;
 | |
|             }
 | |
| 
 | |
|             protected override void Execute(NativeActivityContext context)
 | |
|             {
 | |
|                 Interop interop = this.Interop.Get(context);
 | |
| 
 | |
|                 if (interop == null)
 | |
|                 {
 | |
|                     return;
 | |
|                 }
 | |
| 
 | |
|                 if (!typeof(System.Workflow.ComponentModel.Activity).IsAssignableFrom(interop.ActivityType))
 | |
|                 {
 | |
|                     return;
 | |
|                 }
 | |
| 
 | |
|                 System.ComponentModel.Design.ServiceContainer container = new System.ComponentModel.Design.ServiceContainer();
 | |
|                 container.AddService(typeof(ITypeProvider), CreateTypeProvider(interop.ActivityType));
 | |
|                 ValidationManager manager = new ValidationManager(container);
 | |
| 
 | |
|                 System.Workflow.ComponentModel.Activity interopBody = interop.ComponentModelActivity;
 | |
|                 using (WorkflowCompilationContext.CreateScope(manager))
 | |
|                 {
 | |
|                     foreach (Validator validator in manager.GetValidators(interop.ActivityType))
 | |
|                     {
 | |
|                         ValidationErrorCollection errors = validator.Validate(manager, interopBody);
 | |
|                         foreach (System.Workflow.ComponentModel.Compiler.ValidationError error in errors)
 | |
|                         {
 | |
|                             Constraint.AddValidationError(context, new ValidationError(error.ErrorText, error.IsWarning, error.PropertyName));
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             static TypeProvider CreateTypeProvider(Type rootType)
 | |
|             {
 | |
|                 TypeProvider typeProvider = new TypeProvider(null);
 | |
| 
 | |
|                 typeProvider.SetLocalAssembly(rootType.Assembly);
 | |
|                 typeProvider.AddAssembly(rootType.Assembly);
 | |
| 
 | |
|                 foreach (AssemblyName assemblyName in rootType.Assembly.GetReferencedAssemblies())
 | |
|                 {
 | |
|                     Assembly referencedAssembly = null;
 | |
|                     try
 | |
|                     {
 | |
|                         referencedAssembly = Assembly.Load(assemblyName);
 | |
|                         if (referencedAssembly != null)
 | |
|                             typeProvider.AddAssembly(referencedAssembly);
 | |
|                     }
 | |
|                     catch
 | |
|                     {
 | |
|                     }
 | |
| 
 | |
|                     if (referencedAssembly == null && assemblyName.CodeBase != null)
 | |
|                         typeProvider.AddAssemblyReference(assemblyName.CodeBase);
 | |
|                 }
 | |
| 
 | |
|                 return typeProvider;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         class CheckForTransactionScope : CodeActivity<bool>
 | |
|         {
 | |
|             public InArgument<HashSet<InteropValidationEnum>> ValidationResults
 | |
|             {
 | |
|                 get;
 | |
|                 set;
 | |
|             }
 | |
| 
 | |
|             protected override bool Execute(CodeActivityContext context)
 | |
|             {
 | |
|                 HashSet<InteropValidationEnum> validationResults = this.ValidationResults.Get(context);
 | |
|                 if (validationResults.Contains(InteropValidationEnum.TransactionScope))
 | |
|                 {
 | |
|                     return false;
 | |
|                 }
 | |
| 
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         class CheckForPersistOnClose : CodeActivity<bool>
 | |
|         {
 | |
|             public InArgument<HashSet<InteropValidationEnum>> NestedChildrenValidationData
 | |
|             {
 | |
|                 get;
 | |
|                 set;
 | |
|             }
 | |
| 
 | |
|             public InArgument<HashSet<InteropValidationEnum>> RootLevelValidationData
 | |
|             {
 | |
|                 get;
 | |
|                 set;
 | |
|             }
 | |
| 
 | |
|             protected override bool Execute(CodeActivityContext context)
 | |
|             {
 | |
|                 HashSet<InteropValidationEnum> nestedValidationData = this.NestedChildrenValidationData.Get(context);
 | |
|                 HashSet<InteropValidationEnum> rootValidationData = this.RootLevelValidationData.Get(context);
 | |
| 
 | |
|                 if (nestedValidationData.Contains(InteropValidationEnum.PersistOnClose) || rootValidationData.Contains(InteropValidationEnum.PersistOnClose))
 | |
|                 {
 | |
|                     return false;
 | |
|                 }
 | |
| 
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         class ValidateAtRootAndNestedLevels : NativeActivity
 | |
|         {
 | |
|             public ValidateAtRootAndNestedLevels()
 | |
|             {
 | |
|             }
 | |
| 
 | |
|             public InArgument<Interop> Interop
 | |
|             {
 | |
|                 get;
 | |
|                 set;
 | |
|             }
 | |
| 
 | |
|             public InArgument<HashSet<InteropValidationEnum>> RootLevelValidationData
 | |
|             {
 | |
|                 get;
 | |
|                 set;
 | |
|             }
 | |
| 
 | |
|             public InArgument<HashSet<InteropValidationEnum>> NestedChildrenValidationData
 | |
|             {
 | |
|                 get;
 | |
|                 set;
 | |
|             }
 | |
| 
 | |
|             protected override void Execute(NativeActivityContext context)
 | |
|             {
 | |
|                 Interop activity = this.Interop.Get(context);
 | |
| 
 | |
|                 foreach (InteropValidationEnum validationEnum in this.RootLevelValidationData.Get(context))
 | |
|                 {
 | |
|                     //We care to mark PersistOnClose during the walking algorithm because we need to check if it happens under a 4.0 TransactionScopActivity and flag that
 | |
|                     //That is done later, so skip here. 
 | |
|                     if (validationEnum != InteropValidationEnum.PersistOnClose)
 | |
|                     {
 | |
|                         string message = string.Format(CultureInfo.CurrentCulture, ExecutionStringManager.InteropBodyRootLevelViolation, activity.DisplayName, validationEnum.ToString() + "Activity");
 | |
|                         Constraint.AddValidationError(context, new ValidationError(message));
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 foreach (InteropValidationEnum validationEnum in this.NestedChildrenValidationData.Get(context))
 | |
|                 {
 | |
|                     //We care to mark PersistOnClose or TransactionScope during the walking algorithm because we need to check if it happens under a 4.0 TransactionScopActivity and flag that
 | |
|                     //That is done later, so skip here. 
 | |
|                     if ((validationEnum != InteropValidationEnum.PersistOnClose) && (validationEnum != InteropValidationEnum.TransactionScope))
 | |
|                     {
 | |
|                         string message = string.Format(CultureInfo.CurrentCulture, ExecutionStringManager.InteropBodyNestedViolation, activity.DisplayName, validationEnum.ToString() + "Activity");
 | |
|                         Constraint.AddValidationError(context, new ValidationError(message));
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         class WalkInteropBodyAndGatherData : System.Activities.CodeActivity
 | |
|         {
 | |
|             public InArgument<Interop> InteropActivity
 | |
|             {
 | |
|                 get;
 | |
|                 set;
 | |
|             }
 | |
| 
 | |
|             public InArgument<HashSet<InteropValidationEnum>> RootLevelValidationData
 | |
|             {
 | |
|                 get;
 | |
|                 set;
 | |
|             }
 | |
| 
 | |
|             public InArgument<HashSet<InteropValidationEnum>> NestedChildrenValidationData
 | |
|             {
 | |
|                 get;
 | |
|                 set;
 | |
|             }
 | |
| 
 | |
|             protected override void Execute(CodeActivityContext context)
 | |
|             {
 | |
|                 Interop interop = this.InteropActivity.Get(context);
 | |
|                 Debug.Assert(interop != null, "Interop activity is null");
 | |
| 
 | |
|                 Debug.Assert(interop.hasValidBody, "Interop activity has an invalid body");
 | |
| 
 | |
|                 System.Workflow.ComponentModel.Activity interopBody = interop.ComponentModelActivity;
 | |
|                 Debug.Assert(interopBody != null, "Interop Body was null");
 | |
| 
 | |
|                 HashSet<InteropValidationEnum> validationResults;
 | |
|                 validationResults = this.RootLevelValidationData.Get(context);
 | |
|                 Debug.Assert(validationResults != null, "The RootLevelValidationData hash set was null");
 | |
| 
 | |
|                 //Gather data at root level first
 | |
|                 ProcessAtRootLevel(interopBody, validationResults);
 | |
| 
 | |
|                 validationResults = null;
 | |
|                 validationResults = this.NestedChildrenValidationData.Get(context);
 | |
|                 Debug.Assert(validationResults != null, "The NestedChildrenValidationData hash set was null");
 | |
| 
 | |
|                 //Next, process nested children of the Body
 | |
|                 if (interopBody is System.Workflow.ComponentModel.CompositeActivity)
 | |
|                 {
 | |
|                     ProcessNestedChildren(interopBody, validationResults);
 | |
|                 }
 | |
| 
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             void ProcessAtRootLevel(System.Workflow.ComponentModel.Activity interopBody, HashSet<InteropValidationEnum> validationResults)
 | |
|             {
 | |
|                 Debug.Assert(interopBody != null, "Interop Body is null");
 | |
|                 Debug.Assert(validationResults != null, "The HashSet of validation results is null");
 | |
| 
 | |
|                 if (interopBody.PersistOnClose)
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.PersistOnClose);
 | |
|                 }
 | |
| 
 | |
|                 Type interopBodyType = interopBody.GetType();
 | |
|                 if (interopBodyType == typeof(System.Workflow.ComponentModel.TransactionScopeActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.TransactionScope);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.CodeActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.Code);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.DelayActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.Delay);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.InvokeWebServiceActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.InvokeWebService);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.InvokeWorkflowActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.InvokeWorkflow);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.PolicyActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.Policy);
 | |
|                 }
 | |
|                 else if (interopBodyType.FullName == "System.Workflow.Activities.SendActivity")
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.Send);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.SetStateActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.SetState);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.WebServiceFaultActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.WebServiceFault);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.WebServiceInputActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.WebServiceInput);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.WebServiceOutputActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.WebServiceOutput);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.ComponentModel.CompensateActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.Compensate);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.ComponentModel.SuspendActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.Suspend);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.ComponentModel.TerminateActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.Terminate);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.ComponentModel.ThrowActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.Throw);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.ConditionedActivityGroup))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.ConditionedActivityGroup);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.EventHandlersActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.EventHandlers);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.EventHandlingScopeActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.EventHandlingScope);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.IfElseActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.IfElse);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.ListenActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.Listen);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.ParallelActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.Parallel);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.ReplicatorActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.Replicator);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.SequenceActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.Sequence);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.CompensatableSequenceActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.CompensatableSequence);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.EventDrivenActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.EventDriven);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.IfElseBranchActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.IfElseBranch);
 | |
|                 }
 | |
|                 else if (interopBodyType.FullName == "System.Workflow.Activities.ReceiveActivity")
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.Receive);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.SequentialWorkflowActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.SequentialWorkflow);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.StateFinalizationActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.StateFinalization);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.StateInitializationActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.StateInitialization);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.StateActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.State);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.StateMachineWorkflowActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.StateMachineWorkflow);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.Activities.WhileActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.While);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.ComponentModel.CancellationHandlerActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.CancellationHandler);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.ComponentModel.CompensatableTransactionScopeActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.CompensatableTransactionScope);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.ComponentModel.CompensationHandlerActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.CompensationHandler);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.ComponentModel.FaultHandlerActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.FaultHandler);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.ComponentModel.FaultHandlersActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.FaultHandlers);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.ComponentModel.SynchronizationScopeActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.SynchronizationScope);
 | |
|                 }
 | |
|                 else if (interopBodyType == typeof(System.Workflow.ComponentModel.ICompensatableActivity))
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.ICompensatable);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             void ProcessNestedChildren(System.Workflow.ComponentModel.Activity interopBody, HashSet<InteropValidationEnum> validationResults)
 | |
|             {
 | |
|                 Debug.Assert(interopBody != null, "Interop Body is null");
 | |
|                 Debug.Assert(validationResults != null, "The HashSet of validation results is null");
 | |
|                 bool persistOnClose = false;
 | |
| 
 | |
|                 foreach (System.Workflow.ComponentModel.Activity activity in interopBody.CollectNestedActivities())
 | |
|                 {
 | |
|                     if (activity.PersistOnClose)
 | |
|                     {
 | |
|                         persistOnClose = true;
 | |
|                     }
 | |
| 
 | |
|                     if (activity is System.Workflow.ComponentModel.TransactionScopeActivity)
 | |
|                     {
 | |
|                         validationResults.Add(InteropValidationEnum.TransactionScope);
 | |
|                     }
 | |
|                     else if (activity is System.Workflow.Activities.InvokeWorkflowActivity)
 | |
|                     {
 | |
|                         validationResults.Add(InteropValidationEnum.InvokeWorkflow);
 | |
|                     }
 | |
|                     // SendActivity is sealed
 | |
|                     else if (activity.GetType().FullName == "System.Workflow.Activities.SendActivity")
 | |
|                     {
 | |
|                         validationResults.Add(InteropValidationEnum.Send);
 | |
|                     }
 | |
|                     else if (activity is System.Workflow.Activities.WebServiceFaultActivity)
 | |
|                     {
 | |
|                         validationResults.Add(InteropValidationEnum.WebServiceFault);
 | |
|                     }
 | |
|                     else if (activity is System.Workflow.Activities.WebServiceInputActivity)
 | |
|                     {
 | |
|                         validationResults.Add(InteropValidationEnum.WebServiceInput);
 | |
|                     }
 | |
|                     else if (activity is System.Workflow.Activities.WebServiceOutputActivity)
 | |
|                     {
 | |
|                         validationResults.Add(InteropValidationEnum.WebServiceOutput);
 | |
|                     }
 | |
|                     else if (activity is System.Workflow.ComponentModel.CompensateActivity)
 | |
|                     {
 | |
|                         validationResults.Add(InteropValidationEnum.Compensate);
 | |
|                     }
 | |
|                     else if (activity is System.Workflow.ComponentModel.SuspendActivity)
 | |
|                     {
 | |
|                         validationResults.Add(InteropValidationEnum.Suspend);
 | |
|                     }
 | |
|                     else if (activity is System.Workflow.Activities.CompensatableSequenceActivity)
 | |
|                     {
 | |
|                         validationResults.Add(InteropValidationEnum.CompensatableSequence);
 | |
|                     }
 | |
|                     // ReceiveActivity is sealed
 | |
|                     else if (activity.GetType().FullName == "System.Workflow.Activities.ReceiveActivity")
 | |
|                     {
 | |
|                         validationResults.Add(InteropValidationEnum.Receive);
 | |
|                     }
 | |
|                     else if (activity is System.Workflow.ComponentModel.CompensatableTransactionScopeActivity)
 | |
|                     {
 | |
|                         validationResults.Add(InteropValidationEnum.CompensatableTransactionScope);
 | |
|                     }
 | |
|                     else if (activity is System.Workflow.ComponentModel.CompensationHandlerActivity)
 | |
|                     {
 | |
|                         validationResults.Add(InteropValidationEnum.CompensationHandler);
 | |
|                     }
 | |
|                     else if (activity is System.Workflow.ComponentModel.ICompensatableActivity)
 | |
|                     {
 | |
|                         validationResults.Add(InteropValidationEnum.ICompensatable);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (persistOnClose)
 | |
|                 {
 | |
|                     validationResults.Add(InteropValidationEnum.PersistOnClose);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         //This needs to be in [....] with the table in the spec
 | |
|         //We use this internally to keep a hashset of validation data
 | |
|         enum InteropValidationEnum
 | |
|         {
 | |
|             Code,
 | |
|             Delay,
 | |
|             InvokeWebService,
 | |
|             InvokeWorkflow,
 | |
|             Policy,
 | |
|             Send,
 | |
|             SetState,
 | |
|             WebServiceFault,
 | |
|             WebServiceInput,
 | |
|             WebServiceOutput,
 | |
|             Compensate,
 | |
|             Suspend,
 | |
|             ConditionedActivityGroup,
 | |
|             EventHandlers,
 | |
|             EventHandlingScope,
 | |
|             IfElse,
 | |
|             Listen,
 | |
|             Parallel,
 | |
|             Replicator,
 | |
|             Sequence,
 | |
|             CompensatableSequence,
 | |
|             EventDriven,
 | |
|             IfElseBranch,
 | |
|             Receive,
 | |
|             SequentialWorkflow,
 | |
|             StateFinalization,
 | |
|             StateInitialization,
 | |
|             State,
 | |
|             StateMachineWorkflow,
 | |
|             While,
 | |
|             CancellationHandler,
 | |
|             CompensatableTransactionScope,
 | |
|             CompensationHandler,
 | |
|             FaultHandler,
 | |
|             FaultHandlers,
 | |
|             SynchronizationScope,
 | |
|             TransactionScope,
 | |
|             ICompensatable,
 | |
|             PersistOnClose,
 | |
|             Terminate,
 | |
|             Throw
 | |
|         }
 | |
| 
 | |
|         class ObtainType : CodeActivity<Type>
 | |
|         {
 | |
|             public ObtainType()
 | |
|             {
 | |
|             }
 | |
| 
 | |
|             public InArgument<Activity> Input
 | |
|             {
 | |
|                 get;
 | |
|                 set;
 | |
|             }
 | |
| 
 | |
|             protected override Type Execute(CodeActivityContext context)
 | |
|             {
 | |
|                 return this.Input.Get(context).GetType();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         abstract class InteropProperty : PropertyDescriptor
 | |
|         {
 | |
|             Interop owner;
 | |
|             bool isValid;
 | |
| 
 | |
|             public InteropProperty(Interop owner, string name, Attribute[] propertyInfoAttributes)
 | |
|                 : base(name, propertyInfoAttributes)
 | |
|             {
 | |
|                 this.owner = owner;
 | |
|                 this.isValid = true;
 | |
|             }
 | |
| 
 | |
|             public override Type ComponentType
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     ThrowIfInvalid();
 | |
|                     return this.owner.GetType();
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             protected internal Interop Owner
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     return this.owner;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public override bool CanResetValue(object component)
 | |
|             {
 | |
|                 ThrowIfInvalid();
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             public override void ResetValue(object component)
 | |
|             {
 | |
|                 ThrowIfInvalid();
 | |
|             }
 | |
| 
 | |
|             public override bool ShouldSerializeValue(object component)
 | |
|             {
 | |
|                 ThrowIfInvalid();
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             protected void ThrowIfInvalid()
 | |
|             {
 | |
|                 if (!this.isValid)
 | |
|                 {
 | |
|                     throw new InvalidOperationException(ExecutionStringManager.InteropInvalidPropertyDescriptor);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             internal void Invalidate()
 | |
|             {
 | |
|                 this.isValid = false;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         class ArgumentProperty : InteropProperty
 | |
|         {
 | |
|             string argumentName;
 | |
|             Argument argument;
 | |
| 
 | |
|             public ArgumentProperty(Interop owner, string argumentName, Argument argument, Attribute[] attributes)
 | |
|                 : base(owner, argumentName, attributes)
 | |
|             {
 | |
|                 this.argumentName = argumentName;
 | |
|                 this.argument = argument;
 | |
|             }
 | |
| 
 | |
|             public override bool IsReadOnly
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     ThrowIfInvalid();
 | |
|                     return false;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public override Type PropertyType
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     ThrowIfInvalid();
 | |
|                     return GetArgument().GetType();
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public override object GetValue(object component)
 | |
|             {
 | |
|                 ThrowIfInvalid();
 | |
|                 return GetArgument();
 | |
|             }
 | |
| 
 | |
|             public override void SetValue(object component, object value)
 | |
|             {
 | |
|                 ThrowIfInvalid();
 | |
|                 if (value != null)
 | |
|                 {
 | |
|                     this.Owner.ActivityProperties[this.argumentName] = (Argument)value;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     this.Owner.ActivityProperties.Remove(this.argumentName);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             Argument GetArgument()
 | |
|             {
 | |
|                 Argument argument;
 | |
|                 if (!this.Owner.ActivityProperties.TryGetValue(this.argumentName, out argument))
 | |
|                 {
 | |
|                     argument = this.argument;
 | |
|                 }
 | |
|                 return argument;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         class LiteralProperty : InteropProperty
 | |
|         {
 | |
|             string literalName;
 | |
|             Type literalType;
 | |
| 
 | |
|             public LiteralProperty(Interop owner, string literalName, Type literalType, Attribute[] attributes)
 | |
|                 : base(owner, literalName, attributes)
 | |
|             {
 | |
|                 this.literalName = literalName;
 | |
|                 this.literalType = literalType;
 | |
|             }
 | |
| 
 | |
|             public override bool IsReadOnly
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     ThrowIfInvalid();
 | |
|                     return false;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public override Type PropertyType
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     ThrowIfInvalid();
 | |
|                     return this.literalType;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public override object GetValue(object component)
 | |
|             {
 | |
|                 ThrowIfInvalid();
 | |
|                 return GetLiteral();
 | |
|             }
 | |
| 
 | |
|             public override void SetValue(object component, object value)
 | |
|             {
 | |
|                 ThrowIfInvalid();
 | |
|                 this.Owner.ActivityMetaProperties[this.literalName] = value;
 | |
|             }
 | |
| 
 | |
|             object GetLiteral()
 | |
|             {
 | |
|                 object literal;
 | |
|                 if (this.Owner.ActivityMetaProperties.TryGetValue(this.literalName, out literal))
 | |
|                 {
 | |
|                     return literal;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     return null;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         class InteropPersistenceParticipant : PersistenceIOParticipant
 | |
|         {
 | |
|             public InteropPersistenceParticipant()
 | |
|                 : base(true, false)
 | |
|             {
 | |
|                 this.ResourceManagers = new Dictionary<string, VolatileResourceManager>();
 | |
|                 this.CommittedResourceManagers = new Dictionary<Transaction, Dictionary<string, VolatileResourceManager>>();
 | |
|             }
 | |
| 
 | |
|             Dictionary<string, VolatileResourceManager> ResourceManagers
 | |
|             {
 | |
|                 get;
 | |
|                 set;
 | |
|             }
 | |
| 
 | |
|             Dictionary<Transaction, Dictionary<string, VolatileResourceManager>> CommittedResourceManagers
 | |
|             {
 | |
|                 get;
 | |
|                 set;
 | |
|             }
 | |
| 
 | |
|             protected override IAsyncResult BeginOnSave(IDictionary<XName, object> readWriteValues, IDictionary<System.Xml.Linq.XName, object> writeOnlyValues, TimeSpan timeout, AsyncCallback callback, object state)
 | |
|             {
 | |
|                 try
 | |
|                 {
 | |
|                     foreach (VolatileResourceManager rm in this.ResourceManagers.Values)
 | |
|                     {
 | |
|                         rm.Commit();
 | |
|                     }
 | |
|                 }
 | |
|                 finally
 | |
|                 {
 | |
|                     this.CommittedResourceManagers.Add(Transaction.Current, this.ResourceManagers);
 | |
|                     this.ResourceManagers = new Dictionary<string, VolatileResourceManager>();
 | |
|                     Transaction.Current.TransactionCompleted += new TransactionCompletedEventHandler(Current_TransactionCompleted);
 | |
|                 }
 | |
| 
 | |
|                 return new CompletedAsyncResult(callback, state);
 | |
|             }
 | |
| 
 | |
|             protected override void EndOnSave(IAsyncResult result)
 | |
|             {
 | |
|                 CompletedAsyncResult.End(result);
 | |
|             }
 | |
| 
 | |
|             void Current_TransactionCompleted(object sender, TransactionEventArgs e)
 | |
|             {
 | |
|                 if (e.Transaction.TransactionInformation.Status == TransactionStatus.Committed)
 | |
|                 {
 | |
|                     foreach (VolatileResourceManager rm in this.CommittedResourceManagers[e.Transaction].Values)
 | |
|                     {
 | |
|                         rm.Complete();
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     foreach (VolatileResourceManager rm in this.CommittedResourceManagers[e.Transaction].Values)
 | |
|                     {
 | |
|                         rm.ClearAllBatchedWork();
 | |
|                     }
 | |
|                 }
 | |
|                 this.CommittedResourceManagers.Remove(e.Transaction);
 | |
|             }
 | |
| 
 | |
|             protected override void Abort()
 | |
|             {
 | |
|                 foreach (VolatileResourceManager rm in this.ResourceManagers.Values)
 | |
|                 {
 | |
|                     rm.ClearAllBatchedWork();
 | |
|                 }
 | |
| 
 | |
|                 this.ResourceManagers = new Dictionary<string, VolatileResourceManager>();
 | |
|             }
 | |
| 
 | |
|             internal void Add(string activityId, VolatileResourceManager rm)
 | |
|             {
 | |
|                 // Add and OnSave shouldn't be called at the same time.  A lock isn't needed here.
 | |
|                 this.ResourceManagers.Add(activityId, rm);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         [DataContract]
 | |
|         class InteropEnlistment : IEnlistmentNotification
 | |
|         {
 | |
|             VolatileResourceManager resourceManager;
 | |
|             Transaction transaction;
 | |
| 
 | |
|             public InteropEnlistment()
 | |
|             {
 | |
|             }
 | |
| 
 | |
|             public InteropEnlistment(Transaction transaction, VolatileResourceManager resourceManager)
 | |
|             {
 | |
|                 this.resourceManager = resourceManager;
 | |
|                 this.transaction = transaction;
 | |
|                 this.IsValid = true;
 | |
|             }
 | |
| 
 | |
|             public bool IsValid { get; set; }
 | |
| 
 | |
|             public void Commit(Enlistment enlistment)
 | |
|             {
 | |
|                 this.resourceManager.Complete();
 | |
|                 enlistment.Done();
 | |
|             }
 | |
| 
 | |
|             public void InDoubt(Enlistment enlistment)
 | |
|             {
 | |
|                 // Following the WF3 runtime behavior - Aborting during InDoubt
 | |
|                 this.Rollback(enlistment);
 | |
|             }
 | |
| 
 | |
|             public void Prepare(PreparingEnlistment preparingEnlistment)
 | |
|             {
 | |
|                 using (System.Transactions.TransactionScope ts = new System.Transactions.TransactionScope(this.transaction))
 | |
|                 {
 | |
|                     this.resourceManager.Commit();
 | |
|                     ts.Complete();
 | |
|                 }
 | |
|                 preparingEnlistment.Prepared();
 | |
|             }
 | |
| 
 | |
|             public void Rollback(Enlistment enlistment)
 | |
|             {
 | |
|                 this.resourceManager.ClearAllBatchedWork();
 | |
|                 enlistment.Done();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         class CompletedAsyncResult : IAsyncResult
 | |
|         {
 | |
|             AsyncCallback callback;
 | |
|             bool endCalled;
 | |
|             ManualResetEvent manualResetEvent;
 | |
|             object state;
 | |
|             object thisLock;
 | |
| 
 | |
|             public CompletedAsyncResult(AsyncCallback callback, object state)
 | |
|             {
 | |
|                 this.callback = callback;
 | |
|                 this.state = state;
 | |
|                 this.thisLock = new object();
 | |
| 
 | |
|                 if (callback != null)
 | |
|                 {
 | |
|                     try
 | |
|                     {
 | |
|                         callback(this);
 | |
|                     }
 | |
|                     catch (Exception e) // transfer to another thread, this is a fatal situation
 | |
|                     {
 | |
|                         throw new InvalidProgramException(ExecutionStringManager.AsyncCallbackThrewException, e);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public static void End(IAsyncResult result)
 | |
|             {
 | |
|                 if (result == null)
 | |
|                 {
 | |
|                     throw new ArgumentNullException("result");
 | |
|                 }
 | |
| 
 | |
|                 CompletedAsyncResult asyncResult = result as CompletedAsyncResult;
 | |
| 
 | |
|                 if (asyncResult == null)
 | |
|                 {
 | |
|                     throw new ArgumentException(ExecutionStringManager.InvalidAsyncResult, "result");
 | |
|                 }
 | |
| 
 | |
|                 if (asyncResult.endCalled)
 | |
|                 {
 | |
|                     throw new InvalidOperationException(ExecutionStringManager.EndCalledTwice);
 | |
|                 }
 | |
| 
 | |
|                 asyncResult.endCalled = true;
 | |
| 
 | |
|                 if (asyncResult.manualResetEvent != null)
 | |
|                 {
 | |
|                     asyncResult.manualResetEvent.Close();
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public object AsyncState
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     return state;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public WaitHandle AsyncWaitHandle
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     if (this.manualResetEvent != null)
 | |
|                     {
 | |
|                         return this.manualResetEvent;
 | |
|                     }
 | |
| 
 | |
|                     lock (ThisLock)
 | |
|                     {
 | |
|                         if (this.manualResetEvent == null)
 | |
|                         {
 | |
|                             this.manualResetEvent = new ManualResetEvent(true);
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     return this.manualResetEvent;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public bool CompletedSynchronously
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     return true;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             public bool IsCompleted
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     return true;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             object ThisLock
 | |
|             {
 | |
|                 get
 | |
|                 {
 | |
|                     return this.thisLock;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |