这个工作流异常时常能见到: Event "SubmitEvent" on interface type "WorkflowConsoleApplication2.ISalesOrderService" for instance id "8ed729b9-1dd1-46a2-b7ef-fb5a75eeb7fd" cannot be delivered.
看ms的帖子说有多种可能导致此异常, 因此, 在这里罗列总结一下自己曾经遇到过的和解决方法.
1.参数序列化的问题.
1.1 先从一个状态机工作流的例子开始, 比如说要处理订单状态, 提交, 审批通过或拒绝, 结束.
先把工作流鸟瞰截图share一下, 简简单单, 总共三个状态, 每个步骤里一个handleExternalEventActivity, 一个自定义的CodeAcitvity和一个SetStateActivity.
1.2 开始从头描述代码
要处理的订单类代码:
using System;
using System.Collections.Generic;using System.Linq;using System.Text;namespace WorkflowConsoleApplication2
{ public class SalesOrder { public int SalesOrderID { set; get; } public string CustomerName { set; get; } public string ProductName { set; get; } public int Amount { set; get; } public decimal UnitPrice { set; get; } public decimal TotalMoney { set; get; } public int Status { set; get; } }}
服务接口:
using System;
using System.Collections.Generic;using System.Linq;using System.Text;using System.Workflow.Activities;namespace WorkflowConsoleApplication2
{ [ExternalDataExchange] public interface ISalesOrderService { event EventHandler<SalesOrderArgs> SubmitEvent; event EventHandler<SalesOrderArgs> ApprovalEvent; event EventHandler<SalesOrderArgs> RejectEvent; }}
本地服务代码:
using System;
using System.Collections.Generic;using System.Linq;using System.Text;namespace WorkflowConsoleApplication2
{ public class SalesOrderService: ISalesOrderService { public event EventHandler<SalesOrderArgs> SubmitEvent; public event EventHandler<SalesOrderArgs> ApprovalEvent; public event EventHandler<SalesOrderArgs> RejectEvent;public void FireSubmitEvent(Guid instanceID, SalesOrder salesOrder)
{ if (SubmitEvent != null) { SalesOrderArgs args = new SalesOrderArgs(instanceID, salesOrder); SubmitEvent(null, args); } }public void FireApprovalEvent(Guid instanceID, SalesOrder salesOrder)
{ if (ApprovalEvent != null) { SalesOrderArgs args = new SalesOrderArgs(instanceID, salesOrder); ApprovalEvent(null, args); } }public void FireRejectEvent(Guid instanceID, SalesOrder salesOrder)
{ if (RejectEvent != null) { SalesOrderArgs args = new SalesOrderArgs(instanceID, salesOrder); RejectEvent(null, args); } } }}
事件参数类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Workflow.Activities;namespace WorkflowConsoleApplication2
{ [Serializable] public class SalesOrderArgs : ExternalDataEventArgs { public SalesOrder SalesOrder { set; get; }public SalesOrderArgs(Guid instanceID, SalesOrder salesOrder) : base(instanceID)
{ this.SalesOrder = salesOrder; } }}
工作流类:
using System;
using System.ComponentModel;using System.ComponentModel.Design;using System.Collections;using System.Linq;using System.Workflow.ComponentModel.Compiler;using System.Workflow.ComponentModel.Serialization;using System.Workflow.ComponentModel;using System.Workflow.ComponentModel.Design;using System.Workflow.Runtime;using System.Workflow.Activities;using System.Workflow.Activities.Rules;namespace WorkflowConsoleApplication2
{ public sealed partial class Workflow1 : StateMachineWorkflowActivity { public static DependencyProperty SalesOrderArgsProperty = DependencyProperty.Register("SalesOrderArgs", typeof(SalesOrderArgs), typeof(Workflow1));[Description("SalesOrderArgs")]
[Category("SalesOrderArgs Category")] [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public SalesOrderArgs SalesOrderArgs { get { return ((SalesOrderArgs)(base.GetValue(Workflow1.SalesOrderArgsProperty))); } set { base.SetValue(Workflow1.SalesOrderArgsProperty, value); } }public Workflow1()
{ InitializeComponent(); }private void HandleSumitInvoked(object sender, ExternalDataEventArgs e)
{ Console.WriteLine("HandleSumitInvoked"); }private void HandleApprovalInvoked(object sender, ExternalDataEventArgs e)
{ Console.WriteLine("HandleApprovalInvoked"); }private void HandleRejectInvoked(object sender, ExternalDataEventArgs e)
{ Console.WriteLine("HandleRejectInvoked"); }}
}
自定义CodeActivity类,其它两类一样,就不贴出来了:
using System;
using System.ComponentModel;using System.ComponentModel.Design;using System.Collections;using System.Linq;using System.Workflow.ComponentModel;using System.Workflow.ComponentModel.Design;using System.Workflow.ComponentModel.Compiler;using System.Workflow.ComponentModel.Serialization;using System.Workflow.Runtime;using System.Workflow.Activities;using System.Workflow.Activities.Rules;namespace WorkflowConsoleApplication2
{ public partial class SubmitActivity : Activity { public static DependencyProperty SalesOrderArgsProperty = DependencyProperty.Register("SalesOrderArgs", typeof(SalesOrderArgs), typeof(SubmitActivity));[Description("SalesOrderArgs")]
[Category("SalesOrderArgs Category")] [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public SalesOrderArgs SalesOrderArgs { get { return ((SalesOrderArgs)(base.GetValue(SubmitActivity.SalesOrderArgsProperty))); } set { base.SetValue(SubmitActivity.SalesOrderArgsProperty, value); } }public SubmitActivity()
{ InitializeComponent(); }protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{ this.SalesOrderArgs.SalesOrder.Status = 0; return base.Execute(executionContext); } }}
启动Main函数:
using System;
using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Workflow.Runtime;using System.Workflow.Runtime.Hosting;using System.Workflow.Activities;namespace WorkflowConsoleApplication2
{ class Program { static void Main(string[] args) { using (WorkflowRuntime workflowRuntime = new WorkflowRuntime()) { AutoResetEvent waitHandle = new AutoResetEvent(false); workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { SalesOrderArgs soArgs = (SalesOrderArgs)e.OutputParameters["SalesOrderArgs"]; Console.WriteLine(soArgs.SalesOrder.SalesOrderID + soArgs.SalesOrder.CustomerName + soArgs.SalesOrder.ProductName + " status" + soArgs.SalesOrder.Status); waitHandle.Set(); }; workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e) { Console.WriteLine(e.Exception.Message); waitHandle.Set(); };//创建数据交换服务
ExternalDataExchangeService dataService = new ExternalDataExchangeService();//将数据交换服务加入运行时
workflowRuntime.AddService(dataService);//创建local数据接口服务
SalesOrderService localService = new SalesOrderService();//将local数据接口服务加入数据交换服务
dataService.AddService(localService);WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowConsoleApplication2.Workflow1));
instance.Start();
SalesOrder so = new SalesOrder() { SalesOrderID = 100, CustomerName = "上海汽车股份有限公司", ProductName = "ACM", UnitPrice = 1200, Amount = 10, TotalMoney = 12000, Status = -1 };
localService.FireSubmitEvent(instance.InstanceId, so);
waitHandle.WaitOne();
} } }}
1.3 调试运行
上边的代码看似无懈可击,但一运行,就遇到异常.
点击下面的View Detail链接:
可见真正的问题是:EventArgs not serializable.
可是回头看SalesOrderArgs,该类已经设置了[Serializable]属性,怎么还会错呢?莫非是SalesOrder类?它倒没有设置Serializable,给它也设置一下。
using System;
using System.Collections.Generic;using System.Linq;using System.Text;namespace WorkflowConsoleApplication2
{ [Serializable] public class SalesOrder { public int SalesOrderID { set; get; } public string CustomerName { set; get; } public string ProductName { set; get; } public int Amount { set; get; } public decimal UnitPrice { set; get; } public decimal TotalMoney { set; get; } public int Status { set; get; } }}
再运行,ok,成功了!
也就是说,只要是参数类中用到参数,都必须能序列化才可以,而不能以为给参数类加了序列化标记就算万事大吉了。
2.消息队列问题。
如果在Main函数中跳过submit状态,直接激发approval事件,代码如下:
using System;
using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Workflow.Runtime;using System.Workflow.Runtime.Hosting;using System.Workflow.Activities;namespace WorkflowConsoleApplication2
{ class Program { static void Main(string[] args) { using (WorkflowRuntime workflowRuntime = new WorkflowRuntime()) { AutoResetEvent waitHandle = new AutoResetEvent(false); workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { SalesOrderArgs soArgs = (SalesOrderArgs)e.OutputParameters["SalesOrderArgs"]; Console.WriteLine(soArgs.SalesOrder.SalesOrderID + soArgs.SalesOrder.CustomerName + soArgs.SalesOrder.ProductName + " status" + soArgs.SalesOrder.Status); waitHandle.Set(); }; workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e) { Console.WriteLine(e.Exception.Message); waitHandle.Set(); };//创建数据交换服务
ExternalDataExchangeService dataService = new ExternalDataExchangeService();//将数据交换服务加入运行时
workflowRuntime.AddService(dataService);//创建local数据接口服务
SalesOrderService localService = new SalesOrderService();//将local数据接口服务加入数据交换服务
dataService.AddService(localService);WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowConsoleApplication2.Workflow1));
instance.Start();
SalesOrder so = new SalesOrder() { SalesOrderID = 100, CustomerName = "上海汽车股份有限公司", ProductName = "ACM", UnitPrice = 1200, Amount = 10, TotalMoney = 12000, Status = -1 };
//localService.FireSubmitEvent(instance.InstanceId, so);
localService.FireApprovalEvent(instance.InstanceId, so);waitHandle.WaitOne();
} } }}
一运行,得到异常图如下:
可见,真正的错误如下:
"Queue 'Message Properties
Interface Type:WorkflowConsoleApplication2.ISalesOrderService Method Name:ApprovalEvent CorrelationValues: ' is not enabled.
如何解决呢?吃完午饭再说吧!