Skip to content

Commit e68d78d

Browse files
committed
Refactored DataObjectSerializer to be able to use decimal value type and BsonRepresentation attributes
1 parent 24f05e3 commit e68d78d

File tree

4 files changed

+112
-12
lines changed

4 files changed

+112
-12
lines changed

src/providers/WorkflowCore.Persistence.MongoDB/Services/DataObjectSerializer.cs

Lines changed: 92 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22
using MongoDB.Bson.Serialization.Serializers;
33
using MongoDB.Bson;
44
using System;
5+
using System.Collections;
56
using System.Collections.Generic;
67
using System.Linq;
7-
using System.Linq.Expressions;
8-
using System.Threading.Tasks;
9-
using WorkflowCore.Models;
108
using Newtonsoft.Json;
119

1210
namespace WorkflowCore.Persistence.MongoDB.Services
@@ -17,7 +15,7 @@ public class DataObjectSerializer : SerializerBase<object>
1715
{
1816
TypeNameHandling = TypeNameHandling.Objects,
1917
};
20-
18+
2119
public override object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
2220
{
2321
if (context.Reader.CurrentBsonType == BsonType.String)
@@ -26,18 +24,103 @@ public override object Deserialize(BsonDeserializationContext context, BsonDeser
2624
return JsonConvert.DeserializeObject(raw, SerializerSettings);
2725
}
2826

29-
return BsonSerializer.Deserialize(context.Reader, typeof(object));
27+
var obj = BsonSerializer.Deserialize(context.Reader, typeof(object));
28+
return obj;
3029
}
3130

3231
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
3332
{
34-
var str = JsonConvert.SerializeObject(value, SerializerSettings);
35-
var doc = BsonDocument.Parse(str);
36-
ConvertMetaFormat(doc);
33+
BsonDocument doc;
34+
if (BsonClassMap.IsClassMapRegistered(value.GetType()))
35+
{
36+
doc = value.ToBsonDocument();
37+
doc.Remove("_t");
38+
doc.InsertAt(0, new BsonElement("_t", value.GetType().AssemblyQualifiedName));
39+
AddTypeInformation(doc.Elements, value, string.Empty);
40+
}
41+
else
42+
{
43+
var str = JsonConvert.SerializeObject(value, SerializerSettings);
44+
doc = BsonDocument.Parse(str);
45+
ConvertMetaFormat(doc);
46+
}
3747

3848
BsonSerializer.Serialize(context.Writer, doc);
3949
}
4050

51+
private void AddTypeInformation(IEnumerable<BsonElement> elements, object value, string xPath)
52+
{
53+
foreach (var element in elements)
54+
{
55+
var elementXPath = string.IsNullOrEmpty(xPath) ? element.Name : xPath + "." + element.Name;
56+
if (element.Value.IsBsonDocument)
57+
{
58+
var doc = element.Value.AsBsonDocument;
59+
doc.Remove("_t");
60+
doc.InsertAt(0, new BsonElement("_t", GetTypeNameFromXPath(value, elementXPath)));
61+
AddTypeInformation(doc.Elements, value, elementXPath);
62+
}
63+
if (element.Value.IsBsonArray)
64+
{
65+
AddTypeInformation(element.Value.AsBsonArray, value, elementXPath);
66+
}
67+
}
68+
}
69+
70+
private string GetTypeNameFromXPath(object root, string xPath)
71+
{
72+
var parts = xPath.Split('.').ToList();
73+
object value = root;
74+
while (parts.Count > 0)
75+
{
76+
var subPath = parts[0];
77+
if (subPath[0] == '[')
78+
{
79+
var index = Int32.Parse(subPath.Trim('[', ']'));
80+
if (value.GetType().IsSubclassOf(typeof(IList)) || value.GetType().IsArray)
81+
{
82+
IList list = (IList) value;
83+
value = list[index];
84+
}
85+
else
86+
{
87+
throw new NotSupportedException();
88+
}
89+
}
90+
else
91+
{
92+
var propInfo = value.GetType().GetProperty(subPath);
93+
value = propInfo.GetValue(value);
94+
}
95+
96+
parts.RemoveAt(0);
97+
}
98+
99+
return value.GetType().AssemblyQualifiedName;
100+
}
101+
102+
private void AddTypeInformation(IEnumerable<BsonValue> elements, object value, string xPath)
103+
{
104+
//foreach (var element in elements)
105+
for (int i = 0; i < elements.Count(); i++)
106+
{
107+
var element = elements.ElementAt(i);
108+
if (element.IsBsonDocument)
109+
{
110+
var doc = element.AsBsonDocument;
111+
var elementXPath = xPath + $".[{i}]";
112+
doc.Remove("_t");
113+
doc.InsertAt(0, new BsonElement("_t", GetTypeNameFromXPath(value, elementXPath)));
114+
AddTypeInformation(doc.Elements, value, elementXPath);
115+
}
116+
117+
if (element.IsBsonArray)
118+
{
119+
AddTypeInformation(element.AsBsonArray, value, xPath);
120+
}
121+
}
122+
}
123+
41124
private static void ConvertMetaFormat(BsonDocument root)
42125
{
43126
var stack = new Stack<BsonDocument>();
@@ -72,4 +155,4 @@ private static void ConvertMetaFormat(BsonDocument root)
72155
}
73156
}
74157
}
75-
}
158+
}

test/WorkflowCore.IntegrationTests/Scenarios/DataIOScenario.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ public class MyDataClass
2929
public int Value1 { get; set; }
3030
public int Value2 { get; set; }
3131
public int Value3 { get; set; }
32+
public decimal Value4 { get; set; }
33+
34+
public DataSubclass SubValue { get; set; }
35+
}
36+
37+
public class DataSubclass
38+
{
39+
public decimal Value5 { get; set; }
3240
}
3341

3442
public class DataIOWorkflow : IWorkflow<MyDataClass>
@@ -47,18 +55,20 @@ public void Build(IWorkflowBuilder<MyDataClass> builder)
4755

4856
public DataIOScenario()
4957
{
50-
Setup();
58+
Setup(true);
5159
}
5260

5361
[Fact]
5462
public void Scenario()
5563
{
56-
var workflowId = StartWorkflow(new MyDataClass() { Value1 = 2, Value2 = 3 });
64+
decimal v4 = 1.235465673450897890m;
65+
var workflowId = StartWorkflow(new MyDataClass() {Value1 = 2, Value2 = 3, Value4 = v4, SubValue = new DataSubclass() {Value5 = v4}});
5766
WaitForWorkflowToComplete(workflowId, TimeSpan.FromSeconds(30));
5867

5968
GetStatus(workflowId).Should().Be(WorkflowStatus.Complete);
6069
UnhandledStepErrors.Count.Should().Be(0);
6170
GetData(workflowId).Value3.Should().Be(5);
71+
GetData(workflowId).Value4.Should().Be(v4);
6272
}
6373
}
6474
}

test/WorkflowCore.Testing/WorkflowCore.Testing.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.0" />
1313
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.0" />
1414
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.1.0" />
15+
<PackageReference Include="MongoDB.Bson" Version="2.8.1" />
1516
</ItemGroup>
1617

1718
<ItemGroup>

test/WorkflowCore.Testing/WorkflowTest.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Threading.Tasks;
88
using Microsoft.Extensions.DependencyInjection;
99
using Microsoft.Extensions.Logging;
10+
using MongoDB.Bson.Serialization;
1011
using WorkflowCore.Interface;
1112
using WorkflowCore.Models;
1213

@@ -20,7 +21,7 @@ public abstract class WorkflowTest<TWorkflow, TData> : IDisposable
2021
protected IPersistenceProvider PersistenceProvider;
2122
protected List<StepError> UnhandledStepErrors = new List<StepError>();
2223

23-
protected virtual void Setup()
24+
protected virtual void Setup(bool registerClassMap = false)
2425
{
2526
//setup dependency injection
2627
IServiceCollection services = new ServiceCollection();
@@ -33,6 +34,11 @@ protected virtual void Setup()
3334
var loggerFactory = serviceProvider.GetService<ILoggerFactory>();
3435
//loggerFactory.AddConsole(LogLevel.Debug);
3536

37+
if (registerClassMap && !BsonClassMap.IsClassMapRegistered(typeof(TData)))
38+
{
39+
BsonClassMap.RegisterClassMap<TData>(map => map.AutoMap());
40+
}
41+
3642
PersistenceProvider = serviceProvider.GetService<IPersistenceProvider>();
3743
Host = serviceProvider.GetService<IWorkflowHost>();
3844
Host.RegisterWorkflow<TWorkflow, TData>();

0 commit comments

Comments
 (0)