لود کردن Workflow از پایگاه داده

چاپ

لود کردن Workflow از پایگاه داده

یکی از مهمترین اهداف Workflow، پیاده سازی برنامه هایی با پروسه های طولانی مدت (long-running) است. بعنوان مثال پروسه ی "ثبت مرخصی" یکی از پروسه هایی است که باید توسط مدیر تأیید شود و سپس به بخش منابع انسانی ارسال شود.

کلید رسیدن به هدف بالا این است که بتوانیم، گردش کارهایی که در پایگاه داده ذخیره شده اند را بنحوی دوباره به جریان بیاندازیم.

در این قسمت از آموزش Workflow، قصد داریم سیستم گردش کار قبلی (ذخیره Workflow در پایگاه داده) را بنحوی تغییر دهیم که بعد از توقف Workflow که بخاطر اکتویتی Delay اتفاق افتاده است، با زدن کلید Enter جریان کار، ادامه یابد.

مراحل انجام کار

 پروژه گردش کار UsingForeachActivity شامل شش مرحله زیر است:

  1. ایجاد یک پروژه از نوع Workflow Console Application
  2. طراحی Workflow
  3. کدهای لازم برای Host کردن Workflow
  4. اجرای Workflow
  5. سیستم گردش کار LoadingUpWorkflowFromPersistenceDB چگونه کار می کند؟

ایجاد یک پروژه از نوع Workflow Console Application

یک پروژه جدید از نوع Workflow Console Application و با نام LoadingUpWorkflowFromPersistenceDB ایجاد نمایید.

توجه: برای ذخیره Workflow در DataBase، به پایگاه داده PersistenceWorkflow نیاز است، بنابراین در این پروژه نیز از پیکربندی که در مطلب قبل انجام دادیم، مجددا استفاده خواهیم کرد.


طراحی Workflow

حالا فایل Workflow1.xaml را باز کنید و Workflow را مطابق زیر طراحی نمایید:

  1. از پنل ToolBox، اکتیویتی Sequence را انتخاب کرده و به داخل صفحه طراحی گردش کار بکشید.
  2. از پنل Toolbox اکتیویتی WriteLine را به داخل Sequence بکشید و آنرا مطابق زیر تنظیم نمایید.
  3. حالا یک اکتیویتی Delay زیر WriteLine قرار دهید و خصوصیت Duration آنرا با "00:00:01" تنظیم نمایید.
  4. مجدداً از پنل Toolbox یک اکتیویتی WriteLine دیگر به داخل Sequence بکشید و آنرا مطابق زیر تنظیم نمایید.

در اکتیویتی Delay، خصوصیت Duration را با 1 ثانیه تنظیم کردیم، بنابراین زمانی که Workflow به اکتیویتی Delay می رسد، گردش کار متوقف یا Idle شده و Workflow در پایگاه داده ذخیره می شود.


کدهای لازم برای Host کردن Workflow

 ابتدا فضانام های زیر را به پروژه Add Reference کنید:

  1. System.Activities.DurableInstancing
  2. System.Runtime.DurableInstancing

حالا فایل Program.cs را باز کنید و کدهای زیر را در آن جایگزین نمایید:

Program.cs

using System;
using System.Linq;
using System.Activities;
using System.Activities.Statements;
using System.Activities.DurableInstancing;
using System.Threading;

namespace LoadingUpWorkflowFromPersistenceDB
{
    /// 
    /// Author : Amir Pahlavan sadegh
    /// provided to you by : http://www.beyamooz.com
    ///
    class Program
    {
        static SqlWorkflowInstanceStore sqlWorkflowInstanceStore = SetupSqlPersistenceStore();
        static void Main(string[] args)
        {
            StartAndUnloadInstance();

            Console.WriteLine("-------------\nProvided to you by : http://www.beyamooz.com \npress any key ...");
            Console.ReadLine();
        }
        static void StartAndUnloadInstance()
        {
            AutoResetEvent waitHandler = new AutoResetEvent(false);
            WorkflowApplication wfApp = new WorkflowApplication(new
            Workflow1());
            wfApp.InstanceStore = sqlWorkflowInstanceStore;
            wfApp.PersistableIdle = (e) => { return PersistableIdleAction.Unload; };
            wfApp.Unloaded = (e) => { waitHandler.Set(); };
            Guid id = wfApp.Id;
            wfApp.Run();
            waitHandler.WaitOne();
            LoadAndCompleteInstance(id);
        }
        static void LoadAndCompleteInstance(Guid id)
        {
            Console.WriteLine("Press  to load the persisted workflow");
            Console.ReadLine();
            AutoResetEvent waitHandler = new AutoResetEvent(false);
            WorkflowApplication wfApp = new WorkflowApplication(new Workflow1());
            wfApp.InstanceStore = sqlWorkflowInstanceStore;
            wfApp.Unloaded = (workflowApplicationEventArgs) => { waitHandler.Set(); };
            wfApp.Load(id);
            wfApp.Run();
            waitHandler.WaitOne();
        }
        private static SqlWorkflowInstanceStore SetupSqlPersistenceStore()
        {
            string connectionString = @"Data Source=172.16.33.12; Initial Catalog=PersistenceWorkflow; User ID=sa; Password=yalatif!@#123";
            SqlWorkflowInstanceStore sqlWFInstanceStore = new SqlWorkflowInstanceStore(connectionString);
            sqlWFInstanceStore.InstanceCompletionAction = InstanceCompletionAction.DeleteAll;
            return sqlWFInstanceStore;
        }
    }
}

اجرای Workflow

پروژه LoadingUpWorkflowFromPersistenceDB را بعنوان پروژه StartUp تنظیم نمایید و در ادامه برای اجرای Workflow دکمه های میانبر Ctrl+F5 را فشار دهید. همان طور که در تصویر زیر مشاهده می کنید، زمانی که اجرای Workflow به اکتیویتی Delay می رسد، اجرای Workflow متوقف شده و همزمان اطلاعات در پایگاه داده ذخیره می شود:

اما در مرحله بعد، با فشردن دکمه ی Enter، اجرای سیستم گردش کار ادامه می یابد و نهایتاً با چاپ "Workflow end"، سیستم گردش کار پایان می یابد:


سیستم گردش کار LoadingUpWorkflowFromPersistenceDB چگونه کار می کند؟

به متد StartAndUnloadInstance در فایل program.cs توجه فرمایید:

program.cs

static void StartAndUnloadInstance()
        {
            AutoResetEvent waitHandler = new AutoResetEvent(false);
            WorkflowApplication wfApp = new WorkflowApplication(new  Workflow1());
            wfApp.InstanceStore = sqlWorkflowInstanceStore;
            wfApp.PersistableIdle = (e) => { return PersistableIdleAction.Unload; };
            wfApp.Unloaded = (e) => { waitHandler.Set(); };
            Guid id = wfApp.Id;
            wfApp.Run();
            waitHandler.WaitOne();
            LoadAndCompleteInstance(id);
        }

ممکن است بخواهیم بجای کد قرمز شده ی بالا از کد زیر برای ذخیره کردن Workflow در پایگاه داده استفاده کنیم: 

program.cs

              wfApp.PersistableIdle = (e) => {return PersistableIdleAction.Persist;};

به این ترتیب، Workflow ی ذخیرهِ شده در پایگاه داده، در انحصار شیء ایجاد کننده ی Workflow خواهد ماند و بدون اینکه فضای اشغالی آن در حافظه تخلیه شود، از Workflow خارج خواهد شد. در نتیجه اگر Workflow مذکور را که بوسیله شیء قبلی Lock شده است بخواهیم با استفاده یک شیء جدید WorkflowApplication لود کنیم، با خطای زیر مواجه خواهیم شد:

Unhandled Exception: System.Runtime.DurableInstancing.InstanceLockedException: The execution of an InstancePersistenceCommand was interrupted because the instance 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx' is locked by a different instance owner. This error usually occurs because a different host has the instance loaded. The instance owner ID of the owner or host with a lock on the instance is 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx'.

اگر می خواهید Workflow ای را در پایگاه داده ذخیره کنید و حافظه را از فضای اشغالی توسط آن تخلیه کنید، باید از PersistableIdelAction.Unload بجای PersistableIdleAction.Persist استفاده کنید.