Skip to content

Commit d217c0d

Browse files
authored
Merge pull request danielgerlag#1391 from danielgerlag/copilot/fix-1372
Add configurable ObjectSerializer for MongoDB persistence to allow user type deserialization
2 parents 447bd79 + a945b97 commit d217c0d

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

src/providers/WorkflowCore.Persistence.MongoDB/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,43 @@ Use the .UseMongoDB extension method when building your service provider.
1818
services.AddWorkflow(x => x.UseMongoDB(@"mongodb://localhost:27017", "workflow"));
1919
```
2020

21+
### Configuring the ObjectSerializer
22+
23+
When using MongoDB persistence with user-defined data classes, you need to configure which types are allowed to be deserialized. This is done via the `serializerTypeFilter` parameter:
24+
25+
```C#
26+
services.AddWorkflow(x => x.UseMongoDB(
27+
@"mongodb://localhost:27017",
28+
"workflow",
29+
serializerTypeFilter: type =>
30+
MongoDB.Bson.Serialization.Serializers.ObjectSerializer.DefaultAllowedTypes(type) ||
31+
type.FullName?.StartsWith("MyApp.") == true));
32+
```
33+
34+
This configuration allows:
35+
- All default MongoDB allowed types (primitives, collections, etc.)
36+
- Types in your application namespace (e.g., `MyApp.*`)
37+
38+
**Important:** You must configure the serializer to allow your workflow data types, otherwise you will encounter a `BsonSerializationException` when MongoDB tries to deserialize your data.
39+
40+
Example for multiple namespaces:
41+
42+
```C#
43+
services.AddWorkflow(x => x.UseMongoDB(
44+
@"mongodb://localhost:27017",
45+
"workflow",
46+
serializerTypeFilter: type =>
47+
{
48+
if (MongoDB.Bson.Serialization.Serializers.ObjectSerializer.DefaultAllowedTypes(type))
49+
return true;
50+
51+
var fullName = type.FullName ?? "";
52+
return fullName.StartsWith("MyApp.") ||
53+
fullName.StartsWith("MyCompany.Models.") ||
54+
fullName.StartsWith("WorkflowCore.");
55+
}));
56+
```
57+
2158
### State object serialization
2259

2360
By default (to maintain backwards compatibility), the state object is serialized using a two step serialization process using object -> JSON -> BSON serialization.

src/providers/WorkflowCore.Persistence.MongoDB/ServiceCollectionExtensions.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@ public static WorkflowOptions UseMongoDB(
1212
this WorkflowOptions options,
1313
string mongoUrl,
1414
string databaseName,
15-
Action<MongoClientSettings> configureClient = default)
15+
Action<MongoClientSettings> configureClient = default,
16+
Func<Type, bool> serializerTypeFilter = null)
1617
{
18+
RegisterObjectSerializer(serializerTypeFilter);
19+
1720
options.UsePersistence(sp =>
1821
{
1922
var mongoClientSettings = MongoClientSettings.FromConnectionString(mongoUrl);
@@ -35,11 +38,14 @@ public static WorkflowOptions UseMongoDB(
3538

3639
public static WorkflowOptions UseMongoDB(
3740
this WorkflowOptions options,
38-
Func<IServiceProvider, IMongoDatabase> createDatabase)
41+
Func<IServiceProvider, IMongoDatabase> createDatabase,
42+
Func<Type, bool> serializerTypeFilter = null)
3943
{
4044
if (options == null) throw new ArgumentNullException(nameof(options));
4145
if (createDatabase == null) throw new ArgumentNullException(nameof(createDatabase));
4246

47+
RegisterObjectSerializer(serializerTypeFilter);
48+
4349
options.UsePersistence(sp =>
4450
{
4551
var db = createDatabase(sp);
@@ -53,5 +59,14 @@ public static WorkflowOptions UseMongoDB(
5359

5460
return options;
5561
}
62+
63+
private static void RegisterObjectSerializer(Func<Type, bool> serializerTypeFilter)
64+
{
65+
if (serializerTypeFilter != null)
66+
{
67+
MongoDB.Bson.Serialization.BsonSerializer.TryRegisterSerializer(
68+
new MongoDB.Bson.Serialization.Serializers.ObjectSerializer(serializerTypeFilter));
69+
}
70+
}
5671
}
5772
}

0 commit comments

Comments
 (0)