elsa-workflows / elsa-workflows/elsa-core

Condition JSON Serialization failure with the SwitchCase activity

Open
#6,567 0 comments 0 reactions 0 assignees View on GitHub
triaged
Dominant language
C#
Stars
7.9k
Forks
1.5k
Avg merge
15h 22m
Merged PRs (30d)
114

Description

## Description
When using the `SwitchCase` activity and specifying a delegate expression condition, with Elsa 3.3.5 I receive the following error message:
```
System.NotSupportedException: Serialization and deserialization of 'System.Func`2[[Elsa.Expressions.Models.ExpressionExecutionContext, Elsa.Expressions, Version=3.3.5.0, Culture=neutral, PublicKeyToken=null],[System.Threading.Tasks.ValueTask`1[[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]]' instances is not supported. The unsupported member type is located on type 'System.Func`2[Elsa.Expressions.Models.ExpressionExecutionContext,System.Threading.Tasks.ValueTask`1[System.Object]]'. Path: $.
```

This issue did not occur with Elsa 3.2.0, having the same exact code.

In my case, I have a workflow with the `Switch` activity, and a `SwitchCase` with a delegate expression condition, that gets the content of a variable and makes a comparison:

```
new SwitchCase(
nameof(ContentElement),
condition => changePublicationStatusData.Get(condition).EntityType == nameof(ContentElement),
new DispatchWorkflow()
)
```

The condition is executed, and a child workflow is being called (and properly executed). After the child workflow is finished, the parent workflow tries to store its own workflow data in the data storage by serializing it. While serializing, the switch condition cannot be serialized due to the above error.

This might be related to https://github.com/elsa-workflows/elsa-core/issues/5474

Subsequently, after the workflow data cannot be serialized, the whole workflow instance is not persisted to the data storage. The child workflow then tries to access its non existing parent and an additional error is thrown (workflow with id ... is not found).

This is reproducible 100% of the time, and even changing the delegate expression to simple `condition => true` does not resolve the issue.

I was able to implement a workaround, by substituting the default IWorkflowStateSerializer `services.Replace(ServiceLifetime.Singleton);` with my custom implementation. The `CustomJsonWorkflowStateSerializer` overrides `AddConverters` :

```
protected override void AddConverters(JsonSerializerOptions options)
{
options.Converters.Add(new TypeJsonConverter(_wellKnownTypeRegistry));
options.Converters.Add(new CustomPolymorphicObjectConverterFactory(_wellKnownTypeRegistry));
options.Converters.Add(new VariableConverterFactory(_wellKnownTypeRegistry, _loggerFactory));
}
```

The `CustomPolymorphicObjectConverterFactory` overrides the `CreateConverter` method:

```
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
if (typeof(IDictionary).IsAssignableFrom(typeToConvert))
return new PolymorphicDictionaryConverter(options, _wellKnownTypeRegistry);

return new CustomPolymorphicObjectConverter(_wellKnownTypeRegistry);
}
```

and the `CustomPolymorphicObjectConverter` overrides the `Write` method, and replaces the line
`var jsonElement = JsonDocument.Parse(JsonSerializer.Serialize(value, type, newOptions)).RootElement;`
with
```
var jsonElement = value is Func>
? JsonSerializer.SerializeToElement(new {})
: JsonDocument.Parse(JsonSerializer.Serialize(value, type, newOptions)).RootElement;
```

This is probably not the correct way, and I do not know if it causes more errors down the road. So far it works for me.

Please note in the below stack trace, that after debugging, I have found out, that the ExpressionJsonConverter mentioned here https://github.com/elsa-workflows/elsa-core/issues/5474 seems to work as expected (delegate expression is marked as `IsSerializable=false`, `PolymorphicObjectConverter` is nonetheless called, where the error then happens.

Full Stack Trace:

```
System.NotSupportedException: Serialization and deserialization of 'System.Func`2[[Elsa.Expressions.Models.ExpressionExecutionContext, Elsa.Expressions, Version=3.3.5.0, Culture=neutral, PublicKeyToken=null],[System.Threading.Tasks.ValueTask`1[[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]]' instances is not supported. The unsupported member type is located on type 'System.Func`2[Elsa.Expressions.Models.ExpressionExecutionContext,System.Threading.Tasks.ValueTask`1[System.Object]]'. Path: $.
---> System.NotSupportedException: Serialization and deserialization of 'System.Func`2[[Elsa.Expressions.Models.ExpressionExecutionContext, Elsa.Expressions, Version=3.3.5.0, Culture=neutral, PublicKeyToken=null],[System.Threading.Tasks.ValueTask`1[[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]]' instances is not supported.
at System.Text.Json.Serialization.Converters.UnsupportedTypeConverter`1.Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ThrowNotSupportedException(WriteStack& state, Exception innerException)
at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.Serialize(Utf8JsonWriter writer, T& rootValue, Object rootValueBoxed)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.SerializeAsObject(Utf8JsonWriter writer, Object rootValue)
at System.Text.Json.JsonSerializer.WriteStringAsObject(Object value, JsonTypeInfo jsonTypeInfo)
at System.Text.Json.JsonSerializer.Serialize(Object value, Type inputType, JsonSerializerOptions options)
at Elsa.Workflows.Serialization.Converters.PolymorphicObjectConverter.Write(Utf8JsonWriter writer, Object value, JsonSerializerOptions options)
at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.Converters.ListOfTConverter`2.OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryWrite(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.Serialize(Utf8JsonWriter writer, T& rootValue, Object rootValueBoxed)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.SerializeAsObject(Utf8JsonWriter writer, Object rootValue)
at System.Text.Json.JsonSerializer.WriteStringAsObject(Object value, JsonTypeInfo jsonTypeInfo)
at System.Text.Json.JsonSerializer.Serialize(Object value, Type inputType, JsonSerializerOptions options)
at Elsa.Workflows.Serialization.Converters.PolymorphicObjectConverter.Write(Utf8JsonWriter writer, Object value, JsonSerializerOptions options)
at Elsa.Workflows.Serialization.Converters.PolymorphicDictionaryConverter.Write(Utf8JsonWriter writer, IDictionary`2 value, JsonSerializerOptions options)
at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.Converters.IEnumerableDefaultConverter`2.OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryWrite(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.Serialize(Utf8JsonWriter writer, T& rootValue, Object rootValueBoxed)
at System.Text.Json.JsonSerializer.WriteString[TValue](TValue& value, JsonTypeInfo`1 jsonTypeInfo)
at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options)
at Elsa.Workflows.Serialization.Serializers.JsonWorkflowStateSerializer.Serialize(WorkflowState workflowState)
at Elsa.EntityFrameworkCore.Modules.Management.EFCoreWorkflowInstanceStore.OnSaveAsync(ManagementElsaDbContext managementElsaDbContext, WorkflowInstance entity, CancellationToken cancellationToken)
at Elsa.EntityFrameworkCore.Store`2.SaveAsync(TEntity entity, Expression`1 keySelector, Func`4 onSaving, CancellationToken cancellationToken)
at Elsa.EntityFrameworkCore.Store`2.SaveAsync(TEntity entity, Expression`1 keySelector, Func`4 onSaving, CancellationToken cancellationToken)
at Elsa.EntityFrameworkCore.Store`2.SaveAsync(TEntity entity, Expression`1 keySelector, Func`4 onSaving, CancellationToken cancellationToken)
at Elsa.EntityFrameworkCore.EntityStore`2.SaveAsync(TEntity entity, Func`4 onSaving, CancellationToken cancellationToken)
at Elsa.EntityFrameworkCore.Modules.Management.EFCoreWorkflowInstanceStore.SaveAsync(WorkflowInstance instance, CancellationToken cancellationToken)
at Elsa.Workflows.Management.Services.WorkflowInstanceManager.SaveAsync(WorkflowInstance workflowInstance, CancellationToken cancellationToken)
at Elsa.Workflows.Management.Services.WorkflowInstanceManager.SaveAsync(WorkflowState workflowState, CancellationToken cancellationToken)
at Elsa.Workflows.Runtime.StoreCommitStateHandler.CommitAsync(WorkflowExecutionContext workflowExecutionContext, WorkflowState workflowState, CancellationToken cancellationToken)
at Elsa.Workflows.WorkflowRunner.RunAsync(WorkflowExecutionContext workflowExecutionContext)
at Elsa.Workflows.WorkflowRunner.RunAsync(WorkflowGraph workflowGraph, WorkflowState workflowState, RunWorkflowOptions options, CancellationToken cancellationToken)
at Elsa.Workflows.Runtime.LocalWorkflowClient.RunInstanceAsync(WorkflowInstance workflowInstance, RunWorkflowInstanceRequest request, CancellationToken cancellationToken)
at Elsa.Workflows.Runtime.LocalWorkflowClient.CreateAndRunInstanceAsync(CreateAndRunWorkflowInstanceRequest request, CancellationToken cancellationToken)
at Elsa.Workflows.Runtime.Distributed.DistributedWorkflowClient.CreateAndRunInstanceAsync(CreateAndRunWorkflowInstanceRequest request, CancellationToken cancellationToken)
at Elsa.Workflows.Runtime.DefaultWorkflowStarter.StartWorkflowAsync(StartWorkflowRequest request, CancellationToken cancellationToken)
at Elsa.Workflows.Runtime.TriggerInvoker.InvokeAsync(InvokeTriggerRequest request, CancellationToken cancellationToken)
at Elsa.Workflows.Runtime.StimulusSender.TriggerNewWorkflowsAsync(String stimulusHash, StimulusMetadata metadata, CancellationToken cancellationToken)
at Elsa.Workflows.Runtime.StimulusSender.SendAsync(String stimulusHash, StimulusMetadata metadata, CancellationToken cancellationToken)
at Elsa.MassTransit.Consumers.WorkflowMessageConsumer`1.Consume(ConsumeContext`1 context)
at MassTransit.DependencyInjection.ScopeConsumerFactory`1.Send[TMessage](ConsumeContext`1 context, IPipe`1 next) in /_/src/MassTransit/DependencyInjection/DependencyInjection/ScopeConsumerFactory.cs:line 22
at MassTransit.DependencyInjection.ScopeConsumerFactory`1.Send[TMessage](ConsumeContext`1 context, IPipe`1 next) in /_/src/MassTransit/DependencyInjection/DependencyInjection/ScopeConsumerFactory.cs:line 22
at MassTransit.Middleware.ConsumerMessageFilter`2.MassTransit.IFilter>.Send(ConsumeContext`1 context, IPipe`1 next) in /_/src/MassTransit/Middleware/ConsumerMessageFilter.cs:line 48
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.