danielgerlag / danielgerlag/workflow-core

Deserialisation in the ToWorkflowInstance() duplicates List items due to not set ObjectCreationHandling = ObjectCreationHandling.Replace in the JsonSerializerSettings

Open
#1,270 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C#
Stars
5.9k
Forks
1.3k
Avg merge
1d 1h
Merged PRs (30d)
5

Description

Hello. I was trying out the Workflow Core library recently and found a bug in the deserialisation in the [ToWorkflowInstance()](https://github.com/danielgerlag/workflow-core/blob/a761d783fe6f6bf9b0c6797321a439bf6f94c827/src/providers/WorkflowCore.Persistence.EntityFramework/ExtensionMethods.cs#L136) method when using SqlServer as the persistence (which uses the EntityFrameworkPersistenceProvider under the hood).

Basically,

`result.Data = JsonConvert.DeserializeObject(instance.Data, SerializerSettings);`

is duplicating List items due a `JsonSerializerSetting`, `ObjectCreationHandling = ObjectCreationHandling.Replace` not set. This in turn, causes all workflow steps to duplicate the items in lists.

More about the `ObjectCreationHandling` setting [here](https://www.newtonsoft.com/json/help/html/DeserializeObjectCreationHandling.htm) and it's the same problem as described [here](https://stackoverflow.com/questions/13394401/json-net-deserializing-list-gives-duplicate-items).

To reproduce:

1. [you need to configure your own SQL persistance](https://github.com/danielgerlag/workflow-core/tree/master/src/providers/WorkflowCore.Persistence.SqlServer)
2. then go into [ToWorkflowInstance()](https://github.com/danielgerlag/workflow-core/blob/a761d783fe6f6bf9b0c6797321a439bf6f94c827/src/providers/WorkflowCore.Persistence.EntityFramework/ExtensionMethods.cs#L136) and before deserialising assign `instance.Data` some sample json which contains a list with items, you can use mine, ex.

```
instance.Data = "{\"$type\":\"AtlasWorkflowEngine.Services.Workflows.TestWorkflow.TestData, AtlasWorkflowEngine.Services\",\"ApprovalStages\":{\"$type\":\"System.Collections.Generic.List`1[[AtlasWorkflowEngine.Services.Workflows.TestWorkflow.TestStage, AtlasWorkflowEngine.Services]], System.Private.CoreLib\",\"$values\":[{\"$type\":\"AtlasWorkflowEngine.Services.Workflows.TestWorkflow.TestStage, AtlasWorkflowEngine.Services\",\"StageOrder\":1,\"StageName\":\"Stage 1.1\",\"ApprovedBy\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[\"test1@test.com\"]},\"RejectedBy\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[]},\"ResponseTimes\":{\"$type\":\"System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib],[System.DateTime, System.Private.CoreLib]], System.Private.CoreLib\"},\"RequiredApprovers\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[\"test1@test.com\",\"test2@test.com\"]},\"ApprovalEventId\":\"4c3d8dbb-f0f1-4b9f-b4a8-39d70f213c69\",\"RequireAllApprovers\":true,\"StageIsApproved\":false,\"StageIsRejected\":false},{\"$type\":\"AtlasWorkflowEngine.Services.Workflows.TestWorkflow.TestStage, AtlasWorkflowEngine.Services\",\"StageOrder\":1,\"StageName\":\"Stage 1.2\",\"ApprovedBy\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[]},\"RejectedBy\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[]},\"ResponseTimes\":{\"$type\":\"System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib],[System.DateTime, System.Private.CoreLib]], System.Private.CoreLib\"},\"RequiredApprovers\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[\"test1@test.com\",\"test2@test.com\",\"test3@test.com\"]},\"ApprovalEventId\":\"acb565b7-26cc-47d8-ad54-c0dbcbbe64e8\",\"RequireAllApprovers\":false,\"StageIsApproved\":false,\"StageIsRejected\":false},{\"$type\":\"AtlasWorkflowEngine.Services.Workflows.TestWorkflow.TestStage, AtlasWorkflowEngine.Services\",\"StageOrder\":2,\"StageName\":\"Stage 2\",\"ApprovedBy\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[]},\"RejectedBy\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[]},\"ResponseTimes\":{\"$type\":\"System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib],[System.DateTime, System.Private.CoreLib]], System.Private.CoreLib\"},\"RequiredApprovers\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[\"test1@test.com\"]},\"ApprovalEventId\":\"4e28761f-2544-4f64-9f88-38278c2828ed\",\"RequireAllApprovers\":true,\"StageIsApproved\":false,\"StageIsRejected\":false}]},\"CurrentStage\":{\"$type\":\"AtlasWorkflowEngine.Services.Workflows.TestWorkflow.TestStage, AtlasWorkflowEngine.Services\",\"StageOrder\":1,\"StageName\":\"Stage 1.1\",\"ApprovedBy\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[\"test1@test.com\"]},\"RejectedBy\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[]},\"ResponseTimes\":{\"$type\":\"System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib],[System.DateTime, System.Private.CoreLib]], System.Private.CoreLib\"},\"RequiredApprovers\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[\"test1@test.com\",\"test2@test.com\"]},\"ApprovalEventId\":\"4c3d8dbb-f0f1-4b9f-b4a8-39d70f213c69\",\"RequireAllApprovers\":true,\"StageIsApproved\":false,\"StageIsRejected\":false},\"CurrentStages\":{\"$type\":\"System.Collections.Generic.List`1[[AtlasWorkflowEngine.Services.Workflows.TestWorkflow.TestStage, AtlasWorkflowEngine.Services]], System.Private.CoreLib\",\"$values\":[{\"$type\":\"AtlasWorkflowEngine.Services.Workflows.TestWorkflow.TestStage, AtlasWorkflowEngine.Services\",\"StageOrder\":1,\"StageName\":\"Stage 1.1\",\"ApprovedBy\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[\"test1@test.com\"]},\"RejectedBy\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[]},\"ResponseTimes\":{\"$type\":\"System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib],[System.DateTime, System.Private.CoreLib]], System.Private.CoreLib\"},\"RequiredApprovers\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[\"test1@test.com\",\"test2@test.com\"]},\"ApprovalEventId\":\"4c3d8dbb-f0f1-4b9f-b4a8-39d70f213c69\",\"RequireAllApprovers\":true,\"StageIsApproved\":false,\"StageIsRejected\":false},{\"$type\":\"AtlasWorkflowEngine.Services.Workflows.TestWorkflow.TestStage, AtlasWorkflowEngine.Services\",\"StageOrder\":1,\"StageName\":\"Stage 1.2\",\"ApprovedBy\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[]},\"RejectedBy\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[]},\"ResponseTimes\":{\"$type\":\"System.Collections.Generic.Dictionary`2[[System.String, System.Private.CoreLib],[System.DateTime, System.Private.CoreLib]], System.Private.CoreLib\"},\"RequiredApprovers\":{\"$type\":\"System.Collections.Generic.List`1[[System.String, System.Private.CoreLib]], System.Private.CoreLib\",\"$values\":[\"test1@test.com\",\"test2@test.com\",\"test3@test.com\"]},\"ApprovalEventId\":\"acb565b7-26cc-47d8-ad54-c0dbcbbe64e8\",\"RequireAllApprovers\":false,\"StageIsApproved\":false,\"StageIsRejected\":false}]}}";
```

3. Step over and you will see the duplicated items in lists. If you use the json I provided above, the expected count for the ApprovedBy is 1 and RequiredApprovers 2, however the counts are getting doubled each time the `ToWorkflowInstance()` is being called.

![image](https://github.com/danielgerlag/workflow-core/assets/6545828/d7a1ae4e-8337-428c-b48c-8e00c310c1fb)

I believe the fix is to simply set the `ObjectCreationHandling = ObjectCreationHandling.Replace` like this:

```csharp
private static JsonSerializerSettings SerializerSettings = new JsonSerializerSettings {
TypeNameHandling = TypeNameHandling.All,
ObjectCreationHandling = ObjectCreationHandling.Replace
};
```

but as I have a very limited knowledge and understanding of this library I kindly ask for your assistance in evaluating the impacts and/or possible side effects this might have on the rest of the library.

I'm happy to create a pull request for this "bugfix" and cross reference with this thread this afternoon.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.