この記事では、ASP.NET(クラシックまたはMVC)のWindows Workflow Foundation(WF)のサポートを有効にするために、実行する必要がある手順をすばやく詳しく説明します。非常に小さなデモアプリケーションを使用して、これを行う方法を示しましょう。
ASP.NETにWFを統合することは、私が取り組んだ過去数回のプロジェクトで私がしなければならなかったことです。だから、これを達成するために必要な最小限のコードを示す小さなサンプルアプリケーションを構築すると思いました。サンプルアプリケーションを段階的に作成しましょう...
注:この記事は、WFの入門書ではありません。 WFの基本的な理解が必要です。
SQL Server Management Studioを起動し、「ワークフロー」と呼ばれる新しいデータベースを作成します。 WFの持続性をサポートするには、いくつかのテーブルとロジック(ストアドプロシージャなど)を作成する必要があります。ディレクトリ「C: Windows Microsoft.net Framework V3.0 Windows Workflow Foundation sql en」4つのSQLファイルがあります。この順序で次の2つを実行します。
これにより、SQL ServerデータベースでWFの永続性をサポートするために必要な2つのテーブルと10のストアドプロシージャが作成されます。この記事のソースコードをダウンロードし、それを抽出し、DDL.SQLスクリプトを実行します。このスクリプトは、顧客と呼ばれる1つのテーブルを作成します。
次のように見えるデータベース構造に巻き込まれる必要があります。
図1-ワークフローデータベース

この記事のサンプルソリューションを開くと、「データベース」と呼ばれる1つのコードライブラリプロジェクトが見つかります。含まれているのは、1つのエンティティ、つまり顧客を含むLINQからSQLクラスファイルだけです。
図2-顧客エンティティ

サンプルアプリケーションを使用すると、顧客を作成できます。あなたがしなければならないのは、ユーザー名を入力することだけです。その後、新しいワークフローが開始され、顧客を承認したり、拒否したり、何もしないことを選択できます。アクションを実行しないと、特定のタイムアウト後に顧客は削除されます。
図3-ワークフロー

このサンプルには、1つのステートマシンワークフローがあります。このようなワークフローについては、初期および完成した状態を提供する必要があります。上の図でわかるように、適切に命名された2つの状態のみが含まれています。
このワークフローには、ユーザー名と呼ばれる1つのパラメーターが必要です。初期状態に到着すると、StateInitializationActivityが実行され、新しい顧客が作成され、顧客テーブルに持続します。デフォルトでは、すべての顧客が承認が必要です。
図4-承認を待っている顧客

このワークフローを別のプロジェクトに入れました。
図5-解決策

StateInitializationActivityがワークフローの実行を終了した場合、3つの可能なイベントのいずれかを聞きます。
タイムアウトイベントは、遅延性に依存しています。自分でこのイベントを解雇する必要はありませんが、他の2つのイベントを発射することを担当しています。そのため、ローカルサービスを作成しました。
リスト1 -icustomerserviceインターフェイス
[ ExternalDataExchange ]
public interface ICustomerService
{
event EventHandler < ExternalDataEventArgs > Approved ;
event EventHandler < ExternalDataEventArgs > Rejected ;
}ワークフローランタイムでローカルサービスの実装を1つだけ登録でき、顧客サービスの実装は次のようになります。
リスト2-顧客サービス
public class CustomerService : ICustomerService
{
public event EventHandler < ExternalDataEventArgs > Approved ;
public event EventHandler < ExternalDataEventArgs > Rejected ;
private bool FireEvent ( EventHandler < ExternalDataEventArgs > theEvent , ExternalDataEventArgs args )
{ //...}
public bool OnApproved ( Guid instanceId )
{
return FireEvent ( Approved , new ExternalDataEventArgs ( instanceId ) ) ;
}
public bool OnRejected ( Guid instanceId )
{
return FireEvent ( Rejected , new ExternalDataEventArgs ( instanceId ) ) ;
}
}このローカルサービスを使用すると、実行し続けるワークフローのインスタンスID(GUID)を指定することにより、承認または拒否されたイベントをトリガーできます。
顧客の作成、承認、または拒否には多くの論理が関係していませんが、Customermanagerクラスにすべてを入れています。方法は自明です。このクラスを使用すると、すべての顧客のリストを取得し、新しい顧客を追加し、顧客を承認、拒否、削除することができます。
リスト3-カスタムエルマナージャークラス
public class CustomerManager
{
public IEnumerable < Customer > GetCustomers ( ) { //... }
public Customer GetCustomerById ( Guid customerId ) { //... }
public void ApproveCustomer ( Guid customerId ) { //... }
public void RejectCustomer ( Guid customerId ) { //... }
public void DeleteCustomer ( Guid customerId ) { //... }
public void AddCustomer ( Guid customerId , string userName ) { //... }
}このワークフローは、このカスタムマーナーゲータータイプを使用して、すべての作業を実行します。
出来上がり、基礎は敷設されています。 WFの永続性をサポートするデータベースをセットアップし、顧客を作成、承認、拒否するワークフローを作成し、ワークフローインスタンスの指示を行うのに役立つローカルサービスを作成しました。
これは、これらすべてを機能させる新しいASP.NET Webアプリケーションを作成できるようになりました。 ASP.NETプロジェクトの元の名前「WebApplication」を思いつきました。
図6- WebApplicationプロジェクト

このサイトには、default.aspxと呼ばれる1ページのみが含まれています。このページには、顧客のリストが表示され、新しい顧客を追加して既存の顧客を承認または拒否できます。
図7-デフォルト.aspxページ

WFをサポートするようにWebアプリケーションを構成しましょう。この記事に示されている構成コードは、読みやすさのために略されます。フルバージョンのサンプルソースコードをダウンロードします。
アプリケーション構成ファイル(web.config)を開き、次の行をConfigSectionsセクションに追加します。
< configSections >
<!-- ... -->
< section name = " WorkflowRuntime "
type = " System.Workflow.Runtime.Configuration.WorkflowRuntimeSection...etc. " />
</ configSections >この行をConfigSectionsノードに追加する必要があります。これにより、.NETは、WorkFlowRuntimenectionタイプを使用して、構成ノードに追加する必要がある次の構成を読み取る必要があることがわかります。
< WorkflowRuntime >
< CommonParameters >
< add name = " ConnectionString " value = " your connection string " />
</ CommonParameters >
< Services >
< add type = " System.Workflow.Runtime.Hosting.ManualWorkflowSchedulerService,...etc. "
useActiveTimers = " true " />
< add type = " System.Workflow.Runtime.Hosting.SqlWorkflowPersistenceService,...etc. "
UnloadOnIdle = " true " LoadIntervalSeconds = " 5 " />
</ Services >
</ WorkflowRuntime >ワークフローランティムノードは、ワークフローランタイムのManualWorkFlowsChedulerServiceおよびSQLWorkFlowPersistencesServiceサービスをロードします。ワークフローを維持したい場合はSQLWorkFlowPersistencesServiceをロードする必要があり、ASP.NETの場合は、defaultWorkFlowsChedulerServiceサービスの代わりにManualWorkFlowsCheDulerServiceを使用することをお勧めします。
各ワークフローインスタンスは、個別のスレッドで実行されます。ワークフローランタイムは、ワークフロースケジューラサービスを使用してこれを管理します。デフォルトでは、RuntimeはDefaultWorkFlowsChedulerServiceタイプを使用します。すべてのワークフローインスタンスは、非同期に実行されます。
ASP.NETの場合、ManualWorkFlowsCheDulerServiceを使用することをお勧めします。これにより、ワークフローを同期して実行できるためです。この場合、ワークフローランタイムはホストアプリケーションの呼び出しスレッドを使用します。
これにより、ASP.NETが応答を送信する前に、ワークフローからの応答を待つことができます。もちろん、この場合、ワークフローで長期にわたるタスクを実行することは賢明ではありません。 (PS:このトピックの詳細については、このブログ投稿をご覧ください。)
ManualWorkFlowsCheDulerServiceを使用する場合、UseActivetimersプロパティをTRUEに設定してください。この設定をfalseのデフォルト値に残したままにしておくと、遅延アクティブが期限切れになった後に自動的に再開されません。 Trueに設定すると、ワークフローランタイムがメモリ内タイマーを使用して、期限切れの遅延性を定期的に確認します。
アプリケーションが使用ワークフローファンデーションに設定されたので、ワークフローランタイムをホストする必要があります。
ASP.NETでは、これを行うのに理想的な場所はGlobal.Asaxファイルです。次のコードをApplication_start(...)イベントハンドラーに追加するだけです。
リスト4 -Global.Asax Application_start
protected void Application_Start ( object sender , EventArgs e )
{
WorkflowRuntime runtime = new WorkflowRuntime ( "WorkflowRuntime" ) ;
ExternalDataExchangeService exchangeService = new ExternalDataExchangeService ( ) ;
runtime . AddService ( exchangeService ) ;
CustomerService customerService = new CustomerService ( ) ;
exchangeService . AddService ( customerService ) ;
runtime . StartRuntime ( ) ;
Application [ "WorkflowRuntime" ] = runtime ;
}ワークフローランティムの新しいインスタンスが作成され、externaldataexchangeserviceが作成され、ランタイムに追加されます。次に、ローカルサービスicustomerserviceのインスタンスを作成し、externaldataexchangeserviceインスタンスに追加します。最後に、ランタイムが開始され、アプリケーションの状態に保存されます。
同様に、リスト5に示すように、アプリケーションが終了するときにワークフローランタイムを停止する必要があります。
リスト5 -Global.Asax Application_End
protected void Application_End ( object sender , EventArgs e )
{
WorkflowRuntime runtime = Application [ "WorkflowRuntime" ] as WorkflowRuntime ;
if ( runtime != null )
{
runtime . StopRuntime ( ) ;
runtime . Dispose ( ) ;
}
} [追加]ボタンをクリックすると、新しいワークフローを開始する必要があります。 ManualWorkFlowsCheDulerServiceを使用する場合、ワークフローインスタンスを実行することを完全に制御できます。リスト6では、次の手順に従う必要があることがわかります。
リスト6-新しい顧客を作成します
WorkflowRuntime runtime = ( WorkflowRuntime ) Application [ "WorkflowRuntime" ] ;
Dictionary < string , object > arguments = new Dictionary < string , object > ( ) ;
arguments . Add ( "UserName" , txtUserName . Text . Trim ( ) ) ;
WorkflowInstance workflow = runtime . CreateWorkflow ( typeof ( CustomerApprovalWorkflow ) , arguments ) ;
workflow . Start ( ) ;
ManualWorkflowSchedulerService scheduler =
( ManualWorkflowSchedulerService ) runtime . GetService ( typeof ( ManualWorkflowSchedulerService ) ) ;
scheduler . RunWorkflow ( workflow . InstanceId ) ; 顧客を作成した後、アカウントを承認または拒否することができます。言い換えれば、アカウントを作成したときに開始されたワークフローを継続する必要があります。
リスト7に示されているコードは、リスト6のコードと似ています。唯一の違いは、ローカルサービス(customerservice)のインスタンスを取得し、承認された(...)メソッドを呼び出す必要があることです。承認されたメソッドは、承認されたイベントをトリガーします。配達が成功すると、スケジューラにワークフローの実行を続けるよう指示できます。
リスト7-顧客を承認します
WorkflowRuntime runtime = ( WorkflowRuntime ) Application [ "WorkflowRuntime" ] ;
ManualWorkflowSchedulerService scheduler =
( ManualWorkflowSchedulerService ) runtime . GetService ( typeof ( ManualWorkflowSchedulerService ) ) ;
CustomerService customerService = ( CustomerService ) runtime . GetService < ICustomerService > ( ) ;
if ( customerService . OnApproved ( customerId ) )
{
scheduler . RunWorkflow ( customerId ) ;
}顧客のアカウントを拒否することも同様です。承認されたイベントではなく、拒否されたイベントを送信するだけです。アクションを実行しないと、遅延性が1分後にトリガーされ、顧客のアカウントが自動的に削除されます。
そして、それだけです。