`

使用本地服务异步执行自定义活动业务逻辑

阅读更多

通常情况下我们开发的自定义活动的业务逻辑都是写在Execte方法中的,由于一个工作流实例在单一的线程上执行,这样当工作流在执行到这个活动的时候,该活动就独占了整个工作流的线程,如果该自定义活动需要做很长时间的任务,那么此时就不能处理工作流中的其他请求。所以我们不建议把所有的业务逻辑都放到Execute方法中去执行。

1.我们可以将活动的业务逻辑放到本地服务中去异步执行,下面我们用一个例子来说明,建立一个顺序型工作流控制台项目,首先我们先写两个类CaryWork和CaryWorkResult,分别代表我们要执行的工作项和返回的结果,代码如下:

[Serializable]
public class CaryWork
{
    public Guid InstanceId { get; set; }
    public String WorkItem { get; set; }
    public String ResultQueueName { get; set; }

    public CaryWork( Guid InstanceId, String ResultQueueName, String WorkItem)
    {
        this.InstanceId = InstanceId;
        this.ResultQueueName = ResultQueueName;
        this.WorkItem = WorkItem;
    }
}
[Serializable]
public class CaryWorkResult
{
   public String Result { get; set; }
public CaryWorkResult(String Result) { this.Result = Result; } }

ResultQueueName 表示返回结果的队列名称。
InstanceId表示工作流的id
WorkItem 表示要执行的任务


2.然后我们开始编写本地服务的部分,首先声明一个接口,接口中的方法将会在自定义活动中调用,代码如下:
public interface ILongTaskServices
{
   voidDoLongTaskWork(CaryWorkworkToDo);
}

然后实现该接口,代码如下:

public class LongTaskServices : WorkflowRuntimeService,ILongTaskServices
{
   private Random _random = new Random();

   public void DoLongTaskWork(CaryWork workToDo)
   {
       ThreadPool.QueueUserWorkItem(TPWorkCallback, workToDo);
       Console.WriteLine("工作项队列: {0}",workToDo.WorkItem);
   }       

   private void TPWorkCallback(Object state)
   {
       CaryWork workitem = state as CaryWork;
       WorkflowInstance instance = Runtime.GetWorkflow(workitem.InstanceId);            
       Int32 msw = _random.Next(1000, 5000);
       Thread.Sleep(msw);
       CaryWorkResult response = new CaryWorkResult(String.Format(
"工作项-{0}返回-{1}", workitem.WorkItem, msw)); instance.EnqueueItem(workitem.ResultQueueName, response, null, null); } }
在本地服务中我们使用线程池来执行我们要完成的任务,我们使用Thread的Sleep方法假定每项任务要执行的时间,完
成后会返回CaryWorkResult对象。
 
3.现在我们实现我们的自定义活动,代码如下:
public partial class LongTaskActivity : Activity,IActivityEventListener<QueueEventArgs>
{
public static DependencyProperty WorkItemProperty = DependencyProperty.Register("WorkItem", typeof(string), typeof(LongTaskActivity)); [DescriptionAttribute("WorkItem")] [BrowsableAttribute(true)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)] public string WorkItem { get{ return ((string)(base.GetValue(LongTaskActivity.WorkItemProperty)));} set{ base.SetValue(LongTaskActivity.WorkItemProperty, value);} } private String queueName = Guid.NewGuid().ToString(); public LongTaskActivity() { InitializeComponent(); } protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { ILongTaskServices longRunningService=executionContext.GetService(typeof
(ILongTaskServices)) as ILongTaskServices; WorkflowQueuingService queueService= executionContext.GetService(typeof
(WorkflowQueuingService))as WorkflowQueuingService;
WorkflowQueue queue = queueService.CreateWorkflowQueue(queueName, true); queue.RegisterForQueueItemAvailable(this); CaryWork request = new CaryWork(this.WorkflowInstanceId, queueName, WorkItem); Console.WriteLine("调用本地服务: {0}", WorkItem); longRunningService.DoLongTaskWork(request); return ActivityExecutionStatus.Executing; } public void OnEvent(object sender, QueueEventArgs e) { ActivityExecutionContext aec = sender as ActivityExecutionContext; WorkflowQueuingService queueService = aec.GetService<WorkflowQueuingService>(); WorkflowQueue queue = queueService.GetWorkflowQueue(e.QueueName); if (queue != null && queue.Count > 0) { CaryWorkResult response = queue.Dequeue() as CaryWorkResult; if (response != null) Console.WriteLine("结果为: {0}", response.Result); } queueService.DeleteWorkflowQueue(e.QueueName); aec.CloseActivity(); }
}
在自定义活动中我们去调用本地服务的方法来执行工作项,queue工作流队列被创建,Execute方法中返回
ActivityExecutionStatus.Executing表示工作项没有执行完成,完成后会在OnEvent事件中向控制台输出结果,并调
用AEC的CloseActivity方法来关闭活动。
 
4.设计工作流,我们在工作流设计器中拖一个ParallelActivity活动,并向每个分支中拖入一个我们自定义的活动,
并设置其WorkItem属性,如图:
ActivitLocalService2 
 
5.在宿主程序我们需要加载本地服务到工作流引擎中,代码如下:
static void Main(string[] args)
{
    using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
    {
        AutoResetEvent waitHandle = new AutoResetEvent(false);
        workflowRuntime.WorkflowCompleted += delegate(object sender,WorkflowCompletedEventArgs e)
{waitHandle.Set();}; workflowRuntime.WorkflowTerminated+=delegate(object sender,WorkflowTerminatedEventArgs e) { Console.WriteLine(e.Exception.Message); waitHandle.Set(); }; workflowRuntime.AddService(new LongTaskServices()); WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof
(CaryLongWF.LongTaskWorkflow)); Console.WriteLine("---工作流执行开始---"); instance.Start(); waitHandle.WaitOne(); Console.WriteLine("---工作流执行结束---"); } }
 
6.运行程序执行结果如下:

ActivitLocalService1 

从结果上我们有的时候会看到WorkItem1和WorkItem2的顺序会颠倒,这是因为我们在本地服务中做了随机的Sleep动作。

分享到:
评论

相关推荐

    自定义rpc框架

    4. **服务提供者处理**:服务提供者接收到请求后,反序列化数据,执行对应的业务逻辑,然后将结果再次序列化并返回给服务消费者。 5. **结果处理**:服务消费者接收到响应后,对结果进行反序列化,完成调用过程。 ...

    kindeditor文本编辑器实例(包含本地图片上传及浏览服务器方法)

    自定义按钮可以绑定特定的函数,例如执行一段JavaScript代码或发送Ajax请求,以实现特定的业务逻辑。 4. **安装与集成** 首先,你需要从KindEditor官方网站下载最新版本的源码包,然后将包含CSS、JavaScript和图片...

    DataGridView自定义控件。。。

    8. **数据绑定**:除了使用默认的数据源绑定,还可以实现自定义的数据绑定逻辑,支持更复杂的数据模型。 9. **行状态管理**:可以添加额外的行状态信息,如行的选中、禁用、高亮等,通过自定义属性来实现。 10. **...

    自定义城市选择轮滑

    这样,当用户在Webview中选择城市后,可以选择调用原生方法来更新应用的状态或执行其他业务逻辑。 4. **数据加载**:城市数据可能来自本地资源文件,也可能通过网络API获取。本地数据可以通过JSON格式存储,然后在...

    如何使用Java Spring Boot执行RAG架构GenAI项目的示例.zip

    6. **业务逻辑服务层**: - 定义一个`GenAiTaskService`,它是业务逻辑的中心,负责处理GenAI任务的状态转换。这里可以集成GenAI算法,如训练模型或执行NLP任务。 7. **状态转换逻辑**: - 实现RAG状态转换逻辑,...

    自定义轮播图

    在自定义轮播图中,可以为每个图片添加点击监听器(OnClickListener),当用户点击图片时,触发相应的回调方法,执行开发者预设的操作,比如跳转到详情页面或者执行其他业务逻辑。 最后,"无限轮播"是指当图片轮播...

    jar包直接当做web服务,netty负责http协议,配合springMVC,再也不用tomcat了

    它提供了一个模型-视图-控制器(MVC)架构,帮助开发者分离业务逻辑、数据处理和用户界面。在没有Tomcat的情况下,Spring MVC仍然可以处理路由、请求处理和视图渲染,但是由于不支持JSP,我们需要寻找其他方式来呈现...

    ASP.NET 控件的使用

    15.3.3 创建业务逻辑层 492 15.3.4 创建数据访问层 494 15.4 小结 497 第16章 使用ObjectDataSource控件 498 16.1 使用ObjectDataSource控件表示对象 498 16.1.1 绑定到组件 499 16.1.2 绑定到DataReader 500 ...

    图片缓存自定义

    Observable负责监听网络请求或本地缓存,Subscriber则负责订阅这些事件并在适当的时候执行相应的操作,如将新图片加载到视图或者更新缓存。 具体实现步骤如下: 1. 创建一个LRUCache实例,作为图片缓存容器。...

    wf工作流资料<转自网上的笔记>

    "坚持学习WF(11)工作流通信与队列"关注WF如何与其他组件或服务进行通信,可能包括使用队列进行异步通信的场景。 "坚持学习WF(12)使用EventHandlingScopeActivity活动"更进一步,专门讲解EventHandlingScopeActivity...

    Android中实现异步加载图片的Demo

    这些库封装了复杂的异步加载、内存管理、缓存策略等细节,让开发者能更专注于业务逻辑。 总之,异步加载图片是Android开发中的核心技能之一,通过理解和实践这个Demo,开发者可以深入理解Android应用的性能优化,并...

    CRM4.0中Plug-In使用研究文档

    CRM4.0还允许开发人员创建复合插件,即多个插件组合成一个逻辑单元,以及使用工作流活动与插件配合,实现更复杂的业务逻辑。 总结来说,CRM4.0中的Plug-In提供了一种灵活的方式,让企业能够根据自身需求定制CRM...

    Mule ESB 3 User Guide

    在Mule中,可以使用flows、patterns和服务来组织和执行业务逻辑。指南会详细说明它们之间的区别以及在特定场景下应该如何选择。 3. **服务编排**: 当涉及到多个服务交互时,flows的使用将变得至关重要。使用...

    dynamic 365 插件注册工具

    这些类库包含了特定业务逻辑,当特定事件触发时(如创建、更新或删除记录),系统会执行这些逻辑。插件可以是同步的,与主要操作同时执行,也可以是异步的,以避免阻塞用户界面。 插件注册工具的使用通常涉及以下几...

    RSS资源后台服务

    【RSS资源后台服务】是一...通过自动化RSS信息的抓取和处理,它可以帮助开发者减轻维护负担,专注于更高级别的业务逻辑开发。同时,提供的源码意味着用户可以根据自身需求进行定制和扩展,增强了系统的适应性和灵活性。

    建立能与访问者进行相互通

    根据请求内容,服务端执行相应的业务逻辑,如数据库查询、计算等,并将结果封装成响应返回给访问者。 为了使通信双向化,服务端需要有能力不仅发送数据,还能接收来自访问者的反馈。这可能涉及到长连接、WebSocket...

    业务加载中显示等待图片

    在IT行业中,用户体验是至关重要的一个方面,尤其是在处理复杂业务逻辑和数据加载时。"业务加载中显示等待图片"这个话题直接关乎用户界面(UI)的设计和用户体验(UX)。当用户进行操作,如点击按钮、提交表单或加载...

    delphi 调用 webservice 生成unit 的webservice unit 文件的工具

    总之,"Delphi调用WebService生成unit的WebService unit文件的工具"是一个非常实用的功能,它简化了Delphi与Web服务之间的交互,使开发者能更专注于业务逻辑,而不是底层通信细节。通过导入WSDL文件并生成对应的Unit...

    Layui tree 255 可本地执行,样式齐全的demo.rar

    在提供的压缩包"255 可本地执行,样式齐全的demo.rar"中,包含了Layui的tree组件的示例代码,这将帮助我们更深入地理解和使用Layui Tree。 首先,Layui Tree是一个用于展示层级关系数据的组件,通常用于目录结构、...

    Android-一个让http接口调用跟调用本地方法一样自然优雅的项目

    总的来说,这个项目提供了一种高效且优雅的方式来调用HTTP接口,使Android开发者能更专注于业务逻辑,而不是网络通信的底层实现。它通过代理模式和注解驱动的设计,实现了HTTP调用的自动化,提升了开发体验。在实际...

Global site tag (gtag.js) - Google Analytics