企業級工作流解決方案(十七)--工作流--工作流插件模型


  我們搭建框架,一方面是需要滿足業務的需求、易於后期擴展,另一方面,需要減少開發人員的工作量,讓他們不需要整體理解框架的情況下,照樣能接入團隊進行業務開發。

  WWF工作流開發平台對於很多開發人員都比較陌生,如果讓每一個開發人員都充分的理解WWF的定義時和運行時的機制,再接入工作流開發,不管是時間還是成本都是不能接受的。

  我們需要搭建一套工作流開發框架,把WWF的定義時和運行時的邏輯都高度的抽象出來進行封裝,讓不同的開發者只需要關注業務部分的實現即可。

  工作流插件模型設計圖:

  一個WWF工作流,必然有一個唯一的根活動,一般都為組合活動FlowChart,一個組合活動可以包含任何數量的組合活動或者單個活動,活動與活動之間可以通過連線建立關聯,工作流運行時,從起點根據連線往下面執行活動邏輯。

  WWF允許我們自定義活動,需要實現活動基婁NativeActivity,自定義活動包括自定義活動設計器以及自定義活動本身,在活動設計器中,我們可以定義雙擊活動設計器行為,比如雙擊活動設計器打開活動配置窗體,活動設計器與活動之間的關聯是通過ModelItem關聯起來的,即在活動的ModelItem里面可以存取活動配置信息。

我們可以在自定義活動增加一個屬性,ConfigData,存儲活動的配置信息,流程定義時,通過活動配置窗體配置信息,然后把配置信息序列化為字符串,保存到流程定義模版中,設計時和運行時都可以取出ConfigData信息。

  流程運行時,可以把運行時信息持久化到外部存儲介質,可以是數據庫或者Xml,持久化時,需要指定恢復的書簽值,下次運行時,傳遞書簽值到流程引擎,就可以恢復到指定的活動。

一個活動可以定義一個插件與之對應,活動只做一些簡單的配置以及對插件的封裝,基本不處理具體業務,真正的業務執行交由插件來完成。業務插件也不需要關心活動是什么,以及怎么封裝的,只需要執行業務邏輯,需要實現以下幾部分內容:

插件需要定義插件配置窗體,雙擊活動時動態創建窗體,彈出配置窗體,把活動定義時上下文信息傳遞到配置窗體中,在配置窗體中就可以讀取和寫入配置信息,由框架負責存儲配置信息。插件的Execute方法為運行時活動執行的方法,需要把流程的配置信息取出來做為參數傳遞給插件的Execute方法。CallbackExecute為恢復書簽時執行的方法,工作流恢復時調用此方法。

插件執行定義時活動運行時是不知道工作流的信息的,但是有些時候,需要讀取流程的信息,比如運行時工作流的參數集合,定義時流程實例的一些信息,那么這些信息都從IPluginContext插件上下文中獲取。

  關於ConfigData,插件框架定義的是string,插件可以定義自己的業務配置接口,定義時序列化為字符串,運行是反序列化為業務配置接口,方便業務處理。

流程發起時會創建流程實例,流程結束時,會更新流程實例狀態,流程執行到每一個活動,會創建流程審批項以及流程跟蹤信息,流程審批項可以定義TaskId(Guid)做為書簽值,某一個用戶打開任務時,執行審批,根據TaskId恢復流程運行。

  自定義活動基類:

public abstract class BaseActivity : NativeActivity
    {
        private object wfworkflowContext;
        #region Property

        /// <summary>
        /// 活動對應的插件
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IPlugin Plugin { get; set; }

        /// <summary>
        /// 活動Id
        /// </summary>
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string ActivityId {
            get
            {
                return this.Id;
            }
        }

        /// <summary>
        /// 工作流配置信息
        /// </summary>
        [Browsable(false)]
        public string ConfigData { get; set; }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public abstract string ActivityIcon { get; }

        #endregion

        protected BaseActivity()
        {
            Plugin = GetPlugin();
        }

        protected abstract IPlugin GetPlugin();

        protected abstract override void Execute(NativeActivityContext context);

        protected void SetTryRunParams(PluginContext pluginContext, WFWorkflowContext wfworkflowContext)
        {
            var unitOfWorkManager = IocManager.Instance.Resolve<IUnitOfWorkManager>();
            UnitOfWorkOptions unitOfWorkOptions = new UnitOfWorkOptions();
            using (var uow = unitOfWorkManager.Begin(unitOfWorkOptions))
            {
                var wf_WF_FlowItemRepository = IocManager.Instance.Resolve<IRepository<WF_FlowItem, Guid>>();
                var wf_WF_FlowTrackItemRepository = IocManager.Instance.Resolve<IRepository<WF_FlowTrack, Guid>>();
                WF_FlowItem flowItem = wf_WF_FlowItemRepository.Get(wfworkflowContext.WFActivityRunData.FlowItemId);
                WF_FlowTrack flowTrack = wf_WF_FlowTrackItemRepository.GetAll()
                    .Where(r => (r.WF_FlowInstance_Id == flowItem.WF_FlowInstance_Id) && (r.ActivityId == Id)).OrderByDescending(r => r.TrackTime).FirstOrDefault();
                if (flowTrack != null && !string.IsNullOrEmpty(flowTrack.ActivityParam))
                {
                    pluginContext.RuntimeService.SetArgValue(flowTrack.ActivityParam, flowTrack.RouteValue);
                }
                uow.Complete();
            }
        }
    }

  插件基類:

public interface IPlugin
    {
        /// <summary>
        /// Plugin上下文
        /// </summary>
        IPluginContext PluginContext { get; set; }

        /// <summary>
        /// 工作流運行時調用的方法
        /// </summary>
        /// <param name="configData">ConfigData</param>
        /// <returns>調用反回值</returns>
        bool Execute(IConfigData configData);

        /// <summary>
        /// 返回工作流設計時,活動彈出的窗體
        /// </summary>
        /// <param name="configData">ConfigData</param>
        /// <param name="workflowDesignService">工作流設計時上下文</param>
        /// <param name="typeFact">事實庫類型</param>
        /// <returns>活動彈出窗體</returns>
        IConfigForm GetConfigForm(IConfigData configData, WorkflowDesignService workflowDesignService, List<TemplateModel> factModel, Guid flowDefineId);

        /// <summary>
        /// 恢復書簽調用的回調方法
        /// </summary>
        /// <param name="configData">ConfigData</param>
        /// <param name="wfactivityRunData">工作流運行時數據</param>
        /// <returns>調用反回值</returns>
        bool CallbackExecute(IConfigData configData, IWFActivityRunData wfactivityRunData);
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM