المكتبة المصممة لإنشاء سير عمل مخصص ، أو أوركز بين المكونات والخدمات الدقيقة وغيرها من أدوات التشغيل الآلي ، التي تم إنشاؤها على الإصدار 6
تم تصميم هذه المكتبة للحصول على نظام بيئي من الكيانات الموجهة إلى التزامن لأي نوع من العمليات. من أبسط العمليات مثل المكالمات بين العديد من فئاتنا إلى عمليات أكثر تعقيدًا مثل المكالمات إلى الخدمات الصغيرة ، وما إلى ذلك ، ومع ذلك ، بطريقة إعلانية وتبحث عن حفظ التعليمات البرمجية من حيث التعشيش الشاق والمعقد لـ "if" ، "Else" ... إلخ.
في هذا المستودع ، ستكون الفئات الأساسية لهذا النظام البيئي ، تم تجميعها تحت مساحة الاسم magnett.automation.core. يمكن استخدام بعض هذه الفصول خارج نطاق إنشاء سير عمل ، لأنها عامة بما يكفي لتكون مفيدة بشكل مستقل.
في مساحة الاسم هذه ، وجدنا فئة المرافق المستخدمة داخل فئات Libray
سياق المفهوم هو شيء عام للغاية ويستخدم في العديد من الحقول. بالنسبة لنا ، سيكون السياق مساحة مشتركة حيث يتم تخزين القيم للمشاركة بين عدة مكونات ، كونها قيم النوع غير المتجانس.
لذلك ، نحن أمام نظام المفتاح/القيمة ، حيث ستكون القيم من أي نوع.
بنية السياق بسيطة ، لا يتم تشكيلها إلا من خلال فئة السياق ، والتي ستكون مدخلاتنا واسترجاعنا من فئة القيم ، وواجهة IconTextVault التي ستكون تعريف قبو حيث يتم تخزين القيم.
بشكل افتراضي ، سيكون لدينا تنفيذ للأيقونة ، حيث سيقوم بتخزين القيم في الذاكرة ، ولكن سيكون مفتوحًا لأي تطبيق آخر يخزن هذه القيم بأي طريقة أخرى.
سنستخدم Class 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 ، وإمكانية الانتقال إلى حالة أخرى باستخدام رموز الإجراءات التي تولد كيان الانتقال ، إلى حالة أخرى ، إلى حالة أخرى.
لا يمكن الانتقال من ولاية إلى أخرى مباشرة ، فقط من خلال الانتقال ، بحيث يكون لدينا نموذج يمكن أن نذهب إليه من إحدى الدول على وجه الخصوص.
يمكن إعطاء دولة بدون انتقالات محددة وهذا يعني أن الدولة طرفية. وبهذه الطريقة ، يمكننا تحديد آلات محدودة أو غير محدودة.
فيما يتعلق بجزء وقت التشغيل ، سيتم تعريف الجهاز من واجهة imachinedefinition ، والتي سيتم إنشاؤها من فئة MachinedEfinitionBuilder .
مثال على رمز تعريف الجهاز
//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 ( ) ;سبق لك أن حددت بعض فئات المساعد مثل contextDefinition ، إنها مجرد فئة تحتوي على حقل سياق ولتجنب الازدواجية مع تعريفات الاسم.
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 ( ) ;
}
}لقد أنشأنا أيضًا مشتركًا في الفئة المجردة التي سنستخدمها كطبقة أساسية لجميع فئات العقدة الخاصة بنا ، وسنستخدمها كوسيلة لضمان أن جميع العقد لديها conxtextDefinition
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 ، حتى نتمكن من استخدام العقد كركب من كل من العملية. في هذا المثال ، لدينا فقط تطبيق المزامنة.
في مثالنا ، سوف نستخدم فقط مزامنة العقد.
مثال العقدة
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 من الفئة الداخلية هي مجرد فئة مساعدة أخرى ، بناء على فئة التعداد مع تعريف رموز الخروج Avaliable لهذه العقدة ، نستخدم أيضًا Somthin Similira
سيحتاج العداء ، لإقامة إنشاء نفسه ، إلى تلقي تعريف سير العمل ومثيل السياق الذي سيتم استخدامه لتبادل المعلومات بين العقد. بمجرد تنفيذ العداء ، يمكننا استرداد قيم الإرجاع من السياق إذا كان هناك أي شيء.
لدينا فئة مجردة FlowRunnerbase حتى نتمكن من تنفيذ المتسابقين المخصصين لدينا ، خطوة إلى الخطوة ، الموزعة ، إلخ ..
مثال Flow Runner
var flowRunner = FlowRunner . Create ( definition , Context . Create ( ) ) ;
var exit = await flowRunner . Start ( ) ;يتدفق الفصل كما قلنا من قبل ، إنه غلاف لكل هذه العملية ، والآن لديه وظائف أساسية ولكن في الإصدارات المستقبلية سيتم استخدامها كفئة رئيسية لإدارة سير العمل.
var definition = SimpleFlowDefinition . GetDefinition ( ) ;
var context = Context . Create ( ) ;
var flow = Flow . Create ( FlowRunner . Create ( definition , context ) ) ;
var exit = await flow . Run ( ) ;