Hi,
I'm in the process of trying to setup a demonstration application which shows an example of workflow and rules management. I need to basically setup a workflow, set some properties, then run the workflow from the designer. Part of this demo include the use of an IfElse activity and a Policy activity which link with the rules engine portions. I've trundled through the examples and the current samples get things about 75% of the way there, and I've probably gotten another 5-10% there by looking at the threads here, but I'm still stuck. Here is what's happening:
1. Create a new workflow
2. Drop an IfElseActivity on the design surface, throw in a couple MessageActivities for good measure, one on each branch.
3. Edit the condition on the first IfElse branch to attempt to utilize the rules/condition editor to set up the IfElse condition
4. Everything looks good, hit "Run", it saves things properly [I get the save dialog box, the .xoml file has the appropriate information in it], however, it then blows up saying that it can't find the reference to the rule/condition information that I setup through the dialog.
I'm thinking this has something to do with the fact that it's persisting that rule information somewhere else, does anyone know how to get these last pieces linked in. The PolicyActivity has the same problem, telling me that it can't find the associated RuleSet. Since this information is not persisted into the .xoml file, I have to assume it's needs to get written somewhere... any ideas
Thanks!

Workflow Designer Rules Support
wm_al
I've gotten seemingly a bit further on this, but I still can't get it to actually recognize the rules bits during the "Run" command. I've added RuleXoml/RuleXomlFile properties to the loader, and it looks like it is properly getting the rule information to an accompanying .rules file, but I'm thinking that the compilation process is somehow missing the information. I've tried just adding the .rules file to the call to Compile(), but that doesn't do it either.
What is interesting is that in the bin/ directory for my app, there is a '.rules' file which appears to be where the Rule Set/Condition editor is placing the rules by default, once I've Save()'d the ruleset a single time, it appears that it begins to update the appropriate file, so I'm not overly worried about that portion, but it would be nice to get this last piece working... somehow, there must be a way to get that rule file into the assembly so when the workflow executes, the Rule Sets/Conditions are found properly.
Any ideas
Thanks!
Michael Toner
houseofmusic
KalliMan
Which policy object are you using
Generally you will need to have a <wfname>.rules file associated with your WF for this to work - these are created by you, or by the designers when you add rule conditions.
If you are using the Policy object from the External Rules example (beta2) this expects to find a Rule Definition (several ruleset) within a SQL DB - you'll be getting connect string problems I'd imagine first.
Cheers,
Mick.
coastal skier
Add the following compiler options to either the wfc or the WorkflowCompiler (whichever you are using):
/resource:Workflow1.rules,WorkflowConsoleApplication1.Workflow1.rules
Thanks,
Vijay
Gentry
Hello,
I have some trouble for this question.
How can I get the my custom variable from the file that suffix is .xoml.cs in the rule condition editor
Thanks!
maman
Is there a way to reference the rules file from the xoml file. I am loading the xoml file (which references an assembly). I am able to change the xoml file without re-compiling the workflow. Now I want to change my rules xml file without having to recompile the Workflow, but the reference to the rules xml file is in the assembly. The assembly is referenced in the xoml. As a result, I can update the xoml file, but have to reset IIS to be able to updated the rules xml file. Is there a way to reference the rules file directly from the xoml file Below is the syntax for my xoml file:
------------------------------------------------------------------
<ns0:Activity1 x:Name="Activity12" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ns0="clr-namespace:WorkflowActivityLibrary1;Assembly=WorkflowActivityLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<CodeActivity x:Name="codeActivity33" ExecuteCode="{ActivityBind Name=Activity12, Path=codeActivity3_ExecuteCode}" />
<CodeActivity x:Name="codeActivity4" ExecuteCode="{ActivityBind Name=Activity12, Path=GetFullName}" />
<IfElseActivity x:Name="ifElseActivity1">
<IfElseBranchActivity x:Name="ifElseBranchActivity1">
<IfElseBranchActivity.Condition>
<RuleConditionReference ConditionName="Condition1" />
</IfElseBranchActivity.Condition>
<CodeActivity x:Name="codeActivity1" ExecuteCode="{ActivityBind Name=Activity12, Path=FirstNameMatches}" />
</IfElseBranchActivity>
<IfElseBranchActivity x:Name="ifElseBranchActivity2">
<CodeActivity x:Name="codeActivity2" ExecuteCode="{ActivityBind Name=Activity12, Path=FirstNameDoesNotMatch}" />
</IfElseBranchActivity>
</IfElseActivity>
<CodeActivity x:Name="codeActivity3" ExecuteCode="{ActivityBind Name=Activity12, Path=codeActivity3_ExecuteCode}" />
</ns0:Activity1>
-----------------------------------------------------------------------------------------
Any suggestions would be appreciated.
Thanks in advance,
John Portnov
JSF
The creation of that ".rules" file probably has something to do with the default behavior of the included sample. At one time I knew the magic combination to make that .rules file have the appropriate name, but I don't remember it offhand :) I've been away from this specific stuff for a while, but I'll try to remember what I did to avoid this. Setting the XClassProperty business on the workflow itself will give the workflow that "class name", and your resulting .rules file should then be named according to the classname you gave it. For example:
workflow.SetValue(WorkflowMarkupSerializer.XClassProperty, "Namespace.ClassName");
would result in the need to create a "Namespace.ClassName.rules" file for the workflow to pick up the associated rules correctly.
I've extended my previous example to include properties on the workflow designer control itself which set the workflow namespace and class name. I then added a property to the Loader class which records the namespace+classname as it comes out of the .xoml file [but I'm not certain that this was strictly necessary]. Then, when I create the associated files during the Save process, I name them according to the specified class and namespace. Everything then seems to compile together just fine. I don't know that I ever got rid of the phantom ".rules" file that sat around, but I know it didn't cause any issues for me once I had the custom properties in place.
TheJet
rubnov
Thanks!
P.S. On a side note, is there any movement on not requiring an activity when creating the RuleSet configuration dialog, instead passing in any old object Requiring an activity is going to put a pretty serious damper on those of us who may want to use the rules engine bits outside of Workflow.
gilabite
Loader.cs:
1) add using statements
using System.CodeDom;
using System.Reflection;
using System.Workflow.Activities.Rules;
2) in Initialize()
#replace:
typeProvider.AddAssemblyReference(typeof(string).Assembly.Location);
#with:
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
typeProvider.AddAssemblyReference(assembly.Location);
3) add properties:
private string ruleXoml = string.Empty;
private string ruleXomlFile = string.Empty;
public string RuleXomlFile
{
get { return this.ruleXomlFile; }
set { this.ruleXomlFile = value; }
}
public string RuleXoml
{
get { return this.ruleXoml; }
set { this.ruleXoml = value; }
}
4) in PerformLoad() after finally{} clause of rootActivity deserialization:
if (this.ruleXoml.Length > 0)
{
TextReader ruleReader = new StringReader(this.ruleXoml);
try
{
using (XmlReader xmlReader = XmlReader.Create(ruleReader))
{
WorkflowMarkupSerializer xomlSerializer = new WorkflowMarkupSerializer();
RuleDefinitions ruleDef = xomlSerializer.Deserialize(xmlReader) as RuleDefinitions;
if (ruleDef != null)
{
foreach (RuleSet setToAdd in ruleDef.RuleSets)
{
AddedRuleSetAction addAction = new AddedRuleSetAction(setToAdd);
addAction.ApplyTo(rootActivity);
}
foreach (RuleCondition conditionToAdd in ruleDef.Conditions)
{
AddedConditionAction addAction = new AddedConditionAction(conditionToAdd);
addAction.ApplyTo(rootActivity);
}
}
}
}
finally
{
ruleReader.Close();
}
}
5) In PerformFlush() after serializing workflow info:
using (XmlWriter writer = XmlWriter.Create(this.ruleXomlFile))
{
WorkflowMarkupSerializer xomlSerializer = new WorkflowMarkupSerializer();
RuleDefinitions ruleDefs = service.GetValue(RuleDefinitions.RuleDefinitionsProperty) as RuleDefinitions;
if(ruleDefs != null) xomlSerializer.Serialize(writer, ruleDefs);
}
WorkflowDesignerControl.cs
1) add using statement:
using System.Workflow.Activities.Rules;
2) add private variable:
RuleDefinitions workflowRules;
3) add properties:
public string RuleXomlFile
{
get
{
return this.loader.RuleXomlFile;
}
set
{
this.loader.RuleXomlFile = value;
}
}
public string RuleXoml
{
get
{
string xoml = string.Empty;
if (this.loader != null)
{
try
{
this.loader.Flush();
xoml = this.loader.RuleXoml;
}
catch
{
}
}
return xoml;
}
set
{
try
{
if (!String.IsNullOrEmpty(value))
LoadWorkflowRules(value);
}
catch
{
}
}
}
4) Add Site assignment during workflow load, immediately after selection service code:
this.propertyGrid.Site = rootDesigner.Component.Site;
5) Add Rules centric load functionality:
private void LoadWorkflowRules(string xoml)
{
SuspendLayout();
this.loader.RuleXoml = xoml;
this.designSurface.BeginLoad(this.loader);
ResumeLayout(true);
}
private void LoadWorkflowRules()
{
using (StringWriter stringWriter = new StringWriter())
{
using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter))
{
WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
serializer.Serialize(xmlWriter, workflowRules);
this.RuleXoml = stringWriter.ToString();
}
}
}
6) Update ShowDefaultWorkflow [NOTE: This should probably be changed to something else, otherwise the .rules file gets shared by all edited workflows]:
workflow.SetValue(WorkflowMarkupSerializer.XClassProperty, "WorkflowDesignerControl.CustomWorkflow");
7) Update LoadExistingWorkflow, just below the using() which reads the file:
//-- Load any rule information
this.RuleXomlFile = Path.Combine(Path.GetDirectoryName(this.XomlFile), workflow.GetValue(WorkflowMarkupSerializer.XClassProperty).ToString() + ".rules");
if (File.Exists(this.RuleXomlFile))
{
using (XmlReader xmlReader = XmlReader.Create(this.RuleXomlFile))
{
WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
this.workflowRules = (RuleDefinitions)serializer.Deserialize(xmlReader);
this.LoadWorkflowRules();
}
}
8) Update SaveExistingWorkflow() to include Rule info, just before this.loader.PerformFlush():
this.RuleXomlFile = Path.Combine(Path.GetDirectoryName(this.XomlFile), workflow.GetValue(WorkflowMarkupSerializer.XClassProperty).ToString() + ".rules");
9) Update Compile() method to include .rules resource:
if (this.RuleXomlFile.Length > 0)
parameters.CompilerOptions = "/resource:" + this.RuleXomlFile;
10) OPTIONAL: Update Run() method to always recompile. Hooking into some "workflow updated" event would be better, because the HOL code didn't take into account a) compiling with errors sets the compilerResults variable, causing a NullReferenceException on the second call to Run() and b) updating a workflow means it needs to be recompiled.
# remove if (this.compilerResults == null) { } statement surrounding the if(!this.Compile(false)) call
As I do further testing, I'll update this post with additional info.
Thanks!
TommyH
I'm getting a no-go on the compiler flag thing. I've moved to using wfc for the moment until I can get this worked out, then try to integrate the result into the actual application. The compiler command I'm using is:
wfc /out:CustomWorkflow.dll /target:assembly /resource:WorkflowExample3.rules /library:ActivityLibrary\bin\Debug /reference:ActivityLibrary.dll WorkflowExample3.xoml
This results in the following error:
X:\Skyline\Regis\Development\Sandbox\WorkflowBusinessRules\WorkflowExample3.xoml: error 1342: Activity 'ifElseBranchActivity1' validation failed: Can not find the condition "TestIfCondition".
On a side note, if I look at "wfc / " there is no mention of the /resource compiler flag, but by putting in an invalid filename, I can see that it's actually working.
... OK, now I see what the problem is. The workflow must be looking for the .rules file resource which exactly matches the namespace qualified classname [e.g. WorkflowDesignerControl.CustomWorkflow.rules]. When I rename my .rules output file to match and run the compiler again, things seem to work fine, I'll integrate that into my application and see if it fixes the problem.
Thanks!
iNemo
Just to be more clear... add the above CompilerOptions property of the CompilerParameters and pass in the compiler parameters to the Compile() method. Hope this helps. Let me know if you need more help.
Thanks,
Vijay
KiranVuppala
The steps you are describing should work.
What version of WF are you working with
Are you adding the ifElse or policy to a custom activity
Double check your projects references and be sure the reference to System.Workflow.Activities.dll does not have a warning tag.
Ironcity
6) Update ShowDefaultWorkflow [NOTE: This should probably be changed to something else, otherwise the .rules file gets shared by all edited workflows]:
workflow.SetValue(WorkflowMarkupSerializer.XClassProperty, "WorkflowDesignerControl.CustomWorkflow");
hi, thejet .
I have a problem that there is a .rules file which is in the ..\bin\debug file.This file(.rules) will record the rules definition information at design time,If tow apps edit the workflows,the .rules file gets shared by all edited workflows. Can I modify the .rules file path or have some other methods to solve this problem