تفصل هذه المقالة بسرعة الخطوات التي تحتاج إلى تنفيذها من أجل تمكين الدعم لمؤسسة Windows Workflow Foundation (WF) في ASP.NET (Classic أو MVC). دعنا نستخدم تطبيقًا تجريبيًا صغيرًا جدًا لنوضح لك كيف يمكنك القيام بذلك.
دمج WF في ASP.NET هو شيء كان علي القيام به في المشاريع القليلة الماضية التي عملت عليها. لذلك اعتقدت أنني سأبني تطبيقًا صغيرًا يوضح لك الحد الأدنى من التعليمات البرمجية المطلوبة لتحقيق ذلك. دعنا نبني نموذجًا خطوة بخطوة ...
ملاحظة : هذا المقال ليس التمهيدي على WF. مطلوب بعض الفهم الأساسي ل WF.
بدء تشغيل SQL Server Management Studio وإنشاء قاعدة بيانات جديدة تسمى "سير العمل". تحتاج إلى إنشاء عدد قليل من الجداول والمنطق (الإجراءات المخزنة وما شابه) من أجل دعم ثبات WF. في الدليل "C: Windows Microsoft.net Framework V3.0 Windows Workflow Foundation SQL EN" ستجد 4 ملفات SQL. تنفيذ الاثنين التاليين في هذا الترتيب:
هذا ينشئ جدولين و 10 إجراءات مخزنة مطلوبة لدعم ثبات WF في قاعدة بيانات SQL Server. الآن قم بتنزيل الكود المصدري لهذه المقالة ، واستخرجها وتنفيذ البرنامج النصي DDL.SQL. هذا البرنامج النصي ينشئ جدول واحد يسمى العميل.
يجب أن تنتهي بهيكل قاعدة البيانات يشبه هذا:
الشكل 1 - قاعدة بيانات تدفق العمل

عند فتح حل نموذج هذه المقالة ، ستجد مشروع مكتبة رمز واحد يسمى "قاعدة البيانات". كل ما يحتوي عليه هو ملف فئات LINQ إلى SQL الذي يحتوي على كيان واحد ، وهو العميل.
الشكل 2 - كيان العميل

يتيح لك تطبيق نموذج إنشاء العملاء. كل ما عليك فعله هو إدخال اسم مستخدم. بعد ذلك ، يتم بدء سير عمل جديد ويمكنك اختيار الموافقة على العميل أو رفضه أو عدم القيام بأي شيء. إذا لم تتخذ إجراءً ، فسيتم حذف العميل بعد مهلة معينة.
الشكل 3 - سير العمل

في هذه العينة هناك سير عمل آلة واحدة. لمثل هذا سير العمل ، عليك تقديم حالة أولية ومكتملة. كما ترون في الشكل أعلاه ، يحتوي فقط على حالتين تم تسميته بشكل مناسب.
يتطلب سير العمل هذا معلمة واحدة تسمى اسم المستخدم. عند وصولها إلى الحالة الأولية ، يتم تنفيذ النشاط الحكومي للدولة ويتم إنشاء عميل جديد واستمراره في جدول العميل. بشكل افتراضي ، يتطلب جميع العملاء موافقة.
الشكل 4 - العملاء الذين ينتظرون الموافقة

لقد وضعت سير العمل هذا في مشروع منفصل.
الشكل 5 - الحل

عندما تنتهي نشاط الحالة في تنفيذ سير العمل ، ستستمع سير العمل لإحدى الأحداث الثلاثة الممكنة:
يعتمد حدث المهلة على التأخير. ليس عليك إطلاق هذا الحدث بنفسك ، ولكنك مسؤول عن إطلاق الحدثين الآخرين. لذلك قمت بإنشاء خدمة محلية.
قائمة 1 - واجهة الخدمات الفنية ICUSTOMERSION
[ ExternalDataExchange ]
public interface ICustomerService
{
event EventHandler < ExternalDataEventArgs > Approved ;
event EventHandler < ExternalDataEventArgs > Rejected ;
}يمكنك تسجيل تطبيق واحد فقط لخدمة محلية في وقت تشغيل سير العمل ، ويبدو أن التنفيذ الخاص بـ Customerervice:
قائمة 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 ) ) ;
}
}تتيح لك هذه الخدمة المحلية تشغيل الحدث المعتمد أو المرفوض عن طريق تحديد معرف المثيل (GUID) لسير العمل الذي تريد متابعة التنفيذ.
لا يوجد الكثير من المنطق في إنشاء العملاء أو الموافقة عليه أو رفضه ، لكنني وضعت كل هذا في فئة CustomerManager. الطرق هي الذات. يتيح لك هذه الفئة استرداد قائمة بجميع العملاء ، وإضافة عملاء جدد ، والموافقة ، ورفض العملاء وحذفهم.
قائمة 3 - فئة Customermanager
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 ) { //... }
}يستخدم سير العمل هذا نوع CustomerManager لأداء كل أعماله.
فويلا ، تم وضع الأسس. لقد قمت بإعداد قاعدة بيانات تدعم ثبات WF ، وأنشأت سير عمل لإنشاء العملاء والموافقة عليه ورفضه وإنشاء خدمة محلية تساعدك في توجيه مثيلات سير العمل الخاصة بك.
يتيح الآن إنشاء تطبيق ويب ASP.NET جديد سيضع كل هذا في العمل. لقد توصلت إلى الاسم الأصلي "WebApplication" لمشروع ASP.NET.
الشكل 6 - مشروع WebApplication

يحتوي الموقع فقط على صفحة واحدة تسمى default.aspx. تعرض هذه الصفحة قائمة بالعملاء ، وتتيح لك إضافة عملاء جدد والموافقة أو رفض العملاء الحاليين.
الشكل 7 - صفحة default.aspx

دعنا نهيئ تطبيق الويب بحيث يدعم WF. يتم اختصار رمز التكوين الموضح في هذه المقالة لقابلية القراءة. قم بتنزيل رمز المصدر العينة للإصدار الكامل.
افتح ملف تكوين التطبيق الخاص بك (web.config) وأضف السطر التالي إلى قسم التكوينات.
< configSections >
<!-- ... -->
< section name = " WorkflowRuntime "
type = " System.Workflow.Runtime.Configuration.WorkflowRuntimeSection...etc. " />
</ configSections >تحتاج إلى إضافة هذا السطر إلى عقدة التكوينات بحيث يعرف .NET أنه يجب استخدام نوع سير العمل في Hemrotemsection لقراءة الجزء التالي من التكوين الذي تحتاج إلى إضافته إلى عقدة التكوين.
< 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 >تعمل عقدة WorkFlowRuntime على تحميل خدمات SQLWorkFlowPersistenceservice SQLWorkFlowPersencerService لوقت سير العمل. يجب عليك تحميل sqlworkflowpersistenceservice إذا كنت ترغب في استمرار سير العمل الخاص بك وبالنسبة لـ ASP.NET ، من المستحسن استخدام ManualWorkFlowsChedulerservice بدلاً من خدمة DefaultWorkFlowsChedulerService.
ينفذ كل مثيل سير عمل على مؤشر ترابط منفصل. يدير وقت تشغيل سير العمل هذا باستخدام خدمة جدولة سير العمل. بشكل افتراضي ، يستخدم وقت التشغيل نوع DefaultWorkFlowScheDulerservice. يتم تنفيذ جميع مثيلات سير العمل بطريقة غير متزامنة.
بالنسبة لـ ASP.NET ، من الأفضل استخدام خدمة ManualWorkFlowsChedulerservice ، لأنه يتيح لك تشغيل مهام سير العمل بشكل متزامن. يستخدم وقت تشغيل سير العمل مؤشر ترابط الاتصال من تطبيق المضيف في هذه الحالة.
يتيح لك ذلك الانتظار لاستجابة من سير العمل قبل أن يرسل ASP.NET استجابة. Ofcourse ، ليس من الحكمة تنفيذ أي مهام طويلة المدى في سير العمل في هذه الحالة. (PS: تحقق من منشور المدونة هذا لمزيد من المعلومات حول هذا الموضوع.)
عند استخدام ManualWorkFlowsChedulerservice ، تأكد من تعيين خاصية useactivetimers إلى صحيح. إذا تركت هذا الإعداد ضبط على قيمته الافتراضية للخطأ ، فلن يتم استئناف أي تأخير تلقائيًا بعد انتهاء صلاحيتها. إذا تم ضبط وقت تشغيل سير العمل على True ، فسيستخدم وقت تشغيل مؤقتة في الذاكرة للتحقق بشكل دوري للتأخير منتهية الصلاحية.
الآن بعد أن تم تكوين تطبيقك إلى مؤسسة Workflow Use ، تحتاج إلى استضافة وقت تشغيل سير العمل.
في 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 وإضافتها إلى وقت التشغيل. بعد ذلك ، نقوم بإنشاء مثيل لخدمة الخدمات المحلية الخاصة بنا وإضافته إلى مثيل 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. الفرق الوحيد هو أنه يتعين عليك استرداد مثيل الخدمة المحلية (CustomerRovice) والاتصال به على طريقة (...). طريقة OnAproved تؤدي إلى الحدث المعتمد. عند التسليم الناجح ، يمكنك توجيه جدولة لمواصلة تشغيل سير العمل.
قائمة 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 ) ;
}إن رفض حساب العميل مشابه. ما عليك سوى إرسال الحدث المرفوض بدلاً من الحدث المعتمد. إذا لم تتخذ إجراءً ، فسيتم تشغيل التأخير بعد دقيقة واحدة وسيتم حذف حساب العميل تلقائيًا.
وهذا كل ما في الأمر.