澜静 發表於 2024-6-6 11:14:00

C# .NET 6 使用WorkFlow Core 创建工作审批流

<h2>1,背景</h2>
<p>  工作流思想在上世纪60年代就有人提出过;70年代就有人开始尝试,但是由于当时许多的限制,工作流一直没有成功的被实现;80年代才出现第一批成功的工作流系统;90年代工作流技术走向了第一个发展高峰期;90年代后至今工作流出现了很多版本,但是主旨还是不变的,为了使我们的工作变得更加高效。</p>
<p>  通俗点,我们经常使用的OA系统上。关于一个材料的申报,又或者个人的请假。这些流程就属于工作流(工作审批流)。其中对于审批人和各个节点是可以动态操作的。</p>
<p>  <strong>工作流可以通过数据库设计的形式实现,也可以使用第三方的框架Elsa,Workflow Core。本文使用第二种,并详细的介绍一下代码实现和json实现工作流程。</strong></p>
<h2>2,安装</h2>
<p>  使用Nuget包管理工具安装以下的包:  </p>
<p>    Workflow Core&nbsp;3.10.0          <span style="font-family: 宋体, &quot;Songti SC&quot;"><em>核心包不解释</em></span></p>
<p>    WorkflowCore.DSL&nbsp;3.10.0        <em>j<span style="font-family: 宋体, &quot;Songti SC&quot;">son或者yaml注入需要</span></em></p>
<p>    WorkflowCore.Persistence.MySQL    <span style="font-family: 宋体, &quot;Songti SC&quot;"><em>持久化</em></span></p>
<h2>3,文档</h2>
<p>  JSON / YAML Definitions - Workflow Core (workflow-core.readthedocs.io)</p>
<p>&nbsp;</p>
<p>  WorkFlowCore 加载Json文件 - 编程代码 (cscoder.cn)</p>
<p>&nbsp;</p>
<h2>4,例子</h2>
<h3>1,创建项目</h3>
<p>  控制台或者WebApi项目均可,这里拿WebApi项目举例。(版本用的是.net 6)</p>
<h3>2,添加工步</h3>
<p>  工步文件需要继承StepBody。现在添加一个Hello.cs和Goodbye的工步,代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkflowCore.Interface;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkflowCore.Models;

</span><span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.HelloWord.Steps
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Hello : StepBody
    {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">override</span><span style="color: rgba(0, 0, 0, 1)"> ExecutionResult Run(IStepExecutionContext context)
      {
            Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Hello World!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ExecutionResult.Next();
      }
    }
}</span></pre>
</div>
<p>&nbsp;</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkflowCore.Interface;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkflowCore.Models;

</span><span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.HelloWord.Steps
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Goodbye : StepBody
    {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">override</span><span style="color: rgba(0, 0, 0, 1)"> ExecutionResult Run(IStepExecutionContext context)
      {
            Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Goodbye World!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ExecutionResult.Next();
      }
    }
}</span></pre>
</div>
<h3>3,添加工作流文件</h3>
<p>  工作流文件需要继承IWorkflow。现在开始添加:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkflowCore.Interface;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.HelloWord.Steps;

</span><span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.HelloWord
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> HelloWorldWorkflow : IWorkflow
    {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Id =&gt; <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">HelloWorld</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;

      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> Version =&gt; <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;

      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Build(IWorkflowBuilder&lt;<span style="color: rgba(0, 0, 255, 1)">object</span>&gt;<span style="color: rgba(0, 0, 0, 1)"> builder)
      {
            builder
                .StartWith</span>&lt;Hello&gt;<span style="color: rgba(0, 0, 0, 1)">()
                .Then</span>&lt;Goodbye&gt;<span style="color: rgba(0, 0, 0, 1)">();
      }
    }
}</span></pre>
</div>
<h3>4,配置和启动</h3>
<p>  基本数据都准备好了之后,在项目启动文件进行一下配置。代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.AspNetCore.Mvc;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Xml.Linq;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkflowCore.Interface;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkflowCore.Services;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkflowCore.Services.DefinitionStorage;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.Utils;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.AskForLeave.Model;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.AskForLeave;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.HelloWord;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.IfStatement;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.IfStatement.Model;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.Json.Steps;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.SimpleDecision;

</span><span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Program
    {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Main(<span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">[] args)
      {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> builder =<span style="color: rgba(0, 0, 0, 1)"> WebApplication.CreateBuilder(args);
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Add services to the container.</span>
<span style="color: rgba(0, 0, 0, 1)">            builder.Services.AddAuthorization();
            builder.Services.AddControllers();
            builder.Services.AddLogging(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> WorkflowCore需要用到logging service
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">持久化</span>
            builder.Services.AddWorkflow(cfg =&gt;<span style="color: rgba(0, 0, 0, 1)">
            {
                cfg.UseMySQL(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">server=127.0.0.1;Database=Workflow;Uid=root;Pwd=*****</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(0, 0, 255, 1)">true</span>, <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
            });
            builder.Services.AddWorkflowDSL();</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">用来注入json和yaml</span>

            <span style="color: rgba(0, 0, 255, 1)">var</span> app =<span style="color: rgba(0, 0, 0, 1)"> builder.Build();

            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">核心注入方法</span>
<span style="color: rgba(0, 0, 0, 1)">            UseWorkflow(app);

            app.UseAuthorization();
            app.MapControllers();
            app.Run();
      }


      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> UseWorkflow(WebApplication app)
      {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> host = app.Services.GetService&lt;IWorkflowHost&gt;<span style="color: rgba(0, 0, 0, 1)">();

            </span><span style="color: rgba(0, 0, 255, 1)">#region</span> 工步注册
            <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">c#代码注册</span>
            host?.RegisterWorkflow&lt;HelloWorldWorkflow&gt;<span style="color: rgba(0, 0, 0, 1)">();
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">json注册</span>
            <span style="color: rgba(0, 0, 255, 1)">#endregion</span><span style="color: rgba(0, 0, 0, 1)">

            host</span>?<span style="color: rgba(0, 0, 0, 1)">.Start();
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过DI获取IHostApplicationLifetime实例</span>
            <span style="color: rgba(0, 0, 255, 1)">var</span> applicationLifetime = app.Services.GetService(<span style="color: rgba(0, 0, 255, 1)">typeof</span>(IHostApplicationLifetime)) <span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> IHostApplicationLifetime;
            applicationLifetime</span>?.ApplicationStopping.Register(() =&gt;<span style="color: rgba(0, 0, 0, 1)">
            {
                host</span>?<span style="color: rgba(0, 0, 0, 1)">.Stop();
            });
      }


    }
}</span></pre>
</div>
<p>&nbsp;</p>
<p>  这个时候我们添加api控制器进行调用这个helloworld的流程。代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.AspNetCore.Http;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.AspNetCore.Mvc;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.Extensions.Configuration;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.Extensions.DependencyInjection;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.Extensions.Hosting;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Microsoft.Extensions.Logging;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Newtonsoft.Json;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> Newtonsoft.Json.Linq;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Diagnostics;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Net.Http.Json;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Text.Json.Nodes;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkflowCore.Interface;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkflowCore.Models;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkflowCore.Services;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkflowCore.Services.DefinitionStorage;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.Utils;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.AskForLeave.Model;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.SimpleDecision;

</span><span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.Controllers
{
    </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)]
   
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> TestApiController : ControllerBase
    {
      </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> IWorkflowController WorkflowService;
      </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> IWorkflowHost WorkflowHost;
      </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> TestApiController(IWorkflowController workflowService, IWorkflowHost workflowHost)
      {
            WorkflowService </span>=<span style="color: rgba(0, 0, 0, 1)"> workflowService;
            WorkflowHost </span>=<span style="color: rgba(0, 0, 0, 1)"> workflowHost;
      }

      
      
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCoreTestDemo()
      {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">var initialData = new LeaveRequestData
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">{
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">    RequestId = "11111",
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">    RequestMsg = "开始请假"
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">};

            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">WorkflowHost.StartWorkflow("LeaveRequestWorkflow", 1, initialData);</span>
<span style="color: rgba(0, 0, 0, 1)">
            WorkflowService.StartWorkflow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">HelloWorld</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">true</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
      }

      

    }
}</span></pre>
</div>
<h3>5,效果展示</h3>
<p>  启动后调用我们的控制器方法,然后观看console 的变化,如图:</p>
<p><img src="https://img2024.cnblogs.com/blog/1266469/202406/1266469-20240606105751442-1536392441.png" alt="" loading="lazy"></p>
<p><img src="https://img2024.cnblogs.com/blog/1266469/202406/1266469-20240606105800548-551228528.png" alt="" loading="lazy"></p>
<p>&nbsp;</p>
<h3>6,请假单流程</h3>
<p>  请假单的流程创建的话需要用到等待的函数,等待管理员进行审核后进行下一步的操作。请假单的流程代码如下:</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> LeaveRequestData
    {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> RequestId { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> ManagerApproved { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">bool</span> HRApproved { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> RequestMsg { <span style="color: rgba(0, 0, 255, 1)">get</span>; <span style="color: rgba(0, 0, 255, 1)">set</span><span style="color: rgba(0, 0, 0, 1)">; }
    }</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkflowCore.Interface;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.AskForLeave.Model;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.AskForLeave.Steps;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.SimpleDecision.Steps;

</span><span style="color: rgba(0, 0, 255, 1)">namespace</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCore_Test.WorkFlows.AskForLeave
{
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span> AskForLeaveWorkflow : IWorkflow&lt;LeaveRequestData&gt;<span style="color: rgba(0, 0, 0, 1)">
    {
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span> Id =&gt; <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">LeaveRequestWorkflow</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span> Version =&gt; <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">;

      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Build(IWorkflowBuilder&lt;LeaveRequestData&gt;<span style="color: rgba(0, 0, 0, 1)"> builder)
      {
            builder.StartWith(context </span>=&gt; Console.WriteLine(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">提交请假申请</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">))
                .Activity(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">manage-audit</span><span style="color: rgba(128, 0, 0, 1)">"</span>, (data) =&gt;<span style="color: rgba(0, 0, 0, 1)"> data.RequestMsg)
                  .Output(data </span>=&gt; data.ManagerApproved, step =&gt;<span style="color: rgba(0, 0, 0, 1)"> step.Result)
                .Then</span>&lt;ManagerApprovalStep&gt;().Input(step =&gt; step.AuditDataInfo, data =&gt;<span style="color: rgba(0, 0, 0, 1)"> data)
                .If(data </span>=&gt;<span style="color: rgba(0, 0, 0, 1)"> data.ManagerApproved)
                  .Do(then </span>=&gt; then.StartWith(context =&gt; Console.WriteLine(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">经理审核</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)));

            
      }
    }
}</span></pre>
</div>
<p>  然后创建好之后,在启动文件进行注册一下:</p>
<div class="cnblogs_code">
<pre>            host?.RegisterWorkflow&lt;AskForLeaveWorkflow, LeaveRequestData&gt;();</pre>
</div>
<p>  好了,接下来我们就可以用接口的形式进行模拟了。首先我们新增一个接口用来模拟申请请求代码如下:</p>
<div class="cnblogs_code">
<pre>      
      
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCoreTestDemo()
      {
            </span><span style="color: rgba(0, 0, 255, 1)">var</span> initialData = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> LeaveRequestData
            {
                RequestId </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">11111</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
                RequestMsg </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">开始请假</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
            };

            WorkflowHost.StartWorkflow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">LeaveRequestWorkflow</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">, initialData);

            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">WorkflowService.StartWorkflow("HelloWorld");</span>
            <span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">true</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
      }</span></pre>
</div>
<p>  然后创建一个管理员的审批方法,用来审核通过或者拒绝。代码如下:</p>
<div class="cnblogs_code">
<pre>      
      
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">async</span> Task&lt;<span style="color: rgba(0, 0, 255, 1)">string</span>&gt;<span style="color: rgba(0, 0, 0, 1)"> WorkFlowCoreTestDemo4()
      {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取待决活动</span>
            <span style="color: rgba(0, 0, 255, 1)">var</span> approval = <span style="color: rgba(0, 0, 255, 1)">await</span> WorkflowHost.GetPendingActivity(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">manage-audit</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">worker1</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
         

            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (approval != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
            {
                Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">需要批准的</span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> approval.Parameters);
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">提交活动成功</span>
                <span style="color: rgba(0, 0, 255, 1)">await</span> WorkflowHost.SubmitActivitySuccess(approval.Token, <span style="color: rgba(0, 0, 255, 1)">true</span>);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">true,代表审批通过。逻辑验证在步骤里面</span>
<span style="color: rgba(0, 0, 0, 1)">            }
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">请假工作流</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
      }</span></pre>
</div>
<p>  好了,这样就形成闭环了。大家可以在postman上请求测试一下,观察console的变化了。</p>
<h3>7,json注入</h3>
<p>  最后就是json注入的方式了,这种方式也是目前我比较倾向的方式,和前端对接就很方便的。前端按照固定的格式给后端传入json数据,后端根据json数据解析工步进行开启工作流。</p>
<p>  首先需要创建一个json文件,json文件代码如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Id</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">HelloWorldJson</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Version</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Steps</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: [
    {
      </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Id</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Hello</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
      </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">StepType</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">,
      </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">NextStepId</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Bye</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    },
    {
      </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Id</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Bye</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
      </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">StepType</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">

    }
]
}</span></pre>
</div>
<p>  然后在启动文件配置,注入一下json工作流:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">json注册</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> loader = app.Services.GetService&lt;IDefinitionLoader&gt;<span style="color: rgba(0, 0, 0, 1)">();   
</span><span style="color: rgba(0, 0, 255, 1)">var</span> json = System.IO.File.ReadAllText(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">WorkFlows/Json/JsonYaml.json</span><span style="color: rgba(128, 0, 0, 1)">"</span>);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 假设文件位于程序运行目录
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 【json注入时候,stepType写这个程序集的类名】获取并打印全限定名,包括程序集名称
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Type myClassType = typeof(HelloWorldStep);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">string fullAssemblyClassName = myClassType.AssemblyQualifiedName;</span>
loader?.LoadDefinition(json, Deserializers.Json);</pre>
</div>
<p>  到这里就可以了,创建一个api方法来调用看看:</p>
<div class="cnblogs_code">
<pre>      
      
      </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> WorkFlowCoreTestDemo6()
      {</span><span style="color: rgba(0, 0, 0, 1)">
            WorkflowHost.StartWorkflow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">HelloWorldJson</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">1</span>, <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">;</span>
      }</pre>
</div>
<p>  到这里就可以实现json注入工作流了。不过细心的朋友就发现了,我给的json文件中的step的type为什么是空的呢?是因为StepType取的是项目程序集工步的类名称,因为我的电脑项目和你们的项目不一样,所以这里没有写。大家可以自行百度搜搜看,我这里还是放一下我的json例子吧。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Id</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">HelloWorldJson</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Version</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Steps</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: [
    {
      </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Id</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Hello</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
      </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">StepType</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">WorkFlowCore_Test.WorkFlows.Json.Steps.HelloWorldStep, WorkFlowCore-Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
      </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">NextStepId</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Bye</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
    },
    {
      </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Id</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Bye</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
      </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">StepType</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">WorkFlowCore_Test.WorkFlows.Json.Steps.HelloWorldStep, WorkFlowCore-Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">

    }
]
}</span></pre>
</div>
<p>&nbsp;</p>
<h2>5,结语</h2>
<p>  例子备注写的比较多,就不多赘述了。有问题的话就留言吧,感谢观看~</p>

</div>
<div id="MySignature" role="contentinfo">
    从前慢,车马慢。
一生只爱一个人。<br><br>
来源:https://www.cnblogs.com/BFMC/p/18233359
頁: [1]
查看完整版本: C# .NET 6 使用WorkFlow Core 创建工作审批流