You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复Elsa3工作流中SwitchCase表达式序列化错误?

修复Elsa 3中Switch活动条件的序列化错误

问题场景

使用Elsa 3.1.3版本定义包含条件判断的Switch活动时,触发以下序列化错误:

System.NotSupportedException: 不支持'System.Func2[[Elsa.Expressions.Models.ExpressionExecutionContext, Elsa.Expressions, Version=3.1.3.0, Culture=neutral, PublicKeyToken=null],[System.Threading.Tasks.ValueTask1[[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]'实例的序列化和反序列化。

引发错误的工作流构建代码:

protected override void Build(IWorkflowBuilder builder)
{
    var transactionCommandVariable = new Variable<IFlowCommand<TransactionPayload>>();

    builder.Root = new Sequence
    {
        Activities =
        {
            new ReceiveCommandActivity(loggerFactory.CreateLogger<ReceiveCommandActivity>())
            {
                Name = "ReceiveCommand",
                CanStartWorkflow = true,
                Result = new(transactionCommandVariable) // 将变量设置为活动的输出。
            },
            new Switch()
            {
                Cases =
                {
                    new SwitchCase()
                    {
                        Label = "create transaction",
                        Condition = Expression.DelegateExpression(ctx => transactionCommandVariable.Get(ctx) is FlowCommand<CreateTransactionPayload>),
                        Activity = new Sequence
                        {
                            Activities =
                            {
                                new ValidateCreateTransactionCommandActivity(
                                    assetRepository,
                                    walletRepository,
                                    txValidator,
                                    loggerFactory.CreateLogger<ValidateCreateTransactionCommandActivity>())
                                {
                                    Command = new(transactionCommandVariable),
                                },
                                new CreateTransactionActivity(
                                    txnRepository,
                                    mapper,
                                    eventPublisher,
                                    config,
                                    loggerFactory.CreateLogger<CreateTransactionActivity>())
                                {
                                    Command = new(transactionCommandVariable),
                                }
                            }
                        }
                    },

错误抛出位置的序列化代码:

public class JsonIgnoreCompositeRootConverter : JsonConverter<IActivity>
{
    public override IActivity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
    public override void Write(Utf8JsonWriter writer, IActivity? value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        PropertyInfo[] obj = value?.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public) ?? Array.Empty<PropertyInfo>();
        JsonSerializerOptions options2 = new JsonSerializerOptions(options);
        PropertyInfo[] array = obj;
        foreach (PropertyInfo propertyInfo in array)
        {
            if (propertyInfo.GetCustomAttribute<JsonIgnoreAttribute>() == null && propertyInfo.GetCustomAttribute<JsonIgnoreCompositeRootAttribute>() == null)
            {
                string propertyName = options.PropertyNamingPolicy?.ConvertName(propertyInfo.Name) ?? propertyInfo.Name;
                writer.WritePropertyName(propertyName);
                object value2 = propertyInfo.GetValue(value);
                if (value2 == null)
                {
                    writer.WriteNullValue();
                }
                else
                {
// ERROR
                    JsonSerializer.Serialize(writer, value2, options2);
                }
            }
        }
        writer.WriteEndObject();
    }
}

核心原因

DelegateExpression包含匿名委托实例,无法被JSON序列化,而Elsa工作流定义需要持久化存储,因此所有活动属性必须是可序列化类型。

解决方案

方案1:使用CSharpExpression替代DelegateExpression

将条件改为可序列化的CSharp表达式,直接引用工作流变量并检查类型:

protected override void Build(IWorkflowBuilder builder)
{
    // 显式指定变量名称,确保表达式中可以正确引用
    var transactionCommandVariable = new Variable<IFlowCommand<TransactionPayload>> 
    { 
        Name = "TransactionCommand" 
    };

    builder.Root = new Sequence
    {
        Activities =
        {
            // ... ReceiveCommandActivity 代码保持不变
            new Switch()
            {
                Cases =
                {
                    new SwitchCase()
                    {
                        Label = "create transaction",
                        // 使用CSharpExpression编写类型检查逻辑
                        Condition = Expression.CSharpExpression(
                            "TransactionCommand is FlowCommand<CreateTransactionPayload>"
                        ),
                        Activity = new Sequence
                        {
                            // ... 原有活动代码保持不变
                        }
                    },
                }
            }
        }
    };
}

方案2:自定义可序列化表达式(进阶)

如果需要更复杂的判断逻辑,可以实现IExpression接口并确保类型支持JSON序列化,但对于简单的类型检查,方案1已足够满足需求。

额外注意事项

  • 确保CSharpExpression中引用的变量名称与工作流变量的Name属性一致
  • 如果类型不在Elsa默认引用的命名空间中,需要在表达式中使用完整的类型命名空间(例如MyNamespace.FlowCommand<MyNamespace.CreateTransactionPayload>)

内容的提问来源于stack exchange,提问作者RomyZero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 03:27:28