-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CSHARP-4495: Add conventions and attributes to configure ObjectSerial… #1545
base: main
Are you sure you want to change the base?
Conversation
This is an incredibly quick and dirty proof of concept for a new convention that allows users to define the allowed types for serialization/deserialization in multiple ways:
I have also thought if it would make sense to give users the possibility of setting the allowed types with attributes, but I suppose that most of the times that list of types would be valid for the whole project, not only for certain POCOs. As said, this just a very fast POC, so there's a lot missing, but it's to get some initial feedback. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything looks very reasonable!
/// <param name="allowedSerializationTypes"></param> | ||
public AllowedTypesConvention(IEnumerable<Type> allowedDeserializationTypes, IEnumerable<Type> allowedSerializationTypes) | ||
{ | ||
var allowedDeserializationTypesArray = allowedDeserializationTypes as Type[] ?? allowedDeserializationTypes.ToArray(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting optimization...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However... we should probably make a defensive copy anyway because the caller might alter the array they passed in later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we should just make a copy
src/MongoDB.Bson/Serialization/Conventions/AllowedTypesConvention.cs
Outdated
Show resolved
Hide resolved
/// | ||
/// </summary> | ||
#pragma warning disable CA1044 | ||
public bool AllowDefaultFrameworkTypes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of giving them a way to opt-in the default framework types.
src/MongoDB.Bson/Serialization/Conventions/AllowedTypesConvention.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Bson/Serialization/Conventions/AllowedTypesConvention.cs
Outdated
Show resolved
Hide resolved
@rstam This is ready for review now. Apart from all your notes, I've also allowed the convention to work with collections and nested collection (as we did with the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall
.../MongoDB.Bson.Tests/Serialization/Conventions/ObjectSerializerAllowedTypesConventionTests.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Bson/Serialization/Conventions/ObjectSerializerAllowedTypesConvention.cs
Outdated
Show resolved
Hide resolved
/// Initializes a new instance of the <see cref="ObjectSerializerAllowedTypesConvention"/> class | ||
/// that allows all types contained in the calling assembly. | ||
/// </summary> | ||
public ObjectSerializerAllowedTypesConvention() : this(Assembly.GetCallingAssembly()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should define that the default behavior does not configure any allowed types (except for DefaultFrameworkAllowedTypes
). So the configuration needs to be explicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have removed the automatic add of the types in the calling assembly and I have made AllowDefaultFrameworkTypes
default to true, similar to the behaviour of the ObjectSerializer
. For this reason now the delegates that are passed to the ObjectSerializer
are built lazily.
src/MongoDB.Bson/Serialization/Conventions/ObjectSerializerAllowedTypesConvention.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Bson/Serialization/Conventions/ObjectSerializerAllowedTypesConvention.cs
Outdated
Show resolved
Hide resolved
src/MongoDB.Bson/Serialization/Conventions/ObjectSerializerAllowedTypesConvention.cs
Outdated
Show resolved
Hide resolved
? ObjectSerializer.DefaultAllowedTypes | ||
: t => _allowedDeserializationTypes(t) || ObjectSerializer.DefaultAllowedTypes(t) | ||
: _allowedDeserializationTypes ?? ObjectSerializer.NoAllowedTypes; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hope that this is readable enough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's fine. minor optimization possible:
_lazyAllowedDeserializationTypes = new Lazy<Func<Type, bool>>(() => Construct(_allowedDeserializationTypes));
_lazyAllowedSerializationTypes= new Lazy<Func<Type, bool>>(() => Construct(_allowedSerializationTypes));
Func<Type, bool> Construct(Func<Type, bool> allowedTypes) => AllowDefaultFrameworkTypes
? (allowedTypes != null ? t => allowedTypes(t) || ObjectSerializer.DefaultAllowedTypes) : ObjectSerializer.DefaultAllowedTypes
: allowedTypes ?? ObjectSerializer.NoAllowedTypes;
src/MongoDB.Bson/Serialization/Conventions/ObjectSerializerAllowedTypesConvention.cs
Show resolved
Hide resolved
? ObjectSerializer.DefaultAllowedTypes | ||
: t => _allowedDeserializationTypes(t) || ObjectSerializer.DefaultAllowedTypes(t) | ||
: _allowedDeserializationTypes ?? ObjectSerializer.NoAllowedTypes; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's fine. minor optimization possible:
_lazyAllowedDeserializationTypes = new Lazy<Func<Type, bool>>(() => Construct(_allowedDeserializationTypes));
_lazyAllowedSerializationTypes= new Lazy<Func<Type, bool>>(() => Construct(_allowedSerializationTypes));
Func<Type, bool> Construct(Func<Type, bool> allowedTypes) => AllowDefaultFrameworkTypes
? (allowedTypes != null ? t => allowedTypes(t) || ObjectSerializer.DefaultAllowedTypes) : ObjectSerializer.DefaultAllowedTypes
: allowedTypes ?? ObjectSerializer.NoAllowedTypes;
/// <summary> | ||
/// A convention that allows to set the types that can be safely serialized and deserialized with the <see cref="ObjectSerializer"/>. | ||
/// </summary> | ||
public sealed class ObjectSerializerAllowedTypesConvention |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to have convenience presets, like:
ObjectSerializerAllowedTypesConvention.AllowAllTypes
ObjectSerializerAllowedTypesConvention.AllowAllExecutingAssemblyTypes
ObjectSerializerAllowedTypesConvention.DefaultAllowedTypes
...
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that would make sense
.../MongoDB.Bson.Tests/Serialization/Conventions/ObjectSerializerAllowedTypesConventionTests.cs
Outdated
Show resolved
Hide resolved
/// <summary> | ||
/// Default <see cref="ObjectSerializerAllowedTypesConvention"/> where all calling assembly types and default framework types are allowed for both serialization and deserialization. | ||
/// </summary> | ||
public static ObjectSerializerAllowedTypesConvention AllowAllCallingAssemblyAndDefaultFrameworkTypes => new(Assembly.GetCallingAssembly()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it makes sense to have both AllowAllCallingAssemblyAndDefaultFrameworkTypes
and AllowAllCallingAssemblyTypes
or keep only the second one (but then we need to decide if the default framework types are included or not)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need only need AllowAllCallingAssemblyAndDefaultFrameworkTypes
/// <summary> | ||
/// Default <see cref="ObjectSerializerAllowedTypesConvention"/> where all calling assembly types and default framework types are allowed for both serialization and deserialization. | ||
/// </summary> | ||
public static ObjectSerializerAllowedTypesConvention AllowAllCallingAssemblyAndDefaultFrameworkTypes => new(Assembly.GetCallingAssembly()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need only need AllowAllCallingAssemblyAndDefaultFrameworkTypes
{ | ||
_lazyAllowedDeserializationTypes = new Lazy<Func<Type, bool>>(() => Construct(_allowedDeserializationTypes)); | ||
_lazyAllowedSerializationTypes = new Lazy<Func<Type, bool>>(() => Construct(_allowedSerializationTypes)); | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for return
public static ObjectSerializerAllowedTypesConvention AllowAllTypes => new(ObjectSerializer.AllAllowedTypes); | ||
|
||
/// <summary> | ||
/// Default <see cref="ObjectSerializerAllowedTypesConvention"/> where no types are allowed for both serialization and deserialization. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe not need for the word "Default", as it might be confused for an actual default?
…izer AllowedTypes