ห้องสมุดที่ออกแบบมาสำหรับสร้างเวิร์กโฟลว์ที่กำหนดเองการจัดเรียงระหว่างส่วนประกอบไมโครเซอร์และยูทิลิตี้ระบบอัตโนมัติอื่น ๆ ที่สร้างขึ้นใน Dotnet เวอร์ชัน 6
ห้องสมุดนี้ได้รับการออกแบบให้มีระบบนิเวศของเอนทิตีที่มุ่งเน้นไปที่การประสานงานของกระบวนการใด ๆ จากกระบวนการที่ง่ายที่สุดเช่นการโทรระหว่างหลายชั้นเรียนของเราไปจนถึงกระบวนการที่ซับซ้อนมากขึ้นเช่นการโทรไปยัง Microservices ฯลฯ เสมออย่างไรก็ตามในลักษณะที่ประกาศและมองหาการบันทึกรหัสในแง่ของการทำรังที่น่าเบื่อและซับซ้อนของ "ถ้า", "อื่น" ...
ในที่เก็บนี้จะเป็นคลาสหลักของระบบนิเวศนี้จัดกลุ่มภายใต้เนมสเปซ Magnett.automation.core บางชั้นเรียนเหล่านี้สามารถใช้นอกขอบเขตของการสร้างเวิร์กโฟลว์ได้เนื่องจากมีทั่วไปพอที่จะเป็นประโยชน์อย่างอิสระ
ในเนมสเปซนี้เราพบคลาสยูทิลิตี้ที่ใช้ในคลาสไลบรด์
บริบทแนวคิดเป็นสิ่งที่ทั่วไปมากและใช้ในหลายสาขา สำหรับเราบริบทจะเป็นพื้นที่ส่วนกลางที่มีการจัดเก็บค่านิยมระหว่างองค์ประกอบหลายอย่างซึ่งเป็นค่าของประเภทที่แตกต่างกัน
ดังนั้นเราจึงอยู่ด้านหน้าของระบบคีย์/ค่าซึ่งค่าจะเป็นประเภทใดก็ได้
โครงสร้างของบริบทนั้นง่ายมันถูกสร้างขึ้นโดยคลาส บริบท ซึ่งจะเป็นอินพุตและการดึงคลาสของเราและอินเตอร์เฟส icontextVault ซึ่งจะเป็นคำจำกัดความของห้องนิรภัยที่เก็บค่าไว้
โดยค่าเริ่มต้นเราจะมีการใช้งาน IconTextVault ซึ่งจะจัดเก็บค่าในหน่วยความจำ แต่จะเปิดสำหรับการใช้งานอื่น ๆ ที่เก็บค่าเหล่านี้ด้วยวิธีอื่น
เราจะใช้ contextfield ในคลาสเพื่อรับและตั้งค่าในบริบทด้วยคลาสนี้เราสามารถกำหนดประเภทและชื่อของคลาส
ตัวอย่างวิธีการรับ / ตั้งค่าในบริบท
var context = Context . Create ( ) ;
var field = ContextField < int > . Create ( "FieldName" ) ;
//Set Value
context . Store ( field , random . Next ( 1000 ) ) ;
//Get Value
var value = context . Value ( field ) ; เรามีอินเทอร์เฟซหลายอย่างสำหรับคำจำกัดความของเครื่องรัฐรวมถึงการดำเนินการ คำจำกัดความของเครื่องจะถูกแยกออกจากการดำเนินการของเครื่องเองเพื่อหลีกเลี่ยงข้อต่อและการแยกความรับผิดชอบที่ชัดเจน
อินเทอร์เฟซหลักคือ imachine ด้วยอินเทอร์เฟซนี้เราจะสามารถเข้าถึงสถานะปัจจุบัน อิน เทอร์เฟซ istate และความเป็นไปได้ของการเปลี่ยนไปสู่สถานะอื่นโดยใช้รหัสการดำเนินการที่สร้างการเปลี่ยนแปลงเอน ทิตี ITRANSACTION ANTITY ไปสู่สถานะอื่น
เป็นไปไม่ได้ที่จะเปลี่ยนจากสถานะหนึ่งไปยังอีกรัฐหนึ่งโดยตรงผ่านการเปลี่ยนแปลงเพื่อให้เรามีแบบจำลองที่เราสามารถไปจากหนึ่งโดยเฉพาะ
สามารถกำหนดสถานะที่ไม่มีการเปลี่ยนแปลงที่กำหนดได้และหมายความว่ารัฐเป็นเทอร์มินัล ด้วยวิธีนี้เราสามารถกำหนดเครื่องจักรที่ จำกัด หรือไม่ จำกัด
เกี่ยวกับส่วนรันไทม์คำจำกัดความของเครื่องจะทำจากอินเตอร์เฟส imachinedefinition ซึ่งจะถูกสร้างขึ้นจากคลาส MachineFinitionBuilder
ตัวอย่างของรหัสนิยามเครื่อง
//Helper class with states enumeration
public class State : Enumeration
{
public static readonly State Init = new State ( 1 , nameof ( Init ) ) ;
public static readonly State Working = new State ( 2 , nameof ( Working ) ) ;
public static readonly State Paused = new State ( 3 , nameof ( Paused ) ) ;
public static readonly State Finished = new State ( 4 , nameof ( Finished ) ) ;
private State ( int id , string name ) : base ( id , name )
{
}
}
//Helper class with action enumerations
public class Action : Enumeration
{
public static readonly Action Start = new Action ( 1 , nameof ( Start ) ) ;
public static readonly Action Pause = new Action ( 2 , nameof ( Pause ) ) ;
public static readonly Action Continue = new Action ( 3 , nameof ( Continue ) ) ;
public static readonly Action Finish = new Action ( 4 , nameof ( Finish ) ) ;
private Action ( int id , string name ) : base ( id , name )
{
}
}
//Now we can create a definition
_definition = MachineDefinitionBuilder . Create ( )
. InitialState ( State . Init )
. OnAction ( Action . Start ) . ToState ( State . Working )
. Build ( )
. AddState ( State . Working )
. OnAction ( Action . Pause ) . ToState ( State . Paused )
. OnAction ( Action . Finish ) . ToState ( State . Finished )
. Build ( )
. AddState ( State . Paused )
. OnAction ( Action . Continue ) . ToState ( State . Working )
. Build ( )
. AddState ( State . Finished )
. Build ( )
. BuildDefinition ( ) ;ตัวอย่างการสร้างเครื่องจักรและรหัสการใช้งาน
var machine = Machine
. Create ( SimpleMachineDefinition . GetDefinition ( ) ) ;
machine . Dispatch ( Action . Start ) ;
var currentState = machine . State ; ภายใต้เนมสเปซนี้เราจะมีคลาสที่จำเป็นในการกำหนดเวิร์กโฟลว์และดำเนินการ เช่นเดียวกับในส่วนก่อนหน้าเราจะแยกนิยามเวิร์กโฟลว์ออกจากการดำเนินการ
การแยกนี้จะทำโดยใช้อินเตอร์เฟส IWORKFLOWDEFINITION และ IWORKFLOWRUNNER
ในการห่อหุ้มคำจำกัดความและการดำเนินการเรามีอินเทอร์เฟซ IFLOW อินเทอร์เฟซนี้จะช่วยให้เราในอนาคตในการสร้างกระแสย่อยสร้างกระแสที่ถูกห่อหุ้มเป็นบริการภายในแอปพลิเคชันที่ซับซ้อนมากขึ้น ...
หากเราคิดในโฟลว์พื้นฐานเพียงแค่โหนดเริ่มต้นและเริ่มต้นเพื่อรีเซ็ตค่าฟิลด์โหนดถัดไปเพียงเพื่อ caculate ไปยังตัวเลขสุ่มและโหนดสุดท้ายเพื่อรวมค่าทั้งสองค่าที่นิยามควรจะเป็นเช่นนั้น
ตัวอย่างรหัสนิยามเวิร์กโฟลว์
var contextDefinition = ContextDefinition . Create ( ) ;
var definition = FlowDefinitionBuilder . Create ( )
. WithInitialNode ( ResetValue . Create ( Node . Reset , contextDefinition ) )
. OnExitCode ( ResetValue . ExitCode . Ok ) . GoTo ( Node . SetValue )
. Build ( )
. WithNode ( SetValue . Create ( Node . SetValue , contextDefinition ) )
. OnExitCode ( SetValue . ExitCode . Assigned ) . GoTo ( Node . SumValue )
. Build ( )
. WithNode ( SumValue . Create ( Node . SumValue , contextDefinition ) ) . Build ( )
. BuildDefinition ( ) ;ก่อนหน้านี้คุณได้กำหนดคลาสผู้ช่วยบางอย่างเช่น บริบทบริบท มันเป็นเพียงคลาสที่มีฟิลด์บริบทและเพื่อหลีกเลี่ยงการทำซ้ำด้วยคำจำกัดความชื่อ
internal class ContextDefinition
{
public ContextField < int > FirstDigit { get ; }
public ContextField < int > SecondDigit { get ; }
public ContextField < int > Result { get ; }
private ContextDefinition ( )
{
FirstDigit = ContextField < int > . Create ( "FieldOne" ) ;
SecondDigit = ContextField < int > . Create ( "FieldTwo" ) ;
Result = ContextField < int > . Create ( "FieldResult" ) ;
}
public static ContextDefinition Create ( )
{
return new ContextDefinition ( ) ;
}
}เราได้สร้างคลาสนามธรรม ทั่วไป ที่เราจะใช้เป็นคลาสพื้นฐานสำหรับคลาสโหนดทั้งหมดของเราเราจะใช้เป็นวิธีเพื่อให้แน่ใจว่าโหนดทั้งหมดมี avaliable conxtextdinition
internal abstract class Common : Core . WorkFlows . Implementations . Node
{
protected ContextDefinition ContextDefinition { get ; }
protected Common ( CommonNamedKey key , ContextDefinition contextDefinition ) : base ( key )
{
ContextDefinition = contextDefinition
?? throw new ArgumentNullException ( nameof ( contextDefinition ) ) ;
}
}เรามีโหนดสองประเภทซิงค์และ Async ภายใต้อินเทอร์เฟซ inode และ inodeasync ดังนั้นเราจึงสามารถใช้โหนดเป็น wrapper ของกระบวนการทั้งสองประเภท ในตัวอย่างนี้เรามีเพียงการใช้งาน SYNC
ในตัวอย่างของเราเราจะใช้เฉพาะโหนดซิงค์
ตัวอย่างโหนด
internal class ResetValue : Common
{
#region ExitCodes
public class ExitCode : Enumeration
{
public static readonly ExitCode Ok = new ExitCode ( 1 , "Ok" ) ;
private ExitCode ( int id , string name ) : base ( id , name )
{
}
}
#endregion
private ResetValue ( CommonNamedKey key , ContextDefinition contextDefinition ) :
base ( key , contextDefinition )
{
}
public override NodeExit Execute ( Context context )
{
context . Store ( ContextDefinition . FirstDigit , 0 ) ;
context . Store ( ContextDefinition . SecondDigit , 0 ) ;
context . Store ( ContextDefinition . Result , 0 ) ;
return NodeExit . Create ( ExitCode . Ok . Name ) ;
}
public static ResetValue Create ( CommonNamedKey name , ContextDefinition contextDefinition )
{
return new ResetValue ( name , contextDefinition ) ;
}
}ExitCodes คลาสด้านในเป็นเพียงคลาส Helper อีกคลาสสร้างคลาสการแจงนับด้วยคำจำกัดความของรหัสทางออกที่มีความสามารถสำหรับโหนดนี้เราใช้ somthin similira
นักวิ่งเพื่อยกตัวอย่างตัวเองจะต้องได้รับการกำหนดเวิร์กโฟลว์และอินสแตนซ์บริบทที่จะใช้ในการแบ่งปันข้อมูลระหว่างโหนด เมื่อรันเนอร์ถูกดำเนินการแล้วเราสามารถดึงค่าคืนกลับจากบริบทได้หากมี
เรามี FlowRunnerBase คลาสนามธรรมเพื่อให้เราสามารถใช้นักวิ่งที่กำหนดเองของเราขั้นตอนสู่ขั้นตอนกระจาย ฯลฯ ..
ตัวอย่าง Flow Runner
var flowRunner = FlowRunner . Create ( definition , Context . Create ( ) ) ;
var exit = await flowRunner . Start ( ) ;การไหลของชั้นเรียนอย่างที่เราพูดไปก่อนหน้านี้มันเป็น wrapper สำหรับกระบวนการทั้งหมดนี้ตอนนี้มีฟังก์ชันพื้นฐาน แต่ในรุ่นอนาคตจะถูกใช้เป็นคลาสหลักสำหรับการจัดการเวิร์กโฟลว์
var definition = SimpleFlowDefinition . GetDefinition ( ) ;
var context = Context . Create ( ) ;
var flow = Flow . Create ( FlowRunner . Create ( definition , context ) ) ;
var exit = await flow . Run ( ) ;