Windows Workflow Foundation 3


Rule Conditions against custom activities and XAML activation - how should I achieve this?


If I have a simple custom activity and I generate a XAML only workflow with a rule condition that references the activity then how can I use XAML activation to execute the workflow?
Here's the workflow
<SequentialWorkflowActivity x:Name="xyz" xmlns:ns0="clr-namespace:ABC.Workflow.Common.ActivityLibrary;Assembly=ABC.Workflow.Common.ActivityLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
<ns0:ConsoleWritelineActivity Message="test" x:Name="consoleWritelineActivity1" />
<IfElseActivity x:Name="ifElseActivity1"> <IfElseBranchActivity x:Name="ifElseBranchActivity1"> <IfElseBranchActivity.Condition> <RuleConditionReference ConditionName="isATest" /> </IfElseBranchActivity.Condition> </IfElseBranchActivity> <IfElseBranchActivity x:Name="ifElseBranchActivity2" /> </IfElseActivity>
</SequentialWorkflowActivity>
I am using XAML activation to execute the workflow, catching WorkflowValidationFailedException, and have added the custom activity's assembly to a type provider thus, (which is inadequate, I suspect),
TypeProvider typeProvider = new TypeProvider(workflowRuntime);typeProvider.AddAssembly(typeof(ConsoleWritelineActivity).Assembly);workflowRuntime.AddService(typeProvider);
My workflow gets terminated with this message
Unable to validate Condition \"isATest\" as there are validation errors
if the rule is (this.consoleWritelineActivity1.Message == "test")
i.e.
<RuleDefinitions xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow"> <RuleDefinitions.Conditions> <RuleExpressionCondition Name="isATest"> <RuleExpressionCondition.Expression> <ns0:CodeBinaryOperatorExpression Operator="ValueEquality" xmlns:ns0="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <ns0:CodeBinaryOperatorExpression.Left> <ns0:CodePropertyReferenceExpression PropertyName="Message"> <ns0:CodePropertyReferenceExpression.TargetObject> <ns0:CodeFieldReferenceExpression FieldName="consoleWritelineActivity1"> <ns0:CodeFieldReferenceExpression.TargetObject> <ns0:CodeThisReferenceExpression /> </ns0:CodeFieldReferenceExpression.TargetObject> </ns0:CodeFieldReferenceExpression> </ns0:CodePropertyReferenceExpression.TargetObject> </ns0:CodePropertyReferenceExpression> </ns0:CodeBinaryOperatorExpression.Left> <ns0:CodeBinaryOperatorExpression.Right> <ns0:CodePrimitiveExpression> <ns0:CodePrimitiveExpression.Value> <ns1:String xmlns:ns1="clr-namespace:System;Assembly=mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">test</ns1:String> </ns0:CodePrimitiveExpression.Value> </ns0:CodePrimitiveExpression> </ns0:CodeBinaryOperatorExpression.Right> </ns0:CodeBinaryOperatorExpression> </RuleExpressionCondition.Expression> </RuleExpressionCondition> </RuleDefinitions.Conditions></RuleDefinitions>
and my workflow gets terminated with this message
An item with the same key has already been added
if the rule is (((ABC.Workflow.Common.ActivityLibrary.ConsoleWritelineActivity)this.GetActivityByName("consoleWritelineActivity")).Message == "test")
i.e.
<RuleDefinitions xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow"> <RuleDefinitions.Conditions> <RuleExpressionCondition Name="isATest"> <RuleExpressionCondition.Expression> <ns0:CodeBinaryOperatorExpression Operator="ValueEquality" xmlns:ns0="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <ns0:CodeBinaryOperatorExpression.Left> <ns0:CodePropertyReferenceExpression PropertyName="Message"> <ns0:CodePropertyReferenceExpression.TargetObject> <ns0:CodeCastExpression> <ns0:CodeCastExpression.Expression> <ns0:CodeMethodInvokeExpression> <ns0:CodeMethodInvokeExpression.Parameters> <ns0:CodePrimitiveExpression> <ns0:CodePrimitiveExpression.Value> <ns1:String xmlns:ns1="clr-namespace:System;Assembly=mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">consoleWritelineActivity</ns1:String> </ns0:CodePrimitiveExpression.Value> </ns0:CodePrimitiveExpression> </ns0:CodeMethodInvokeExpression.Parameters> <ns0:CodeMethodInvokeExpression.Method> <ns0:CodeMethodReferenceExpression MethodName="GetActivityByName"> <ns0:CodeMethodReferenceExpression.TargetObject> <ns0:CodeThisReferenceExpression /> </ns0:CodeMethodReferenceExpression.TargetObject> </ns0:CodeMethodReferenceExpression> </ns0:CodeMethodInvokeExpression.Method> </ns0:CodeMethodInvokeExpression> </ns0:CodeCastExpression.Expression> <ns0:CodeCastExpression.TargetType> <ns0:CodeTypeReference ArrayElementType="{p11:Null}" BaseType="ABC.Workflow.Common.ActivityLibrary.ConsoleWritelineActivity" Options="0" ArrayRank="0" xmlns:p11="http://schemas.microsoft.com/winfx/2006/xaml" /> </ns0:CodeCastExpression.TargetType> </ns0:CodeCastExpression> </ns0:CodePropertyReferenceExpression.TargetObject> </ns0:CodePropertyReferenceExpression> </ns0:CodeBinaryOperatorExpression.Left> <ns0:CodeBinaryOperatorExpression.Right> <ns0:CodePrimitiveExpression> <ns0:CodePrimitiveExpression.Value> <ns1:String xmlns:ns1="clr-namespace:System;Assembly=mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">test</ns1:String> </ns0:CodePrimitiveExpression.Value> </ns0:CodePrimitiveExpression> </ns0:CodeBinaryOperatorExpression.Right> </ns0:CodeBinaryOperatorExpression> </RuleExpressionCondition.Expression> </RuleExpressionCondition> </RuleDefinitions.Conditions></RuleDefinitions>
In a code only workflow there is a private variable created for each activity added to the workflow allowing you to do this.activityName to access the activities in the workflow, this will only work for code only workflows.  When you are working with xoml workflow, code separation or xoml only, you need to use GetActivityByName to have access to the activity since no variables are created. 
 
Which build are you using?  Can you post the StackTrace for the “An item with the same key has already been added” exception you are getting when you use GetActivityByName?
Writing a special type provider will not work.  The variables don't exist in the workflow so there is nothing to resolve.  A type provider is use to resolve types not variables.  This is a known issue with using XAML activation that will not be fixed in V1.  We are looking into make it easier in a future version.
Go with your second option since "this" is going to refer to a sequential workflow activity and not a new workflow type. 
In order to get this to work, you need to edit one line of your rules file in order to qualify the type name.  What is happening is that the rule validation code is not finding your type in the referenced assembly so it is trying to add it into the collection. 
Change this:
<ns0:CodeTypeReference ArrayElementType="{p11:Null}" BaseType="ABC.Workflow.Common.ActivityLibrary.ConsoleWritelineActivity" Options="0" ArrayRank="0" xmlns:p11="http://schemas.microsoft.com/winfx/2006/xaml" />
to this (Assuming an assembly name of ABC.Workflow.Common.ActivityLibrary):
<ns0:CodeTypeReference ArrayElementType="{p11:Null}" BaseType="ABC.Workflow.Common.ActivityLibrary.ConsoleWritelineActivity,ABC.Workflow.Common.ActivityLibrary" Options="0" ArrayRank="0" xmlns:p11="http://schemas.microsoft.com/winfx/2006/xaml" />
This should work for you. 
Matt
Thanks Matt.
Editing the rules xaml moves me onto another error "Cannot evaluate property \"Message\" because its target object is null".
Ignoring that, for the moment, I have two other issues.
1. This xaml was serialized by my rehosted designer control which obviously knew enough about the activity in order to sucessfully create the rule. Not sure why this would be wrong.
2. I want the first style of rule because the second is too complex for customers who are going to be editing our xoml workflows. Can you set me on the right track to get this working? (I guess that I may still have an issue with the rules xaml generated by the designer, but that's another problem).
The problem is that when you are editing a default XOML workflow, "this" points to the type SequentialWorkflowActivity.  This type does not have any properties, nor can you get typed access to the child activities directly, as the XOML has no "fields" defined which point to those activities. I haven't dug into the rules editor in much detail yet, but it seems very code/type focused so you might run into some problems there when trying to write rules for XOML workflows. 
One solution is to create a base workflow type that derives from the sequential type and then build your XOML workflows for this type.  Then you can have methods on your base type that will help people build rules like a method that makes it easy to reference child activities. 
As for your item 1, when I did this my XOML was created from the VS hosted designer, but it still didn't work until I put the assembly name in there.  I'm not sure if this is technically a bug but it causes problems. 
Matt
In a code only workflow there is a private variable created for each activity added to the workflow allowing you to do this.activityName to access the activities in the workflow, this will only work for code only workflows.  When you are working with xoml workflow, code separation or xoml only, you need to use GetActivityByName to have access to the activity since no variables are created. 
 
Which build are you using?  Can you post the StackTrace for the “An item with the same key has already been added” exception you are getting when you use GetActivityByName?
Stack trace below. (using WinFx beta 2)
I believe, from other posts, that I can use the first approach but would have to write some kind of custom type provider. I cannot expect customers to write rules using GetActivityByName and casting etc. Unfortunately, I don't know how I should go about writing such a type provider. Can you help?
" at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)\r\n at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)\r\n at System.Workflow.Activities.Rules.SimpleRunTimeTypeProvider.get_RemainingAssemblies()\r\n at System.Workflow.Activities.Rules.SimpleRunTimeTypeProvider.GetType(String name, Boolean throwOnError)\r\n at System.Workflow.Activities.Rules.RuleValidation.FindType(String typeName)\r\n at System.Workflow.Activities.Rules.RuleValidation.ResolveType(CodeTypeReference typeRef)\r\n at System.Workflow.Activities.Rules.CastExpression.System.Workflow.Activities.Rules.IRuleExpression.Validate(RuleValidation validation, Boolean isWritten)\r\n at System.Workflow.Activities.Rules.RuleExpressionWalker.Validate(RuleValidation validation, CodeExpression expression, Boolean isWritten)\r\n at System.Workflow.Activities.Rules.PropertyReferenceExpression.System.Workflow.Activities.Rules.IRuleExpression.Validate(RuleValidation validation, Boolean isWritten)\r\n at System.Workflow.Activities.Rules.RuleExpressionWalker.Validate(RuleValidation validation, CodeExpression expression, Boolean isWritten)\r\n at System.Workflow.Activities.Rules.BinaryExpression.System.Workflow.Activities.Rules.IRuleExpression.Validate(RuleValidation validation, Boolean isWritten)\r\n at System.Workflow.Activities.Rules.RuleExpressionWalker.Validate(RuleValidation validation, CodeExpression expression, Boolean isWritten)\r\n at System.Workflow.Activities.Rules.RuleValidation.ValidateConditionExpression(CodeExpression expression)\r\n at System.Workflow.Activities.Rules.RuleExpressionCondition.Validate(RuleValidation validation)\r\n at System.Workflow.Activities.Rules.RuleConditionReference.Evaluate(Activity activity, IServiceProvider provider)\r\n at System.Workflow.Activities.IfElseActivity.Execute(ActivityExecutionContext executionContext)\r\n at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(T activity, ActivityExecutionContext executionContext)\r\n at System.Workflow.ComponentModel.CompositeActivityExecutor`1.Execute(T activity, ActivityExecutionContext executionContext)\r\n at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(Activity activity, ActivityExecutionContext executionContext)\r\n at System.Workflow.ComponentModel.ActivityExecutionFilter.Execute(Activity activity, ActivityExecutionContext executionContext)\r\n at System.Workflow.ComponentModel.FaultAndCancellationHandlingFilter.Execute(Activity activity, ActivityExecutionContext executionContext)\r\n at System.Workflow.ComponentModel.ActivityExecutorOperation.Run(IWorkflowCoreRuntime workflowCoreRuntime)\r\n at System.Workflow.Runtime.Scheduler.Run()"
Writing a special type provider will not work.  The variables don't exist in the workflow so there is nothing to resolve.  A type provider is use to resolve types not variables.  This is a known issue with using XAML activation that will not be fixed in V1.  We are looking into make it easier in a future version.

Related Links

missing method exception in CallExternalMethodActivity
Performance of runtime creation and execution rules in WF
Error in my WorkFlow (Response.Redirect)
Approving Multiple Records in one go..
Dynamic Update
The Executing event of all my SetStateActivity objects dont fire
Design guidance needed for WWF application
Custom pub/sub service for WF message correlation
Is there any event get fired when I changed the content in the workflow designer?
Subscription handler threw System.FormatException
How can I designate string[] field as returnValue for ReceiveActivity?
is the "workflows in memory" performance counter failing to be reset?
Creating a workflow dynamically
writing non-persistance data to Oracle from a workflow app
Is Workflow Foundation a good fit for multiple workflow processes
The workflow failed validation

Categories

MSDN
Windows and Windows ph...
Exchange Server
Unified Communications
Archive
Project
Cortana
Forums Issues (not pro...
Parallel Computing in ...
Visual F#
Visual Studio Tools fo...
Visual Studio Unit Tes...
Payouts and Reporting
Dev Center App
Windows Desktop Develo...
General Windows Deskto...
Application Security f...
Windows Desktop Search...
Windows Filtering Plat...
Windows Desktop SDK
Windows Desktop Ribbon...
Azure SQL Database
Azure Active Directory
Azure HDInsight
Azure Scripting and Co...
Azure Logic Apps
Azure IoT Hub
Azure Blockchain
Azure Time Series Insi...
Windows Workflow Found...
Claims based access pl...
Team Foundation Server...
WCF Data Services
Microsoft Translator H...
Visual Basic for Appli...
Small Basic
.NET Framework inside ...
SQL Server Setup & Upg...
SQL Server Distributed...
Standard 7: Tools
Standard 7: Misc
SQL Server 2012 Report...
SQL Server 2012 SQL To...
Windows Live Messenger...
Windows Live ID: Devel...
The Samsung Windows De...
Bing Maps WPF, WP7/8/8...
Windows File Sharing P...
Expression Design
Retired SharePoint Wor...
ADO.NET Entity Framewo...
ASMX Web Services and ...
Building Windows Store...
Core Coding Experience...
Feedback for Visual Ba...
Game Technologies: Dir...
HealthVault Data Types
LightSwitch in Visual ...
Network Quality of Ser...
Phoenix
Search Server: Federation
Software Transactional...
SQL Creation
SQL Server 2014 Data Q...
SQL Server 2014 High A...
SQL Server 2014 In-Mem...
SQL Server 2014 Integr...
Using Visual Round Tri...
Visual Basic Express E...
Visual Studio 2008 Exp...
Windows Live Search: D...
Building Windows Store...
Tools for Windows Stor...
Mango Update (Archived)
Expression Blend for W...
Kinect for Windows v2 SDK

Resources

Encrypt Message



code
soft
python
ios
c
html
jquery
cloud
mobile