2016-08-03 10:59:49 +00:00
//----------------------------------------------------------------
// 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 ) ;
}
}
}
2017-08-21 15:34:15 +00:00
//This needs to be in sync with the table in the spec
2016-08-03 10:59:49 +00:00
//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 ;
}
}
}
}
}