Skip to content

Commit a945b97

Browse files
Copilotdanielgerlag
andcommitted
Make ObjectSerializer configuration user-controllable via serializerTypeFilter parameter
Co-authored-by: danielgerlag <2357007+danielgerlag@users.noreply.github.com>
1 parent 724de9f commit a945b97

File tree

3 files changed

+54
-27
lines changed

3 files changed

+54
-27
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
}

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

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,31 +27,6 @@ public MongoPersistenceProvider(IMongoDatabase database)
2727

2828
static MongoPersistenceProvider()
2929
{
30-
// Register ObjectSerializer to allow deserialization of user types while maintaining security
31-
// Allows all default types plus user-defined types (excluding system/framework types)
32-
BsonSerializer.TryRegisterSerializer(new ObjectSerializer(type =>
33-
{
34-
// Allow all default MongoDB allowed types (primitives, collections, etc.)
35-
if (ObjectSerializer.DefaultAllowedTypes(type))
36-
return true;
37-
38-
// Allow WorkflowCore types (for backward compatibility)
39-
if (type.FullName?.StartsWith("WorkflowCore") == true)
40-
return true;
41-
42-
// Allow user types by excluding system/framework types
43-
// This prevents security issues while allowing user data classes
44-
var fullName = type.FullName ?? "";
45-
if (fullName.StartsWith("System.") ||
46-
fullName.StartsWith("Microsoft.") ||
47-
fullName.StartsWith("System,") ||
48-
fullName.StartsWith("Microsoft,"))
49-
return false;
50-
51-
// Allow all other types (user-defined types)
52-
return true;
53-
}));
54-
5530
ConventionRegistry.Register(
5631
"workflow.conventions",
5732
new ConventionPack

0 commit comments

Comments
 (0)