Uncategorized

[T2-401 デモ (3)] WF による Rule Base のアプリケーション

環境 :
Visual Studio 2008 (.NET Framework 3.5)

こんにちは。

  1. WCF の Transport レベルの Custom Channel Sample
  2. Rehosting を使ったエンドユーザへのワークフロー公開
  3. WF による Rule Base のアプリケーション
  4. Custom の SharePoint Workflow Editor

製品開発者向けということで実施した Tech Ed の T2-401 セッションですが、お約束通り、デモを添付しておきます。

つぎは、WF の説明で 2 番目にご紹介した、ルールベースアプリケーションのサンプルです。

download sample (20080826_CustomRulebaseService)

WF で、コード条件と、宣言型の条件に分かれている理由についてはセッションでご説明した通りです。このサンプルは、その後者のメカニズムを使用した製品サンプルでした。

コードは以下の通りです。

WF の Rule は、CodeDom を使って編集することができました。ここでも、前回のサンプルで登場した WorkflowMarkupSerializer を使って .rules ファイルへの変換と読み込みが可能です。
このサンプルでは、Excel 上の各行 (4 行目 – 8 行目) に設定された内容を元にこの宣言型のルールを作成しています。(CodeDom の構成について忘れた方は、セッションの資料を見直してください)

private void button1_Click(object sender, EventArgs e)
{
    Excel.Range cell;
 
    RuleSet myRuleset = new RuleSet("RuleSet1");
 
    // Define property and activity reference expressions through CodeDom functionality
    CodeThisReferenceExpression refexp = new CodeThisReferenceExpression();
    CodePropertyReferenceExpression refTotalCost = newCodePropertyReferenceExpression(refexp, "totalCost");
    CodePropertyReferenceExpression refParamCategory = newCodePropertyReferenceExpression(refexp, "paramCategory");
    CodePropertyReferenceExpression refParamPrivilege = newCodePropertyReferenceExpression(refexp, "paramPrivilege");
 
    // Example :
    // IF paramCategory == 3
    // THEN totalCost = totalCost + 300
 
    for (int row = 4; row <= 8; row++)
    {
        cell = (Excel.Range)this.Cells[row, 2];
        if (String.IsNullOrEmpty((string)cell.Value2))
            break;
        Rule myRule = new Rule("Rule" + row);
        myRuleset.Rules.Add(myRule);
 
        // Example :
        // paramCategory == 3
        CodeBinaryOperatorExpression ruleCondition = new CodeBinaryOperatorExpression();
        if ((string)cell.Value2 == "種別 (category)")
            ruleCondition.Left = refParamCategory;
        else if ((string)cell.Value2 == "特典 (privilige)")
            ruleCondition.Left = refParamPrivilege;
        ruleCondition.Operator = CodeBinaryOperatorType.ValueEquality;
        cell = (Excel.Range)this.Cells[row, 3];
        ruleCondition.Right = new CodePrimitiveExpression((int)(double)cell.Value2);
        myRule.Condition = new RuleExpressionCondition(ruleCondition);
 
        // Example :
        // totalCost = totalCost + 300
        CodeAssignStatement ruleAction = new CodeAssignStatement();
        ruleAction.Left = refTotalCost;
        CodeBinaryOperatorExpression actionRight = new CodeBinaryOperatorExpression();
        actionRight.Left = refTotalCost;
        cell = (Excel.Range)this.Cells[row, 4];
        if((string)cell.Value2 == "+")
            actionRight.Operator = CodeBinaryOperatorType.Add;
        else if ((string)cell.Value2 == "-")
            actionRight.Operator = CodeBinaryOperatorType.Subtract;
        else if ((string)cell.Value2 == "*")
            actionRight.Operator = CodeBinaryOperatorType.Multiply;
        else if ((string)cell.Value2 == "/")
            actionRight.Operator = CodeBinaryOperatorType.Divide;
        cell = (Excel.Range)this.Cells[row, 5];
        actionRight.Right = new CodePrimitiveExpression((int)(double)cell.Value2);
        ruleAction.Right = actionRight;
        myRule.ThenActions.Add(new RuleStatementAction(ruleAction));
    }
 
    // 必要に応じ、RuleValidation オブジェクトを使ってチェック!
    // (今回は省略 . . . . . . .)
 
    // RuleDefinitions を設定して保存
    RuleDefinitions ruleDef = new RuleDefinitions();
    ruleDef.RuleSets.Add(myRuleset);
    WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
    cell = (Excel.Range) this.Cells[11, 2];
    XmlTextWriter writer = new XmlTextWriter((string) cell.Value2, System.Text.Encoding.Unicode);
    serializer.Serialize(writer, ruleDef);
    writer.Close();
 
    // ここでは、すぐにコンパイルして実行
    // (Custom WorkflowRuntime Service と Custom Policy Activity を作成して、データベースなど独自の Rule Cache を作成することなども可能です . . .)
 
    MessageBox.Show("ルールを反映しました");
} 

反映されたルールは、xoml (アプリケーションマークアップファイル) とは異なり実行時に読み込まれました。しかし、標準の PolicyActivity, ConditionedActivityGroup, While 等はアセンブリに埋め込まれたルールファイルを見にいくという意地悪な構成になっていたので、これを改造する必要がありました。このルールメカニズムで活躍するのは RuleEngine オブジェクトです。
下記のコードは、外部ファイルやデータベースなどを見に行くようにするようカスタムのアクティビティを作成しています。(ここでは逆に、WorkflowMarkupSerializer で、宣言を読み込んでいます。)

protected override ActivityExecutionStatus Execute(ActivityExecutionContextexecutionContext)
{
    XmlReader reader = new XmlTextReader(RuleFilePath);
    WorkflowMarkupSerializer serializer = new WorkflowMarkupSerializer();
    RuleDefinitions ruleDef = (RuleDefinitions)serializer.Deserialize(reader);
    reader.Close();
 
    // ルートアクティビティを取得
    Activity root = this;
    while (root.Parent != null)
        root = root.Parent;
 
    for (int i = 0; i < ruleDef.RuleSets.Count; i++)
    {
        RuleSet myRuleSet = ruleDef.RuleSets[i];
        RuleEngine ruleEng = new RuleEngine(myRuleSet, root.GetType());
        ruleEng.Execute(root, executionContext);
    }
 
    return base.Execute(executionContext);
}

Advertisements

Categories: Uncategorized

Tagged as:

6 replies »

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s