บทความนี้มีรายละเอียดขั้นตอนที่คุณต้องดำเนินการอย่างรวดเร็วเพื่อเปิดใช้งานการสนับสนุนสำหรับ Windows Workflow Foundation (WF) ใน ASP.NET (Classic หรือ MVC) มาใช้แอปพลิเคชั่นตัวอย่างเล็ก ๆ เพื่อแสดงให้คุณเห็นว่าคุณสามารถทำสิ่งนี้ได้อย่างไร
การรวม WF ใน ASP.NET เป็นสิ่งที่ฉันต้องทำในโครงการไม่กี่โครงการที่ฉันทำงาน ดังนั้นฉันคิดว่าฉันจะสร้างแอปพลิเคชั่นตัวอย่างเล็ก ๆ ที่แสดงรหัสขั้นต่ำที่จำเป็นเพื่อให้ได้สิ่งนี้ มาสร้างแอปพลิเคชันตัวอย่างทีละขั้นตอน ...
หมายเหตุ : บทความนี้ไม่ใช่ไพรเมอร์บน WF จำเป็นต้องมีความเข้าใจพื้นฐานเกี่ยวกับ WF
เริ่มต้น SQL Server Management Studio และสร้างฐานข้อมูลใหม่ที่เรียกว่า "Workflow" คุณต้องสร้างตารางและตรรกะ (ขั้นตอนที่เก็บไว้และเช่นนี้) เพื่อสนับสนุนการคงอยู่ของ WF ในไดเรกทอรี "c: windows microsoft.net framework v3.0 windows workflow foundation sql en" คุณจะพบไฟล์ 4 sql ดำเนินการสองรายการต่อไปนี้ในลำดับนี้:
สิ่งนี้จะสร้างสองตารางและ 10 ขั้นตอนที่จัดเก็บซึ่งจำเป็นเพื่อรองรับการคงอยู่ของ WF ในฐานข้อมูลเซิร์ฟเวอร์ SQL ตอนนี้ดาวน์โหลดซอร์สโค้ดสำหรับบทความนี้แยกและเรียกใช้สคริปต์ DDL.SQL สคริปต์นี้สร้างหนึ่งตารางที่เรียกว่าลูกค้า
คุณควรไขลานด้วยโครงสร้างฐานข้อมูลที่มีลักษณะเช่นนี้:
รูปที่ 1 - ฐานข้อมูลเวิร์กโฟลว์

เมื่อคุณเปิดโซลูชันตัวอย่างของบทความนี้คุณจะพบโครงการไลบรารีรหัสหนึ่งที่เรียกว่า "ฐานข้อมูล" ทั้งหมดที่มีคือไฟล์คลาส LINQ ถึง SQL ซึ่งมีหนึ่งเอนทิตีคือลูกค้า
รูปที่ 2 - นิติบุคคลลูกค้า

แอปพลิเคชันตัวอย่างช่วยให้คุณสร้างลูกค้า สิ่งที่คุณต้องทำคือป้อนชื่อผู้ใช้ หลังจากนั้นเวิร์กโฟลว์ใหม่ก็เริ่มต้นขึ้นและคุณสามารถเลือกที่จะอนุมัติลูกค้าปฏิเสธเขาหรือไม่ทำอะไรเลย หากคุณไม่ดำเนินการลูกค้าจะถูกลบหลังจากหมดเวลา
รูปที่ 3 - เวิร์กโฟลว์

ในตัวอย่างนี้มีเวิร์กโฟลว์ของเครื่องหนึ่งรัฐ สำหรับเวิร์กโฟลว์ดังกล่าวคุณต้องให้สถานะเริ่มต้นและสถานะที่เสร็จสมบูรณ์ อย่างที่คุณเห็นในรูปด้านบนมีเพียงสองสถานะที่มีชื่ออย่างเหมาะสม
เวิร์กโฟลว์นี้ต้องการหนึ่งพารามิเตอร์ที่เรียกว่าชื่อผู้ใช้ เมื่อมาถึงสถานะเริ่มต้นจะมีการดำเนินการ stateInitializationActivity และลูกค้าใหม่จะถูกสร้างและคงอยู่ในตารางลูกค้า โดยค่าเริ่มต้นลูกค้าทุกคนต้องได้รับการอนุมัติ
รูปที่ 4 - ลูกค้ากำลังรอการอนุมัติ

ฉันใส่เวิร์กโฟลว์นี้ในโครงการแยกต่างหาก
รูปที่ 5 - โซลูชัน

เมื่อ stateInitializationActivity เสร็จสิ้นการดำเนินการทำงานจะต้องฟังหนึ่งใน 3 เหตุการณ์ที่เป็นไปได้:
เหตุการณ์การหมดเวลาขึ้นอยู่กับการหน่วงเวลา คุณไม่ต้องยิงเหตุการณ์นี้ด้วยตัวเอง แต่คุณรับผิดชอบในการยิงอีกสองเหตุการณ์ ดังนั้นฉันจึงสร้างบริการท้องถิ่น
รายการ 1 - อินเตอร์เฟส icustomerservice
[ ExternalDataExchange ]
public interface ICustomerService
{
event EventHandler < ExternalDataEventArgs > Approved ;
event EventHandler < ExternalDataEventArgs > Rejected ;
}คุณสามารถลงทะเบียนการใช้งานหนึ่งรายการสำหรับบริการท้องถิ่นในเวิร์กโฟลว์รันไทม์และการใช้งานสำหรับบริการลูกค้าจะเป็นแบบนี้:
รายการ 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 - คลาส 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 นี้เพื่อทำงานทั้งหมด
Voila ฐานรากถูกวางไว้ คุณได้ตั้งค่าฐานข้อมูลที่รองรับ WF Stervingence สร้างเวิร์กโฟลว์สำหรับการสร้างการอนุมัติและปฏิเสธลูกค้าและสร้างบริการท้องถิ่นที่จะช่วยคุณในการกำกับอินสแตนซ์เวิร์กโฟลว์ของคุณว่าจะทำอย่างไร
ตอนนี้ให้สร้างแอปพลิเคชันเว็บ 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 รู้ว่าต้องใช้ประเภท WorkflowRuntimesection เพื่ออ่านบิตของการกำหนดค่าต่อไปนี้ซึ่งคุณต้องเพิ่มลงในโหนดการกำหนดค่า
< 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 โหลด ManualWorkFlowsChedulerservice และ SQLWORKFLOWPERSISTENCESESVICES SERVICES สำหรับงานรันไทม์เวิร์กโฟลว์ คุณต้องโหลด SQLWORKFLOWPERSISTENCESERSERVICES หากคุณต้องการคงทำงานและสำหรับ ASP.NET ขอแนะนำให้ใช้ ManualWorkFlowsChedulerservice แทนบริการ defaultworkflowschedulerservice
แต่ละอินสแตนซ์เวิร์กโฟลว์จะดำเนินการบนเธรดแยกต่างหาก รันไทม์เวิร์กโฟลว์จัดการสิ่งนี้โดยใช้บริการ Workflow Scheduler โดยค่าเริ่มต้นรันไทม์จะใช้ประเภท defaultworkflowschedulerservice อินสแตนซ์เวิร์กโฟลว์ทั้งหมดดำเนินการในลักษณะอะซิงโครนัส
สำหรับ ASP.NET ควรใช้ ManualWorkFlowsChedulerservice เพราะมันช่วยให้คุณเรียกใช้เวิร์กโฟลว์แบบซิงโครนัส รันไทม์เวิร์กโฟลว์ใช้เธรดการโทรจากแอปพลิเคชันโฮสต์ในกรณีนี้
สิ่งนี้ช่วยให้คุณรอการตอบกลับจากเวิร์กโฟลว์ก่อนที่ ASP.NET จะส่งคำตอบ แน่นอนว่ามันไม่ควรที่จะดำเนินงานที่ใช้งานได้ยาวนานในเวิร์กโฟลว์ของคุณในกรณีนี้ (PS: ตรวจสอบโพสต์บล็อกนี้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อนี้)
เมื่อใช้ ManualWorkFlowsChedulerservice ให้แน่ใจว่าคุณตั้งค่าคุณสมบัติ USEACTIVETIMERS เป็น 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 ความแตกต่างเพียงอย่างเดียวคือคุณต้องดึงอินสแตนซ์ของบริการท้องถิ่นของคุณ (ลูกค้าบริการ) และเรียกมันว่าเป็นวิธีการที่ได้รับการอนุมัติ (... ) วิธีการที่ได้รับการอนุมัติทำให้เกิดเหตุการณ์ที่ได้รับการอนุมัติ เมื่อจัดส่งที่ประสบความสำเร็จคุณสามารถสั่งให้ผู้กำหนดตารางเวลาทำงานต่อไป
รายการ 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 ) ;
}การปฏิเสธบัญชีของลูกค้านั้นคล้ายคลึงกัน คุณจะต้องส่งเหตุการณ์ที่ถูกปฏิเสธแทนเหตุการณ์ที่ได้รับอนุมัติ หากคุณไม่ได้ดำเนินการการหน่วงเวลาจะถูกเรียกใช้หลังจากหนึ่งนาทีและบัญชีของลูกค้าจะถูกลบโดยอัตโนมัติ
และนั่นคือทั้งหมดที่มีอยู่