From 0472c3dcf17d733eab185445f4bbfbc11663a502 Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Tue, 19 Aug 2025 17:24:53 +0200 Subject: [PATCH 01/21] Merge --- src/MongoDB.Bson/BsonDefaults.cs | 51 +- src/MongoDB.Bson/BsonDefaultsDomain.cs | 73 ++ src/MongoDB.Bson/BsonExtensionMethods.cs | 61 +- src/MongoDB.Bson/IBsonDefaults.cs | 39 + .../IO/BsonBinaryReaderSettings.cs | 2 +- .../IO/BsonBinaryWriterSettings.cs | 2 +- src/MongoDB.Bson/IO/BsonReader.cs | 9 +- src/MongoDB.Bson/IO/BsonReaderSettings.cs | 1 + src/MongoDB.Bson/IO/BsonWriter.cs | 12 +- src/MongoDB.Bson/IO/BsonWriterSettings.cs | 1 + .../IO/ElementAppendingBsonWriter.cs | 3 +- src/MongoDB.Bson/IO/IBsonReader.cs | 1 + src/MongoDB.Bson/InternalExtensions.cs | 107 +++ src/MongoDB.Bson/ObjectModel/BsonDocument.cs | 3 +- .../ObjectModel/BsonDocumentWrapper.cs | 47 +- src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs | 3 +- .../ObjectModel/LazyBsonDocument.cs | 3 +- src/MongoDB.Bson/ObjectModel/RawBsonArray.cs | 21 +- .../ObjectModel/RawBsonDocument.cs | 27 +- src/MongoDB.Bson/Properties/AssemblyInfo.cs | 5 + .../AttributedSerializationProvider.cs | 1 + .../Serialization/BsonClassMap.cs | 276 ++---- .../Serialization/BsonClassMapDomain.cs | 263 ++++++ .../BsonClassMapSerializationProvider.cs | 15 +- .../BsonDeserializationContext.cs | 42 +- .../Serialization/BsonMemberMap.cs | 10 +- .../Serialization/BsonSerializationContext.cs | 41 +- .../Serialization/BsonSerializationDomain.cs | 878 ++++++++++++++++++ .../Serialization/BsonSerializationInfo.cs | 9 +- .../BsonSerializationProviderBase.cs | 7 +- .../Serialization/BsonSerializer.cs | 581 ++---------- .../Serialization/BsonSerializerRegistry.cs | 29 +- .../Conventions/AttributeConventionPack.cs | 10 +- .../CamelCaseElementNameConvention.cs | 13 +- .../Conventions/ConventionRegistry.cs | 102 +- .../Conventions/ConventionRegistryDomain.cs | 141 +++ .../Conventions/ConventionRunner.cs | 8 +- .../DelegateMemberMapConvention.cs | 7 +- .../DelegatePostProcessingConvention.cs | 7 +- .../EnumRepresentationConvention.cs | 7 +- .../HierarchicalDiscriminatorConvention.cs | 16 +- .../Conventions/IConventionRegistryDomain.cs | 28 + .../Conventions/IDiscriminatorConvention.cs | 22 + .../Conventions/IMemberMapConvention.cs | 10 + .../Conventions/IPostProcessingConvention.cs | 10 + .../IScalarDiscriminatorConvention.cs | 5 + .../Conventions/IgnoreIfDefaultConvention.cs | 7 +- .../Conventions/IgnoreIfNullConvention.cs | 7 +- .../LookupIdGeneratorConvention.cs | 19 +- .../MemberDefaultValueConvention.cs | 7 +- .../MemberNameElementNameConvention.cs | 10 +- .../Conventions/NoIdMemberConvention.cs | 12 +- .../ObjectDiscriminatorConvention.cs | 10 +- .../ObjectSerializerAllowedTypesConvention.cs | 7 +- .../Conventions/ResetMemberMapsConvention.cs | 7 +- .../ScalarDiscriminatorConvention.cs | 23 +- .../StandardDiscriminatorConvention.cs | 13 +- .../StringIdStoredAsObjectIdConvention.cs | 9 +- .../StringObjectIdIdGeneratorConvention.cs | 8 +- .../Serialization/IBsonClassMapDomain.cs | 96 ++ .../Serialization/IBsonIdProvider.cs | 5 + .../Serialization/IBsonSerializationDomain.cs | 317 +++++++ .../IBsonSerializationProvider.cs | 10 + .../IBsonSerializerExtensions.cs | 18 +- .../Serialization/IIdGenerator.cs | 1 + .../Serializers/BsonClassMapSerializer.cs | 26 +- .../Serializers/BsonDocumentSerializer.cs | 6 +- .../Serializers/BsonValueSerializerBase.cs | 2 +- .../Serializers/ClassSerializerBase.cs | 8 +- ...ictionaryInterfaceImplementerSerializer.cs | 2 + .../Serializers/DictionarySerializerBase.cs | 17 +- .../DiscriminatedInterfaceSerializer.cs | 14 +- .../DiscriminatedWrapperSerializer.cs | 6 +- .../DynamicDocumentBaseSerializer.cs | 14 +- .../Serializers/ElementAppendingSerializer.cs | 2 +- .../Serializers/EnumerableSerializerBase.cs | 2 + .../Serializers/ExpandoObjectSerializer.cs | 8 +- ...ableDeserializingAsCollectionSerializer.cs | 1 + ...mpliedImplementationInterfaceSerializer.cs | 3 +- .../Serializers/KeyValuePairSerializer.cs | 2 + .../Serializers/NullableSerializer.cs | 1 + .../Serializers/ObjectSerializer.cs | 13 +- .../SerializeAsNominalTypeSerializer.cs | 1 + .../ThreeDimensionalArraySerializer.cs | 1 + .../Serializers/TupleSerializers.cs | 16 +- .../TwoDimensionalArraySerializer.cs | 1 + .../UndiscriminatedActualTypeSerializer.cs | 2 +- .../Serializers/ValueTupleSerializers.cs | 1 + .../SaslSteps/AWSLastSaslStep.cs | 2 +- ...plicitEncryptionLibMongoCryptController.cs | 8 +- .../AggregateExpressionDefinition.cs | 2 +- .../MongoDBX509Authenticator.cs | 5 +- .../Authentication/Oidc/AzureOidcCallback.cs | 2 +- .../Authentication/SaslAuthenticator.cs | 4 +- .../BsonSerializerExtensions.cs | 5 +- src/MongoDB.Driver/ChangeStreamHelper.cs | 28 +- src/MongoDB.Driver/ClusteredIndexOptions.cs | 10 + .../Core/Bindings/CoreSession.cs | 6 +- src/MongoDB.Driver/Core/Bindings/IChannel.cs | 32 + .../Core/Connections/ConnectionInitializer.cs | 4 +- .../Core/Connections/HelloHelper.cs | 4 +- .../Core/Operations/AggregateOperation.cs | 45 +- .../AggregateToCollectionOperation.cs | 21 +- .../Core/Operations/AsyncCursor.cs | 75 +- .../Core/Operations/ChangeStreamCursor.cs | 35 +- .../Core/Operations/ChangeStreamOperation.cs | 48 +- .../Operations/ClientBulkWriteOperation.cs | 9 +- .../Core/Operations/CommandOperationBase.cs | 26 +- .../Operations/CountDocumentsOperation.cs | 13 +- .../Core/Operations/CountOperation.cs | 13 +- .../Operations/CreateCollectionOperation.cs | 23 +- .../Core/Operations/CreateIndexesOperation.cs | 17 +- .../CreateSearchIndexesOperation.cs | 10 +- .../Core/Operations/CreateViewOperation.cs | 19 +- .../CursorBatchDeserializationHelper.cs | 5 +- .../Operations/DatabaseExistsOperation.cs | 14 +- .../Core/Operations/DistinctOperation.cs | 19 +- .../Operations/DropCollectionOperation.cs | 35 +- .../Core/Operations/DropDatabaseOperation.cs | 16 +- .../Core/Operations/DropIndexOperation.cs | 28 +- .../Operations/DropSearchIndexOperation.cs | 9 +- .../Operations/EndTransactionOperation.cs | 54 +- .../EstimatedDocumentCountOperation.cs | 13 +- .../Operations/FindAndModifyOperationBase.cs | 11 +- .../Operations/FindOneAndDeleteOperation.cs | 15 +- .../Operations/FindOneAndReplaceOperation.cs | 20 +- .../Operations/FindOneAndUpdateOperation.cs | 17 +- .../Core/Operations/FindOperation.cs | 21 +- .../Operations/ListCollectionsOperation.cs | 19 +- .../Core/Operations/ListDatabasesOperation.cs | 14 +- .../Core/Operations/ListIndexesOperation.cs | 16 +- .../ListIndexesUsingCommandOperation.cs | 21 +- .../Core/Operations/MapReduceOperation.cs | 26 +- .../MapReduceOutputToCollectionOperation.cs | 26 +- .../Core/Operations/ReadCommandOperation.cs | 14 +- .../Operations/RenameCollectionOperation.cs | 20 +- .../RetryableDeleteCommandOperation.cs | 14 +- .../RetryableInsertCommandOperation.cs | 18 +- .../RetryableUpdateCommandOperation.cs | 14 +- .../RetryableWriteCommandOperationBase.cs | 16 +- .../Operations/UpdateSearchIndexOperation.cs | 8 +- .../Core/Operations/WriteCommandOperation.cs | 17 +- .../Core/Servers/ServerChannel.cs | 69 +- .../CommandUsingCommandMessageWireProtocol.cs | 7 +- .../CommandUsingQueryMessageWireProtocol.cs | 7 +- .../Core/WireProtocol/CommandWireProtocol.cs | 96 +- .../ClientBulkWriteOpsSectionFormatter.cs | 26 +- .../CommandMessageBinaryEncoder.cs | 11 +- .../MessageBinaryEncoderBase.cs | 6 +- .../QueryMessageBinaryEncoder.cs | 8 +- .../ReplyMessageBinaryEncoder.cs | 10 +- .../BinaryEncoders/Type0SectionFormatter.cs | 9 +- .../BinaryEncoders/Type1SectionFormatter.cs | 6 +- .../ICommandMessageSectionFormatter.cs | 1 + .../JsonEncoders/CommandMessageJsonEncoder.cs | 13 +- .../CompressedMessageJsonEncoder.cs | 2 +- .../JsonEncoders/MessageJsonEncoderBase.cs | 3 + .../JsonEncoders/QueryMessageJsonEncoder.cs | 8 +- .../JsonEncoders/ReplyMessageJsonEncoder.cs | 8 +- .../JsonEncoders/Type0SectionFormatter.cs | 8 +- .../JsonEncoders/Type1SectionFormatter.cs | 9 +- .../Encoders/MessageEncoderSettings.cs | 1 + src/MongoDB.Driver/CreateCollectionOptions.cs | 11 + src/MongoDB.Driver/CreateViewOptions.cs | 9 + src/MongoDB.Driver/FieldDefinition.cs | 4 +- .../FieldValueSerializerHelper.cs | 3 +- src/MongoDB.Driver/FilterDefinition.cs | 4 +- src/MongoDB.Driver/FilterDefinitionBuilder.cs | 32 +- src/MongoDB.Driver/FindFluent.cs | 2 +- .../GeoJsonBoundingBoxSerializer.cs | 5 +- .../Serializers/GeoJsonPointSerializer.cs | 2 +- .../Serializers/GeoJsonPolygonSerializer.cs | 1 + src/MongoDB.Driver/GridFS/GridFSBucket.cs | 29 +- .../GridFS/GridFSBucketCompat.cs | 16 +- .../GridFS/GridFSBucketOptions.cs | 3 +- .../GridFS/GridFSDownloadStreamBase.cs | 18 +- .../GridFS/GridFSFileInfoSerializer.cs | 2 +- .../GridFS/GridFSForwardOnlyDownloadStream.cs | 8 +- .../GridFS/GridFSSeekableDownloadStream.cs | 17 +- .../IInheritableMongoClientSettings.cs | 3 + ...ingWithOutputExpressionStageDefinitions.cs | 23 +- .../Misc/SerializationHelper.cs | 4 +- .../Misc/TypeExtensions.cs | 18 +- .../Linq3Implementation/MongoQueryProvider.cs | 8 +- .../ISetWindowFieldsPartitionSerializer.cs | 2 - .../Translators/DiscriminatorAstExpression.cs | 13 +- .../Translators/DiscriminatorAstFilter.cs | 17 +- ...essionToAggregationExpressionTranslator.cs | 2 +- ...essionToAggregationExpressionTranslator.cs | 4 +- ...essionToAggregationExpressionTranslator.cs | 23 +- ...essionToAggregationExpressionTranslator.cs | 2 +- ...essionToAggregationExpressionTranslator.cs | 4 +- ...essionToAggregationExpressionTranslator.cs | 2 +- ...MethodToAggregationExpressionTranslator.cs | 2 +- ...MethodToAggregationExpressionTranslator.cs | 2 +- ...MethodToAggregationExpressionTranslator.cs | 2 +- ...MethodToAggregationExpressionTranslator.cs | 8 +- ...MethodToAggregationExpressionTranslator.cs | 15 +- ...ethodsToAggregationExpressionTranslator.cs | 4 +- ...MethodToAggregationExpressionTranslator.cs | 27 +- ...MethodToAggregationExpressionTranslator.cs | 4 +- ...essionToAggregationExpressionTranslator.cs | 2 +- ...essionToAggregationExpressionTranslator.cs | 6 +- .../ExpressionToExecutableQueryTranslator.cs | 4 +- ...iationMethodToExecutableQueryTranslator.cs | 2 +- .../SumMethodToExecutableQueryTranslator.cs | 2 +- ...eComparisonExpressionToFilterTranslator.cs | 6 +- .../TypeIsExpressionToFilterTranslator.cs | 6 +- .../AllOrAnyMethodToFilterTranslator.cs | 8 +- .../InjectMethodToFilterTranslator.cs | 7 +- ...onvertExpressionToFilterFieldTranslator.cs | 6 +- .../AppendStageMethodToPipelineTranslator.cs | 8 +- .../AsMethodToPipelineTranslator.cs | 2 +- .../ConcatMethodToPipelineTranslator.cs | 2 +- .../DocumentsMethodToPipelineTranslator.cs | 2 +- .../LookupMethodToPipelineTranslator.cs | 6 +- .../OfTypeMethodToPipelineTranslator.cs | 10 +- .../UnionMethodToPipelineTranslator.cs | 2 +- .../Translators/TranslationContext.cs | 12 +- .../Linq/LinqProviderAdapter.cs | 39 +- src/MongoDB.Driver/MongoClient.cs | 14 +- src/MongoDB.Driver/MongoClientSettings.cs | 19 + src/MongoDB.Driver/MongoCollectionImpl.cs | 72 +- src/MongoDB.Driver/MongoCollectionSettings.cs | 25 +- src/MongoDB.Driver/MongoDB.Driver.csproj | 11 +- src/MongoDB.Driver/MongoDatabase.cs | 52 +- src/MongoDB.Driver/MongoDatabaseSettings.cs | 24 +- src/MongoDB.Driver/OfTypeMongoCollection.cs | 4 +- src/MongoDB.Driver/OfTypeSerializer.cs | 9 +- src/MongoDB.Driver/PipelineDefinition.cs | 3 +- .../PipelineDefinitionBuilder.cs | 4 +- src/MongoDB.Driver/PipelineStageDefinition.cs | 15 +- .../PipelineStageDefinitionBuilder.cs | 38 +- src/MongoDB.Driver/ProjectionDefinition.cs | 4 +- src/MongoDB.Driver/RenderArgs.cs | 42 +- src/MongoDB.Driver/SetFieldDefinitions.cs | 2 +- .../Support/InternalExtensions.cs | 39 + .../Support/ReflectionExtensions.cs | 32 +- src/MongoDB.Driver/UpdateDefinition.cs | 1 + src/MongoDB.Driver/UpdateDefinitionBuilder.cs | 10 +- .../ObjectModel/BsonDocumentWrapperTests.cs | 4 +- .../Core/CoreTestConfiguration.cs | 13 +- .../Core/FailPoint.cs | 4 +- .../ChangeStreamHelperTests.cs | 6 +- .../Core/IAsyncCursorExtensionsTests.cs | 2 + .../Core/IAsyncCursorSourceExtensionsTests.cs | 2 + .../AggregateToCollectionOperationTests.cs | 5 +- .../Core/Operations/AsyncCursorTests.cs | 14 +- .../Operations/ChangeStreamOperationTests.cs | 14 +- .../CreateCollectionOperationTests.cs | 5 +- .../CursorBatchDeserializationHelperTests.cs | 9 +- .../Operations/ReadCommandOperationTests.cs | 24 +- .../Operations/WriteCommandOperationTests.cs | 18 +- .../IMongoCollectionExtensionsTests.cs | 1 + .../Linq3IntegrationTest.cs | 2 +- ...arisonExpressionToFilterTranslatorTests.cs | 5 +- .../AggregateGroupTranslatorTests.cs | 3 +- .../LegacyPredicateTranslatorTests.cs | 3 +- .../Translators/PredicateTranslatorTests.cs | 5 +- .../Linq/LinqProviderAdapterTests.cs | 37 +- .../MultipleRegistriesTests.cs | 357 +++++++ 261 files changed, 4803 insertions(+), 1675 deletions(-) create mode 100644 src/MongoDB.Bson/BsonDefaultsDomain.cs create mode 100644 src/MongoDB.Bson/IBsonDefaults.cs create mode 100644 src/MongoDB.Bson/InternalExtensions.cs create mode 100644 src/MongoDB.Bson/Serialization/BsonClassMapDomain.cs create mode 100644 src/MongoDB.Bson/Serialization/BsonSerializationDomain.cs create mode 100644 src/MongoDB.Bson/Serialization/Conventions/ConventionRegistryDomain.cs create mode 100644 src/MongoDB.Bson/Serialization/Conventions/IConventionRegistryDomain.cs create mode 100644 src/MongoDB.Bson/Serialization/IBsonClassMapDomain.cs create mode 100644 src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs create mode 100644 src/MongoDB.Driver/Support/InternalExtensions.cs create mode 100644 tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs diff --git a/src/MongoDB.Bson/BsonDefaults.cs b/src/MongoDB.Bson/BsonDefaults.cs index 9352d3228ff..47c01789356 100644 --- a/src/MongoDB.Bson/BsonDefaults.cs +++ b/src/MongoDB.Bson/BsonDefaults.cs @@ -24,33 +24,14 @@ namespace MongoDB.Bson /// public static class BsonDefaults { - // private static fields - private static bool __dynamicArraySerializerWasSet; - private static IBsonSerializer __dynamicArraySerializer; - private static bool __dynamicDocumentSerializerWasSet; - private static IBsonSerializer __dynamicDocumentSerializer; - private static int __maxDocumentSize = int.MaxValue; - private static int __maxSerializationDepth = 100; - // public static properties /// /// Gets or sets the dynamic array serializer. /// public static IBsonSerializer DynamicArraySerializer { - get - { - if (!__dynamicArraySerializerWasSet) - { - __dynamicArraySerializer = BsonSerializer.LookupSerializer>(); - } - return __dynamicArraySerializer; - } - set - { - __dynamicArraySerializerWasSet = true; - __dynamicArraySerializer = value; - } + get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicArraySerializer; + set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicArraySerializer = value; } /// @@ -58,28 +39,22 @@ public static IBsonSerializer DynamicArraySerializer /// public static IBsonSerializer DynamicDocumentSerializer { - get - { - if (!__dynamicDocumentSerializerWasSet) - { - __dynamicDocumentSerializer = BsonSerializer.LookupSerializer(); - } - return __dynamicDocumentSerializer; - } - set - { - __dynamicDocumentSerializerWasSet = true; - __dynamicDocumentSerializer = value; - } + get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicDocumentSerializer; + set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicDocumentSerializer = value; } + /* DOMAIN-API We should modify the API to have those two values (and in the writer/reader settings where they are used) be nullable. + * The problem is that we need to now when these values have been set externally or not. If they have not, then they should + * be retrieved from the closest domain. + */ + /// /// Gets or sets the default max document size. The default is 4MiB. /// public static int MaxDocumentSize { - get { return __maxDocumentSize; } - set { __maxDocumentSize = value; } + get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxDocumentSize; + set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxDocumentSize = value; } /// @@ -87,8 +62,8 @@ public static int MaxDocumentSize /// public static int MaxSerializationDepth { - get { return __maxSerializationDepth; } - set { __maxSerializationDepth = value; } + get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxSerializationDepth; + set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxSerializationDepth = value; } } } diff --git a/src/MongoDB.Bson/BsonDefaultsDomain.cs b/src/MongoDB.Bson/BsonDefaultsDomain.cs new file mode 100644 index 00000000000..b105e739374 --- /dev/null +++ b/src/MongoDB.Bson/BsonDefaultsDomain.cs @@ -0,0 +1,73 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Collections.Generic; +using System.Dynamic; +using MongoDB.Bson.Serialization; + +namespace MongoDB.Bson +{ + internal class BsonDefaultsDomain : IBsonDefaults + { + private IBsonSerializationDomain _serializationDomain; + private bool _dynamicArraySerializerWasSet; + private IBsonSerializer _dynamicArraySerializer; + private bool _dynamicDocumentSerializerWasSet; + private IBsonSerializer _dynamicDocumentSerializer; + + public BsonDefaultsDomain(IBsonSerializationDomain serializationDomain) + { + _serializationDomain = serializationDomain; + } + + public IBsonSerializer DynamicArraySerializer + { + get + { + if (!_dynamicArraySerializerWasSet) + { + _dynamicArraySerializer = _serializationDomain.LookupSerializer>(); + } + return _dynamicArraySerializer; + } + set + { + _dynamicArraySerializerWasSet = true; + _dynamicArraySerializer = value; + } + } + + public IBsonSerializer DynamicDocumentSerializer + { + get + { + if (!_dynamicDocumentSerializerWasSet) + { + _dynamicDocumentSerializer = _serializationDomain.LookupSerializer(); + } + return _dynamicDocumentSerializer; + } + set + { + _dynamicDocumentSerializerWasSet = true; + _dynamicDocumentSerializer = value; + } + } + + public int MaxDocumentSize { get; set; } = int.MaxValue; + + public int MaxSerializationDepth { get; set; } = 100; + } +} \ No newline at end of file diff --git a/src/MongoDB.Bson/BsonExtensionMethods.cs b/src/MongoDB.Bson/BsonExtensionMethods.cs index bcb41a8271f..bd52c52e832 100644 --- a/src/MongoDB.Bson/BsonExtensionMethods.cs +++ b/src/MongoDB.Bson/BsonExtensionMethods.cs @@ -25,6 +25,8 @@ namespace MongoDB.Bson /// public static class BsonExtensionMethods { + //DOMAIN-API We should remove this and use the version with the domain. + //QUESTION: Do we want to do something now about this...? It's used also internally, but it seems in most cases it's used for "default serialization", so it should be ok. /// /// Serializes an object to a BSON byte array. /// @@ -49,6 +51,21 @@ public static byte[] ToBson( return ToBson(obj, typeof(TNominalType), writerSettings, serializer, configurator, args, estimatedBsonSize); } + internal static byte[] ToBson( + this TNominalType obj, + IBsonSerializationDomain serializationDomain, + IBsonSerializer serializer = null, + BsonBinaryWriterSettings writerSettings = null, + Action configurator = null, + BsonSerializationArgs args = default(BsonSerializationArgs), + int estimatedBsonSize = 0) + { + args.SetOrValidateNominalType(typeof(TNominalType), ""); + + return ToBson(obj, typeof(TNominalType), serializationDomain, writerSettings, serializer, configurator, args, estimatedBsonSize); + } + + //DOMAIN-API We should remove this and use the version with the domain. /// /// Serializes an object to a BSON byte array. /// @@ -68,6 +85,17 @@ public static byte[] ToBson( BsonBinaryWriterSettings writerSettings = null, IBsonSerializer serializer = null, Action configurator = null, + BsonSerializationArgs args = default, + int estimatedBsonSize = 0) => ToBson(obj, nominalType, BsonSerializer.DefaultSerializationDomain, writerSettings, + serializer, configurator, args, estimatedBsonSize); + + internal static byte[] ToBson( + this object obj, + Type nominalType, + IBsonSerializationDomain serializationDomain, + BsonBinaryWriterSettings writerSettings = null, + IBsonSerializer serializer = null, + Action configurator = null, BsonSerializationArgs args = default(BsonSerializationArgs), int estimatedBsonSize = 0) { @@ -84,7 +112,7 @@ public static byte[] ToBson( if (serializer == null) { - serializer = BsonSerializer.LookupSerializer(nominalType); + serializer = serializationDomain.LookupSerializer(nominalType); } if (serializer.ValueType != nominalType) { @@ -96,7 +124,7 @@ public static byte[] ToBson( { using (var bsonWriter = new BsonBinaryWriter(memoryStream, writerSettings ?? BsonBinaryWriterSettings.Defaults)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator); + var context = BsonSerializationContext.CreateRoot(bsonWriter, serializationDomain, configurator); serializer.Serialize(context, args, obj); } return memoryStream.ToArray(); @@ -138,7 +166,16 @@ public static BsonDocument ToBsonDocument( Type nominalType, IBsonSerializer serializer = null, Action configurator = null, - BsonSerializationArgs args = default(BsonSerializationArgs)) + BsonSerializationArgs args = default) => ToBsonDocument(obj, nominalType, + BsonSerializer.DefaultSerializationDomain, serializer, configurator, args); + + internal static BsonDocument ToBsonDocument( + this object obj, + Type nominalType, + IBsonSerializationDomain serializationDomain, + IBsonSerializer serializer = null, + Action configurator = null, + BsonSerializationArgs args = default) { if (nominalType == null) { @@ -165,7 +202,7 @@ public static BsonDocument ToBsonDocument( return convertibleToBsonDocument.ToBsonDocument(); // use the provided ToBsonDocument method } - serializer = BsonSerializer.LookupSerializer(nominalType); + serializer = serializationDomain.LookupSerializer(nominalType); } if (serializer.ValueType != nominalType) { @@ -177,7 +214,7 @@ public static BsonDocument ToBsonDocument( var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator); + var context = BsonSerializationContext.CreateRoot(bsonWriter, serializationDomain, configurator); serializer.Serialize(context, args, obj); } return document; @@ -226,6 +263,16 @@ public static string ToJson( JsonWriterSettings writerSettings = null, IBsonSerializer serializer = null, Action configurator = null, + BsonSerializationArgs args = default) + => ToJson(obj, nominalType, BsonSerializer.DefaultSerializationDomain, writerSettings, serializer, configurator, args); + + internal static string ToJson( + this object obj, + Type nominalType, + IBsonSerializationDomain domain, + JsonWriterSettings writerSettings = null, + IBsonSerializer serializer = null, + Action configurator = null, BsonSerializationArgs args = default(BsonSerializationArgs)) { if (nominalType == null) @@ -236,7 +283,7 @@ public static string ToJson( if (serializer == null) { - serializer = BsonSerializer.LookupSerializer(nominalType); + serializer = domain.LookupSerializer(nominalType); } if (serializer.ValueType != nominalType) { @@ -248,7 +295,7 @@ public static string ToJson( { using (var bsonWriter = new JsonWriter(stringWriter, writerSettings ?? JsonWriterSettings.Defaults)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator); + var context = BsonSerializationContext.CreateRoot(bsonWriter, domain, configurator); serializer.Serialize(context, args, obj); } return stringWriter.ToString(); diff --git a/src/MongoDB.Bson/IBsonDefaults.cs b/src/MongoDB.Bson/IBsonDefaults.cs new file mode 100644 index 00000000000..e843c8eb4a4 --- /dev/null +++ b/src/MongoDB.Bson/IBsonDefaults.cs @@ -0,0 +1,39 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using MongoDB.Bson.Serialization; + +namespace MongoDB.Bson +{ + internal interface IBsonDefaults + { + /// + /// + /// + IBsonSerializer DynamicArraySerializer { get; set; } + /// + /// + /// + IBsonSerializer DynamicDocumentSerializer { get; set; } + /// + /// + /// + int MaxDocumentSize { get; set; } + /// + /// + /// + int MaxSerializationDepth { get; set; } + } +} \ No newline at end of file diff --git a/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs b/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs index 1c510ed71e3..3b1cc9f4a1e 100644 --- a/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs +++ b/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs @@ -136,7 +136,7 @@ protected override BsonReaderSettings CloneImplementation() Encoding = _encoding, FixOldBinarySubTypeOnInput = _fixOldBinarySubTypeOnInput, FixOldDateTimeMaxValueOnInput = _fixOldDateTimeMaxValueOnInput, - MaxDocumentSize = _maxDocumentSize + MaxDocumentSize = _maxDocumentSize, }; return clone; diff --git a/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs b/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs index 96c8f3168de..5ee1a8c8676 100644 --- a/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs +++ b/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs @@ -122,7 +122,7 @@ protected override BsonWriterSettings CloneImplementation() Encoding = _encoding, FixOldBinarySubTypeOnOutput = _fixOldBinarySubTypeOnOutput, MaxDocumentSize = _maxDocumentSize, - MaxSerializationDepth = MaxSerializationDepth + MaxSerializationDepth = MaxSerializationDepth, }; return clone; } diff --git a/src/MongoDB.Bson/IO/BsonReader.cs b/src/MongoDB.Bson/IO/BsonReader.cs index 25724b855e7..c1e119bccb0 100644 --- a/src/MongoDB.Bson/IO/BsonReader.cs +++ b/src/MongoDB.Bson/IO/BsonReader.cs @@ -321,13 +321,15 @@ public virtual IByteBuffer ReadRawBsonArray() // overridden in BsonBinaryReader to read the raw bytes from the stream // for all other streams, deserialize the array and reserialize it using a BsonBinaryWriter to get the raw bytes - var deserializationContext = BsonDeserializationContext.CreateRoot(this); + //QUESTION Is it correct we only need a default domain here? + var deserializationContext = BsonDeserializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain); var array = BsonArraySerializer.Instance.Deserialize(deserializationContext); using (var memoryStream = new MemoryStream()) using (var bsonWriter = new BsonBinaryWriter(memoryStream, BsonBinaryWriterSettings.Defaults)) { - var serializationContext = BsonSerializationContext.CreateRoot(bsonWriter); + //QUESTION Is it correct we only need a default domain here? + var serializationContext = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain); bsonWriter.WriteStartDocument(); var startPosition = memoryStream.Position + 3; // just past BsonType, "x" and null byte bsonWriter.WriteName("x"); @@ -351,7 +353,8 @@ public virtual IByteBuffer ReadRawBsonDocument() // overridden in BsonBinaryReader to read the raw bytes from the stream // for all other streams, deserialize the document and use ToBson to get the raw bytes - var deserializationContext = BsonDeserializationContext.CreateRoot(this); + //QUESTION Is it correct we only need a default domain here? + var deserializationContext = BsonDeserializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain); var document = BsonDocumentSerializer.Instance.Deserialize(deserializationContext); var bytes = document.ToBson(); return new ByteArrayBuffer(bytes, isReadOnly: true); diff --git a/src/MongoDB.Bson/IO/BsonReaderSettings.cs b/src/MongoDB.Bson/IO/BsonReaderSettings.cs index 649c02ff59c..61992ad4c0d 100644 --- a/src/MongoDB.Bson/IO/BsonReaderSettings.cs +++ b/src/MongoDB.Bson/IO/BsonReaderSettings.cs @@ -14,6 +14,7 @@ */ using System; +using MongoDB.Bson.Serialization; namespace MongoDB.Bson.IO { diff --git a/src/MongoDB.Bson/IO/BsonWriter.cs b/src/MongoDB.Bson/IO/BsonWriter.cs index 3fd705fa31b..1e88a64b400 100644 --- a/src/MongoDB.Bson/IO/BsonWriter.cs +++ b/src/MongoDB.Bson/IO/BsonWriter.cs @@ -326,13 +326,15 @@ public virtual void WriteRawBsonArray(IByteBuffer slice) stream.Position = 0; using (var reader = new BsonBinaryReader(stream, BsonBinaryReaderSettings.Defaults)) { - var deserializationContext = BsonDeserializationContext.CreateRoot(reader); + //QUESTION Is it correct we only need a default domain here? + var deserializationContext = BsonDeserializationContext.CreateRoot(reader, BsonSerializer.DefaultSerializationDomain); reader.ReadStartDocument(); reader.ReadName("x"); var array = BsonArraySerializer.Instance.Deserialize(deserializationContext); reader.ReadEndDocument(); - var serializationContext = BsonSerializationContext.CreateRoot(this); + //QUESTION Is it correct we only need a default domain here? + var serializationContext = BsonSerializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain); BsonArraySerializer.Instance.Serialize(serializationContext, array); } } @@ -350,10 +352,12 @@ public virtual void WriteRawBsonDocument(IByteBuffer slice) using (var stream = new ByteBufferStream(slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, BsonBinaryReaderSettings.Defaults)) { - var deserializationContext = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var deserializationContext = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); var document = BsonDocumentSerializer.Instance.Deserialize(deserializationContext); - var serializationContext = BsonSerializationContext.CreateRoot(this); + //QUESTION Is it correct we only need a default domain here? + var serializationContext = BsonSerializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain); BsonDocumentSerializer.Instance.Serialize(serializationContext, document); } } diff --git a/src/MongoDB.Bson/IO/BsonWriterSettings.cs b/src/MongoDB.Bson/IO/BsonWriterSettings.cs index 06957993d70..82b92538605 100644 --- a/src/MongoDB.Bson/IO/BsonWriterSettings.cs +++ b/src/MongoDB.Bson/IO/BsonWriterSettings.cs @@ -14,6 +14,7 @@ */ using System; +using MongoDB.Bson.Serialization; namespace MongoDB.Bson.IO { diff --git a/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs b/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs index 0e83adcdb91..67ff2a866c0 100644 --- a/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs +++ b/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs @@ -60,7 +60,8 @@ public override void WriteEndDocument() Wrapped.PushSettings(_settingsConfigurator); try { - var context = BsonSerializationContext.CreateRoot(Wrapped); + //QUESTION Is it correct we only need a default domain here? + var context = BsonSerializationContext.CreateRoot(Wrapped, BsonSerializer.DefaultSerializationDomain); foreach (var element in _elements) { Wrapped.WriteName(element.Name); diff --git a/src/MongoDB.Bson/IO/IBsonReader.cs b/src/MongoDB.Bson/IO/IBsonReader.cs index 14af4722a33..89f617fe124 100644 --- a/src/MongoDB.Bson/IO/IBsonReader.cs +++ b/src/MongoDB.Bson/IO/IBsonReader.cs @@ -17,6 +17,7 @@ namespace MongoDB.Bson.IO { + //FP This interface should have the settingg property as well, same way it's done for thr writer /// /// Represents a BSON reader. /// diff --git a/src/MongoDB.Bson/InternalExtensions.cs b/src/MongoDB.Bson/InternalExtensions.cs new file mode 100644 index 00000000000..1df207a684d --- /dev/null +++ b/src/MongoDB.Bson/InternalExtensions.cs @@ -0,0 +1,107 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Conventions; + +namespace MongoDB.Bson +{ + //FP This could be moved somewhere else, and maybe reordered. + internal static class InternalExtensions + { + #region IBsonIdProvider + + public static bool GetDocumentIdInternal(this IBsonIdProvider provider, object document, IBsonSerializationDomain serializationDomain, out object id, + out Type idNominalType, out IIdGenerator idGenerator) + { + if (provider is IBsonIdProviderInternal internalProvider) + { + return internalProvider.GetDocumentId(document, serializationDomain, out id, out idNominalType, out idGenerator); + } + return provider.GetDocumentId(document, out id, out idNominalType, out idGenerator); + } + + #endregion + + #region IDiscriminatorConvention + + public static Type GetActualTypeInternal(this IDiscriminatorConvention discriminatorConvention, IBsonReader bsonReader, Type nominalType, IBsonSerializationDomain serializationDomain) + { + if (discriminatorConvention is IDiscriminatorConventionInternal internalConvention) + { + return internalConvention.GetActualType(bsonReader, nominalType, serializationDomain); + } + return discriminatorConvention.GetActualType(bsonReader, nominalType); + } + + public static BsonValue GetDiscriminatorInternal(this IDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType, IBsonSerializationDomain serializationDomain) + { + if (discriminatorConvention is IDiscriminatorConventionInternal internalConvention) + { + return internalConvention.GetDiscriminator(nominalType, actualType, serializationDomain); + } + return discriminatorConvention.GetDiscriminator(nominalType, actualType); + } + + #endregion + + #region IScalarDiscriminatorConvention + + public static BsonValue[] GetDiscriminatorsForTypeAndSubTypesInternal(this IScalarDiscriminatorConvention discriminatorConvention, Type type, IBsonSerializationDomain serializationDomain) + { + if (discriminatorConvention is IScalarDiscriminatorConventionInternal internalConvention) + { + return internalConvention.GetDiscriminatorsForTypeAndSubTypes(type, serializationDomain); + } + return discriminatorConvention.GetDiscriminatorsForTypeAndSubTypes(type); + } + + #endregion + + #region IMemberMapConvention + + public static void ApplyInternal(this IMemberMapConvention memberMapConvention, BsonMemberMap memberMap, IBsonSerializationDomain serializationDomain) + { + if (memberMapConvention is IMemberMapConventionInternal internalConvention) + { + internalConvention.Apply(memberMap, serializationDomain); + } + else + { + memberMapConvention.Apply(memberMap); + } + } + + #endregion + + #region IPostProcessingConvention + + public static void PostProcessInternal(this IPostProcessingConvention postProcessingConvention, BsonClassMap classMap, IBsonSerializationDomain serializationDomain) + { + if (postProcessingConvention is IPostProcessingConventionInternal internalConvention) + { + internalConvention.PostProcess(classMap, serializationDomain); + } + else + { + postProcessingConvention.PostProcess(classMap); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/MongoDB.Bson/ObjectModel/BsonDocument.cs b/src/MongoDB.Bson/ObjectModel/BsonDocument.cs index 535bb541b62..e6a0a02d74d 100644 --- a/src/MongoDB.Bson/ObjectModel/BsonDocument.cs +++ b/src/MongoDB.Bson/ObjectModel/BsonDocument.cs @@ -331,7 +331,8 @@ public static BsonDocument Parse(string json) { using (var jsonReader = new JsonReader(json)) { - var context = BsonDeserializationContext.CreateRoot(jsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(jsonReader, BsonSerializer.DefaultSerializationDomain); var document = BsonDocumentSerializer.Instance.Deserialize(context); if (!jsonReader.IsAtEndOfFile()) { diff --git a/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs b/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs index 09edc32dbfa..8965a4d0f8a 100644 --- a/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs +++ b/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs @@ -91,9 +91,12 @@ public object Wrapped /// The nominal type of the wrapped object. /// The wrapped object. /// A BsonDocumentWrapper. - public static BsonDocumentWrapper Create(TNominalType value) + public static BsonDocumentWrapper Create(TNominalType value) => + Create(value, BsonSerializer.DefaultSerializationDomain); + + internal static BsonDocumentWrapper Create(TNominalType value, IBsonSerializationDomain serializationDomain) { - return Create(typeof(TNominalType), value); + return Create(typeof(TNominalType), value, serializationDomain); } /// @@ -102,9 +105,12 @@ public static BsonDocumentWrapper Create(TNominalType value) /// The nominal type of the wrapped object. /// The wrapped object. /// A BsonDocumentWrapper. - public static BsonDocumentWrapper Create(Type nominalType, object value) + public static BsonDocumentWrapper Create(Type nominalType, object value) => + Create(nominalType, value, BsonSerializer.DefaultSerializationDomain); + + internal static BsonDocumentWrapper Create(Type nominalType, object value, IBsonSerializationDomain domain) { - var serializer = BsonSerializer.LookupSerializer(nominalType); + var serializer = domain.LookupSerializer(nominalType); return new BsonDocumentWrapper(value, serializer); } @@ -114,14 +120,25 @@ public static BsonDocumentWrapper Create(Type nominalType, object value) /// The nominal type of the wrapped objects. /// A list of wrapped objects. /// A list of BsonDocumentWrappers. - public static IEnumerable CreateMultiple(IEnumerable values) + public static IEnumerable CreateMultiple(IEnumerable values) => + CreateMultiple(values, BsonSerializer.DefaultSerializationDomain); + + /// + /// //TODO + /// + /// + /// + /// + /// + /// + internal static IEnumerable CreateMultiple(IEnumerable values, IBsonSerializationDomain domain) { if (values == null) { throw new ArgumentNullException("values"); } - var serializer = BsonSerializer.LookupSerializer(typeof(TNominalType)); + var serializer = domain.LookupSerializer(typeof(TNominalType)); return values.Select(v => new BsonDocumentWrapper(v, serializer)); } @@ -131,7 +148,18 @@ public static IEnumerable CreateMultiple(IEnu /// The nominal type of the wrapped object. /// A list of wrapped objects. /// A list of BsonDocumentWrappers. - public static IEnumerable CreateMultiple(Type nominalType, IEnumerable values) + public static IEnumerable CreateMultiple(Type nominalType, IEnumerable values) => + CreateMultiple(nominalType, values, BsonSerializer.DefaultSerializationDomain); + + /// + /// //TODO + /// + /// + /// + /// + /// + /// + internal static IEnumerable CreateMultiple(Type nominalType, IEnumerable values, IBsonSerializationDomain domain) { if (nominalType == null) { @@ -142,7 +170,7 @@ public static IEnumerable CreateMultiple(Type nominalType, throw new ArgumentNullException("values"); } - var serializer = BsonSerializer.LookupSerializer(nominalType); + var serializer = domain.LookupSerializer(nominalType); return values.Cast().Select(v => new BsonDocumentWrapper(v, serializer)); } @@ -178,7 +206,8 @@ protected override IEnumerable Materialize() var writerSettings = BsonDocumentWriterSettings.Defaults; using (var bsonWriter = new BsonDocumentWriter(bsonDocument, writerSettings)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + //QUESTION Is it correct we only need a default domain here? + var context = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain); _serializer.Serialize(context, _wrapped); } diff --git a/src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs b/src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs index f9232489f4f..98d44f5c5ec 100644 --- a/src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs +++ b/src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs @@ -173,7 +173,8 @@ private IEnumerable MaterializeThisLevel() using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); BsonType bsonType; diff --git a/src/MongoDB.Bson/ObjectModel/LazyBsonDocument.cs b/src/MongoDB.Bson/ObjectModel/LazyBsonDocument.cs index a95e766a3b8..3e2c9d66292 100644 --- a/src/MongoDB.Bson/ObjectModel/LazyBsonDocument.cs +++ b/src/MongoDB.Bson/ObjectModel/LazyBsonDocument.cs @@ -184,7 +184,8 @@ private IEnumerable MaterializeThisLevel() using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); BsonType bsonType; diff --git a/src/MongoDB.Bson/ObjectModel/RawBsonArray.cs b/src/MongoDB.Bson/ObjectModel/RawBsonArray.cs index 9ddbd6fcb57..2fefa970b51 100644 --- a/src/MongoDB.Bson/ObjectModel/RawBsonArray.cs +++ b/src/MongoDB.Bson/ObjectModel/RawBsonArray.cs @@ -128,7 +128,8 @@ public override IEnumerable Values using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -167,7 +168,8 @@ public override BsonValue this[int index] bsonReader.SkipName(); if (i == index) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); return DeserializeBsonValue(context); } @@ -314,7 +316,8 @@ public override bool Contains(BsonValue value) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -342,7 +345,8 @@ public override void CopyTo(BsonValue[] array, int arrayIndex) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -383,7 +387,8 @@ public override IEnumerator GetEnumerator() using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -429,7 +434,8 @@ public override int IndexOf(BsonValue value, int index, int count) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); var i = 0; @@ -489,7 +495,8 @@ public BsonArray Materialize(BsonBinaryReaderSettings binaryReaderSettings) using (var stream = new MemoryStream(bytes)) using (var reader = new BsonBinaryReader(stream, binaryReaderSettings)) { - var context = BsonDeserializationContext.CreateRoot(reader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(reader, BsonSerializer.DefaultSerializationDomain); var materializedDocument = BsonDocumentSerializer.Instance.Deserialize(context); return materializedDocument["array"].AsBsonArray; } diff --git a/src/MongoDB.Bson/ObjectModel/RawBsonDocument.cs b/src/MongoDB.Bson/ObjectModel/RawBsonDocument.cs index 6fde27bf5c3..b58265261f2 100644 --- a/src/MongoDB.Bson/ObjectModel/RawBsonDocument.cs +++ b/src/MongoDB.Bson/ObjectModel/RawBsonDocument.cs @@ -102,7 +102,8 @@ public override IEnumerable Elements using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -164,7 +165,8 @@ public override IEnumerable Values using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -352,7 +354,8 @@ public override bool ContainsValue(BsonValue value) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -408,7 +411,8 @@ public override BsonElement GetElement(int index) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); var i = 0; @@ -463,7 +467,8 @@ public override IEnumerator GetEnumerator() using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -494,7 +499,8 @@ public override BsonValue GetValue(int index) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); var i = 0; @@ -576,7 +582,8 @@ public BsonDocument Materialize(BsonBinaryReaderSettings binaryReaderSettings) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var reader = new BsonBinaryReader(stream, binaryReaderSettings)) { - var context = BsonDeserializationContext.CreateRoot(reader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(reader, BsonSerializer.DefaultSerializationDomain); return BsonDocumentSerializer.Instance.Deserialize(context); } } @@ -699,7 +706,8 @@ public override bool TryGetElement(string name, out BsonElement element) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -734,7 +742,8 @@ public override bool TryGetValue(string name, out BsonValue value) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) diff --git a/src/MongoDB.Bson/Properties/AssemblyInfo.cs b/src/MongoDB.Bson/Properties/AssemblyInfo.cs index ee574295e6c..2a1d28a924a 100644 --- a/src/MongoDB.Bson/Properties/AssemblyInfo.cs +++ b/src/MongoDB.Bson/Properties/AssemblyInfo.cs @@ -28,3 +28,8 @@ [assembly: InternalsVisibleTo("MongoDB.Bson.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")] [assembly: InternalsVisibleTo("MongoDB.Analyzer.MQLGenerator, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")] +[assembly: InternalsVisibleTo("MongoDB.Driver, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")] +[assembly: InternalsVisibleTo("MongoDB.Driver.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")] +[assembly: InternalsVisibleTo("MongoDB.Driver.Encryption, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")] +[assembly: InternalsVisibleTo("MongoDB.Driver.Authentication.AWS, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")] +[assembly: InternalsVisibleTo("MongoDB.Driver.TestHelpers, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")] diff --git a/src/MongoDB.Bson/Serialization/AttributedSerializationProvider.cs b/src/MongoDB.Bson/Serialization/AttributedSerializationProvider.cs index bc9258cb9b4..df24ee63f2c 100644 --- a/src/MongoDB.Bson/Serialization/AttributedSerializationProvider.cs +++ b/src/MongoDB.Bson/Serialization/AttributedSerializationProvider.cs @@ -20,6 +20,7 @@ namespace MongoDB.Bson.Serialization { + //DOMAIN-API We should consider making all our serialization provider classes sealed or internal. /// /// Provides serializers based on an attribute. /// diff --git a/src/MongoDB.Bson/Serialization/BsonClassMap.cs b/src/MongoDB.Bson/Serialization/BsonClassMap.cs index 0f524fe2326..1d965e89cff 100644 --- a/src/MongoDB.Bson/Serialization/BsonClassMap.cs +++ b/src/MongoDB.Bson/Serialization/BsonClassMap.cs @@ -31,15 +31,9 @@ namespace MongoDB.Bson.Serialization /// public class BsonClassMap { - // private static fields - private readonly static Dictionary __classMaps = new Dictionary(); - private readonly static Queue __knownTypesQueue = new Queue(); - private static int __freezeNestingLevel = 0; - // private fields private readonly Type _classType; private readonly List _creatorMaps; - private readonly IConventionPack _conventionPack; private readonly bool _isAnonymous; private readonly List _allMemberMaps; // includes inherited member maps private readonly ReadOnlyCollection _allMemberMapsReadonly; @@ -70,7 +64,6 @@ public BsonClassMap(Type classType) { _classType = classType; _creatorMaps = new List(); - _conventionPack = ConventionRegistry.Lookup(classType); _isAnonymous = classType.IsAnonymousType(); _allMemberMaps = new List(); _allMemberMapsReadonly = _allMemberMaps.AsReadOnly(); @@ -124,12 +117,13 @@ public IEnumerable CreatorMaps get { return _creatorMaps; } } + //DOMAIN-API This one should be removed, or become a method to get the convention registry/domain as input /// /// Gets the conventions used for auto mapping. /// public IConventionPack ConventionPack { - get { return _conventionPack; } + get { return BsonSerializer.DefaultSerializationDomain.ConventionRegistry.Lookup(_classType); } } /// @@ -253,6 +247,7 @@ internal int ExtraElementsMemberMapIndex get { return _extraElementsMemberIndex; } } + //DOMAIN-API This is a utility method, it should not be public. // public static methods /// /// Gets the type of a member. @@ -282,103 +277,32 @@ public static Type GetMemberInfoType(MemberInfo memberInfo) /// Gets all registered class maps. /// /// All registered class maps. - public static IEnumerable GetRegisteredClassMaps() - { - BsonSerializer.ConfigLock.EnterReadLock(); - try - { - return __classMaps.Values.ToList(); // return a copy for thread safety - } - finally - { - BsonSerializer.ConfigLock.ExitReadLock(); - } - } + public static IEnumerable GetRegisteredClassMaps() => + BsonSerializer.DefaultSerializationDomain.BsonClassMap.GetRegisteredClassMaps(); /// /// Checks whether a class map is registered for a type. /// /// The type to check. /// True if there is a class map registered for the type. - public static bool IsClassMapRegistered(Type type) - { - if (type == null) - { - throw new ArgumentNullException("type"); - } - - BsonSerializer.ConfigLock.EnterReadLock(); - try - { - return __classMaps.ContainsKey(type); - } - finally - { - BsonSerializer.ConfigLock.ExitReadLock(); - } - } + public static bool IsClassMapRegistered(Type type) => + BsonSerializer.DefaultSerializationDomain.BsonClassMap.IsClassMapRegistered(type); /// /// Looks up a class map (will AutoMap the class if no class map is registered). /// /// The class type. /// The class map. - public static BsonClassMap LookupClassMap(Type classType) - { - if (classType == null) - { - throw new ArgumentNullException("classType"); - } - - BsonSerializer.ConfigLock.EnterReadLock(); - try - { - if (__classMaps.TryGetValue(classType, out var classMap)) - { - if (classMap.IsFrozen) - { - return classMap; - } - } - } - finally - { - BsonSerializer.ConfigLock.ExitReadLock(); - } - - // automatically create a new classMap for classType and register it (unless another thread does first) - // do the work of speculatively creating a new class map outside of holding any lock - var classMapDefinition = typeof(BsonClassMap<>); - var classMapType = classMapDefinition.MakeGenericType(classType); - var newClassMap = (BsonClassMap)Activator.CreateInstance(classMapType); - newClassMap.AutoMap(); - - BsonSerializer.ConfigLock.EnterWriteLock(); - try - { - if (!__classMaps.TryGetValue(classType, out var classMap)) - { - RegisterClassMap(newClassMap); - classMap = newClassMap; - } - - return classMap.Freeze(); - } - finally - { - BsonSerializer.ConfigLock.ExitWriteLock(); - } - } + public static BsonClassMap LookupClassMap(Type classType) => + BsonSerializer.DefaultSerializationDomain.BsonClassMap.LookupClassMap(classType); /// /// Creates and registers a class map. /// /// The class. /// The class map. - public static BsonClassMap RegisterClassMap() - { - return RegisterClassMap(cm => { cm.AutoMap(); }); - } + public static BsonClassMap RegisterClassMap()=> + BsonSerializer.DefaultSerializationDomain.BsonClassMap.RegisterClassMap(); /// /// Creates and registers a class map. @@ -387,35 +311,14 @@ public static BsonClassMap RegisterClassMap() /// The class map initializer. /// The class map. public static BsonClassMap RegisterClassMap(Action> classMapInitializer) - { - var classMap = new BsonClassMap(classMapInitializer); - RegisterClassMap(classMap); - return classMap; - } + => BsonSerializer.DefaultSerializationDomain.BsonClassMap.RegisterClassMap(classMapInitializer); /// /// Registers a class map. /// /// The class map. public static void RegisterClassMap(BsonClassMap classMap) - { - if (classMap == null) - { - throw new ArgumentNullException("classMap"); - } - - BsonSerializer.ConfigLock.EnterWriteLock(); - try - { - // note: class maps can NOT be replaced (because derived classes refer to existing instance) - __classMaps.Add(classMap.ClassType, classMap); - BsonSerializer.RegisterDiscriminator(classMap.ClassType, classMap.Discriminator); - } - finally - { - BsonSerializer.ConfigLock.ExitWriteLock(); - } - } + => BsonSerializer.DefaultSerializationDomain.BsonClassMap.RegisterClassMap(classMap); /// /// Registers a class map if it is not already registered. @@ -423,16 +326,7 @@ public static void RegisterClassMap(BsonClassMap classMap) /// The class. /// True if this call registered the class map, false if the class map was already registered. public static bool TryRegisterClassMap() - { - return TryRegisterClassMap(ClassMapFactory); - - static BsonClassMap ClassMapFactory() - { - var classMap = new BsonClassMap(); - classMap.AutoMap(); - return classMap; - } - } + => BsonSerializer.DefaultSerializationDomain.BsonClassMap.TryRegisterClassMap(); /// /// Registers a class map if it is not already registered. @@ -441,19 +335,7 @@ static BsonClassMap ClassMapFactory() /// The class map. /// True if this call registered the class map, false if the class map was already registered. public static bool TryRegisterClassMap(BsonClassMap classMap) - { - if (classMap == null) - { - throw new ArgumentNullException(nameof(classMap)); - } - - return TryRegisterClassMap(ClassMapFactory); - - BsonClassMap ClassMapFactory() - { - return classMap; - } - } + => BsonSerializer.DefaultSerializationDomain.BsonClassMap.TryRegisterClassMap(classMap); /// /// Registers a class map if it is not already registered. @@ -462,19 +344,7 @@ BsonClassMap ClassMapFactory() /// The class map initializer (only called if the class map is not already registered). /// True if this call registered the class map, false if the class map was already registered. public static bool TryRegisterClassMap(Action> classMapInitializer) - { - if (classMapInitializer == null) - { - throw new ArgumentNullException(nameof(classMapInitializer)); - } - - return TryRegisterClassMap(ClassMapFactory); - - BsonClassMap ClassMapFactory() - { - return new BsonClassMap(classMapInitializer); - } - } + => BsonSerializer.DefaultSerializationDomain.BsonClassMap.TryRegisterClassMap(classMapInitializer); /// /// Registers a class map if it is not already registered. @@ -483,54 +353,22 @@ BsonClassMap ClassMapFactory() /// The class map factory (only called if the class map is not already registered). /// True if this call registered the class map, false if the class map was already registered. public static bool TryRegisterClassMap(Func> classMapFactory) - { - if (classMapFactory == null) - { - throw new ArgumentNullException(nameof(classMapFactory)); - } - - BsonSerializer.ConfigLock.EnterReadLock(); - try - { - if (__classMaps.ContainsKey(typeof(TClass))) - { - return false; - } - } - finally - { - BsonSerializer.ConfigLock.ExitReadLock(); - } - - BsonSerializer.ConfigLock.EnterWriteLock(); - try - { - if (__classMaps.ContainsKey(typeof(TClass))) - { - return false; - } - else - { - // create a classMap for TClass and register it - var classMap = classMapFactory(); - RegisterClassMap(classMap); - return true; - } - } - finally - { - BsonSerializer.ConfigLock.ExitWriteLock(); - } - } + => BsonSerializer.DefaultSerializationDomain.BsonClassMap.TryRegisterClassMap(classMapFactory); // public methods /// /// Automaps the class. /// - public void AutoMap() + public void AutoMap() => AutoMap(BsonSerializer.DefaultSerializationDomain); + + /// + /// //TODO + /// + /// + internal void AutoMap(IBsonSerializationDomain serializationDomain) { if (_frozen) { ThrowFrozenException(); } - AutoMapClass(); + AutoMapClass(serializationDomain); } /// @@ -573,13 +411,29 @@ obj is BsonClassMap other && /// public override int GetHashCode() => 0; + internal class FreezeContext + { + public int FreezeNestingLevel { get; set; } = 0; + public Queue KnownTypesQueue { get; set; } = new(); + public IBsonSerializationDomain SerializationDomain { get; set; } + } + /// /// Freezes the class map. /// /// The frozen class map. - public BsonClassMap Freeze() + public BsonClassMap Freeze() => Freeze(BsonSerializer.DefaultSerializationDomain); + + internal BsonClassMap Freeze(IBsonSerializationDomain domain) + { + var freezeContext = new FreezeContext { SerializationDomain = domain }; + return Freeze(freezeContext); + } + + private BsonClassMap Freeze(FreezeContext context) { - BsonSerializer.ConfigLock.EnterReadLock(); + var configLock = context.SerializationDomain!.ConfigLock; + configLock.EnterReadLock(); try { if (_frozen) @@ -589,15 +443,15 @@ public BsonClassMap Freeze() } finally { - BsonSerializer.ConfigLock.ExitReadLock(); + configLock.ExitReadLock(); } - BsonSerializer.ConfigLock.EnterWriteLock(); + configLock.EnterWriteLock(); try { if (!_frozen) { - __freezeNestingLevel++; + context.FreezeNestingLevel++; try { var baseType = _classType.GetTypeInfo().BaseType; @@ -605,9 +459,9 @@ public BsonClassMap Freeze() { if (_baseClassMap == null) { - _baseClassMap = LookupClassMap(baseType); + _baseClassMap = context.SerializationDomain.BsonClassMap.LookupClassMap(baseType); } - _baseClassMap.Freeze(); + _baseClassMap.Freeze(context); _discriminatorIsRequired |= _baseClassMap._discriminatorIsRequired; _hasRootClass |= (_isRootClass || _baseClassMap.HasRootClass); _allMemberMaps.AddRange(_baseClassMap.AllMemberMaps); @@ -699,28 +553,28 @@ public BsonClassMap Freeze() // this avoids infinite recursion when going back down the inheritance tree while processing known types foreach (var knownType in _knownTypes) { - __knownTypesQueue.Enqueue(knownType); + context.KnownTypesQueue.Enqueue(knownType); } // if we are back to the first level go ahead and process any queued known types - if (__freezeNestingLevel == 1) + if (context.FreezeNestingLevel == 1) { - while (__knownTypesQueue.Count != 0) + while (context.KnownTypesQueue.Count != 0) { - var knownType = __knownTypesQueue.Dequeue(); - LookupClassMap(knownType); // will AutoMap and/or Freeze knownType if necessary + var knownType = context.KnownTypesQueue.Dequeue(); + context.SerializationDomain.BsonClassMap.LookupClassMap(knownType); // will AutoMap and/or Freeze knownType if necessary } } } finally { - __freezeNestingLevel--; + context.FreezeNestingLevel--; } } } finally { - BsonSerializer.ConfigLock.ExitWriteLock(); + configLock.ExitWriteLock(); } return this; } @@ -1317,7 +1171,7 @@ public void UnmapProperty(string propertyName) /// Gets the discriminator convention for the class. /// /// The discriminator convention for the class. - internal IDiscriminatorConvention GetDiscriminatorConvention() + internal IDiscriminatorConvention GetDiscriminatorConvention(IBsonSerializationDomain serializationDomain) { // return a cached discriminator convention when possible var discriminatorConvention = _discriminatorConvention; @@ -1354,7 +1208,7 @@ IDiscriminatorConvention LookupDiscriminatorConvention() return classMap._discriminatorConvention; } - if (BsonSerializer.IsDiscriminatorConventionRegisteredAtThisLevel(classMap._classType)) + if (serializationDomain.IsDiscriminatorConventionRegisteredAtThisLevel(classMap._classType)) { // in this case LookupDiscriminatorConvention below will find it break; @@ -1363,21 +1217,29 @@ IDiscriminatorConvention LookupDiscriminatorConvention() if (classMap._isRootClass) { // in this case auto-register a hierarchical convention for the root class and look it up as usual below - BsonSerializer.GetOrRegisterDiscriminatorConvention(classMap._classType, StandardDiscriminatorConvention.Hierarchical); + serializationDomain.GetOrRegisterDiscriminatorConvention(classMap._classType, StandardDiscriminatorConvention.Hierarchical); break; } classMap = classMap._baseClassMap; } - return BsonSerializer.LookupDiscriminatorConvention(_classType); + return serializationDomain.LookupDiscriminatorConvention(_classType); } } + /// + /// Gets the discriminator convention for the class. + /// + /// The discriminator convention for the class. + internal IDiscriminatorConvention GetDiscriminatorConvention() + => GetDiscriminatorConvention(BsonSerializer.DefaultSerializationDomain); + // private methods - private void AutoMapClass() + private void AutoMapClass(IBsonSerializationDomain serializationDomain) { - new ConventionRunner(_conventionPack).Apply(this); + var conventionPack = serializationDomain.ConventionRegistry.Lookup(_classType); + new ConventionRunner(conventionPack).Apply(this, serializationDomain); foreach (var memberMap in _declaredMemberMaps) { diff --git a/src/MongoDB.Bson/Serialization/BsonClassMapDomain.cs b/src/MongoDB.Bson/Serialization/BsonClassMapDomain.cs new file mode 100644 index 00000000000..9efe6c84a1d --- /dev/null +++ b/src/MongoDB.Bson/Serialization/BsonClassMapDomain.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace MongoDB.Bson.Serialization; + +internal class BsonClassMapDomain : IBsonClassMapDomain +{ + // private fields + private readonly IBsonSerializationDomain _serializationDomain; + private readonly Dictionary _classMaps = new(); + + public BsonClassMapDomain(BsonSerializationDomain serializationDomain) + { + _serializationDomain = serializationDomain; + } + + /// + /// Gets all registered class maps. + /// + /// All registered class maps. + public IEnumerable GetRegisteredClassMaps() + { + _serializationDomain.ConfigLock.EnterReadLock(); + try + { + return _classMaps.Values.ToList(); // return a copy for thread safety + } + finally + { + _serializationDomain.ConfigLock.ExitReadLock(); + } + } + + /// + /// Checks whether a class map is registered for a type. + /// + /// The type to check. + /// True if there is a class map registered for the type. + public bool IsClassMapRegistered(Type type) + { + if (type == null) + { + throw new ArgumentNullException("type"); + } + + _serializationDomain.ConfigLock.EnterReadLock(); + try + { + return _classMaps.ContainsKey(type); + } + finally + { + _serializationDomain.ConfigLock.ExitReadLock(); + } + } + + /// + /// Looks up a class map (will AutoMap the class if no class map is registered). + /// + /// The class type. + /// The class map. + public BsonClassMap LookupClassMap(Type classType) + { + if (classType == null) + { + throw new ArgumentNullException("classType"); + } + + _serializationDomain.ConfigLock.EnterReadLock(); + try + { + if (_classMaps.TryGetValue(classType, out var classMap)) + { + if (classMap.IsFrozen) + { + return classMap; + } + } + } + finally + { + _serializationDomain.ConfigLock.ExitReadLock(); + } + + // automatically create a new classMap for classType and register it (unless another thread does first) + // do the work of speculatively creating a new class map outside of holding any lock + var classMapDefinition = typeof(BsonClassMap<>); + var classMapType = classMapDefinition.MakeGenericType(classType); + var newClassMap = (BsonClassMap)Activator.CreateInstance(classMapType); + newClassMap.AutoMap(_serializationDomain); + + _serializationDomain.ConfigLock.EnterWriteLock(); + try + { + if (!_classMaps.TryGetValue(classType, out var classMap)) + { + RegisterClassMap(newClassMap); + classMap = newClassMap; + } + + return classMap.Freeze(_serializationDomain); + } + finally + { + _serializationDomain.ConfigLock.ExitWriteLock(); + } + } + + /// + /// Creates and registers a class map. + /// + /// The class. + /// The class map. + public BsonClassMap RegisterClassMap() + { + return RegisterClassMap(cm => { cm.AutoMap(_serializationDomain); }); + } + + /// + /// Creates and registers a class map. + /// + /// The class. + /// The class map initializer. + /// The class map. + public BsonClassMap RegisterClassMap(Action> classMapInitializer) + { + var classMap = new BsonClassMap(classMapInitializer); + RegisterClassMap(classMap); + return classMap; + } + + /// + /// Registers a class map. + /// + /// The class map. + public void RegisterClassMap(BsonClassMap classMap) + { + if (classMap == null) + { + throw new ArgumentNullException("classMap"); + } + + _serializationDomain.ConfigLock.EnterWriteLock(); + try + { + // note: class maps can NOT be replaced (because derived classes refer to existing instance) + _classMaps.Add(classMap.ClassType, classMap); + _serializationDomain.RegisterDiscriminator(classMap.ClassType, classMap.Discriminator); + } + finally + { + _serializationDomain.ConfigLock.ExitWriteLock(); + } + } + + /// + /// Registers a class map if it is not already registered. + /// + /// The class. + /// True if this call registered the class map, false if the class map was already registered. + public bool TryRegisterClassMap() + { + return TryRegisterClassMap(() => ClassMapFactory(_serializationDomain)); + + static BsonClassMap ClassMapFactory(IBsonSerializationDomain serializationDomain) + { + var classMap = new BsonClassMap(); + classMap.AutoMap(serializationDomain); + return classMap; + } + } + + /// + /// Registers a class map if it is not already registered. + /// + /// The class. + /// The class map. + /// True if this call registered the class map, false if the class map was already registered. + public bool TryRegisterClassMap(BsonClassMap classMap) + { + if (classMap == null) + { + throw new ArgumentNullException(nameof(classMap)); + } + + return TryRegisterClassMap(ClassMapFactory); + + BsonClassMap ClassMapFactory() + { + return classMap; + } + } + + /// + /// Registers a class map if it is not already registered. + /// + /// The class. + /// The class map initializer (only called if the class map is not already registered). + /// True if this call registered the class map, false if the class map was already registered. + public bool TryRegisterClassMap(Action> classMapInitializer) + { + if (classMapInitializer == null) + { + throw new ArgumentNullException(nameof(classMapInitializer)); + } + + return TryRegisterClassMap(ClassMapFactory); + + BsonClassMap ClassMapFactory() + { + return new BsonClassMap(classMapInitializer); + } + } + + /// + /// Registers a class map if it is not already registered. + /// + /// The class. + /// The class map factory (only called if the class map is not already registered). + /// True if this call registered the class map, false if the class map was already registered. + public bool TryRegisterClassMap(Func> classMapFactory) + { + if (classMapFactory == null) + { + throw new ArgumentNullException(nameof(classMapFactory)); + } + + _serializationDomain.ConfigLock.EnterReadLock(); + try + { + if (_classMaps.ContainsKey(typeof(TClass))) + { + return false; + } + } + finally + { + _serializationDomain.ConfigLock.ExitReadLock(); + } + + _serializationDomain.ConfigLock.EnterWriteLock(); + try + { + if (_classMaps.ContainsKey(typeof(TClass))) + { + return false; + } + else + { + // create a classMap for TClass and register it + var classMap = classMapFactory(); + RegisterClassMap(classMap); + return true; + } + } + finally + { + _serializationDomain.ConfigLock.ExitWriteLock(); + } + } +} \ No newline at end of file diff --git a/src/MongoDB.Bson/Serialization/BsonClassMapSerializationProvider.cs b/src/MongoDB.Bson/Serialization/BsonClassMapSerializationProvider.cs index ac088360c2d..563c0871780 100644 --- a/src/MongoDB.Bson/Serialization/BsonClassMapSerializationProvider.cs +++ b/src/MongoDB.Bson/Serialization/BsonClassMapSerializationProvider.cs @@ -21,10 +21,21 @@ namespace MongoDB.Bson.Serialization /// /// Represents the class map serialization provider. /// - internal class BsonClassMapSerializationProvider : BsonSerializationProviderBase + internal class BsonClassMapSerializationProvider : BsonSerializationProviderBase, IDomainAwareBsonSerializationProvider { + public IBsonSerializationDomain SerializationDomain { get; } + + public BsonClassMapSerializationProvider(IBsonSerializationDomain serializationDomain) + { + SerializationDomain = serializationDomain; + } + + //DOMAIN-API This method should be removed. /// public override IBsonSerializer GetSerializer(Type type, IBsonSerializerRegistry serializerRegistry) + => GetSerializerWithDomain(type); + + public IBsonSerializer GetSerializerWithDomain(Type type) { if (type == null) { @@ -41,7 +52,7 @@ public override IBsonSerializer GetSerializer(Type type, IBsonSerializerRegistry !typeof(Array).GetTypeInfo().IsAssignableFrom(type) && !typeof(Enum).GetTypeInfo().IsAssignableFrom(type)) { - var classMap = BsonClassMap.LookupClassMap(type); + var classMap = SerializationDomain.BsonClassMap.LookupClassMap(type); var classMapSerializerDefinition = typeof(BsonClassMapSerializer<>); var classMapSerializerType = classMapSerializerDefinition.MakeGenericType(type); return (IBsonSerializer)Activator.CreateInstance(classMapSerializerType, classMap); diff --git a/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs b/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs index 03ab3137326..696e2f9c39b 100644 --- a/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs +++ b/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs @@ -14,6 +14,7 @@ */ using System; +using System.Net; using MongoDB.Bson.IO; namespace MongoDB.Bson.Serialization @@ -28,10 +29,12 @@ public class BsonDeserializationContext private readonly IBsonSerializer _dynamicArraySerializer; private readonly IBsonSerializer _dynamicDocumentSerializer; private readonly IBsonReader _reader; + private readonly IBsonSerializationDomain _serializationDomain; // constructors private BsonDeserializationContext( IBsonReader reader, + IBsonSerializationDomain serializationDomain, bool allowDuplicateElementNames, IBsonSerializer dynamicArraySerializer, IBsonSerializer dynamicDocumentSerializer) @@ -40,6 +43,12 @@ private BsonDeserializationContext( _allowDuplicateElementNames = allowDuplicateElementNames; _dynamicArraySerializer = dynamicArraySerializer; _dynamicDocumentSerializer = dynamicDocumentSerializer; + + _serializationDomain = serializationDomain; //FP Using this version to find error in an easier way for now + //_serializationDomain = serializationDomain ?? BsonSerializer.DefaultSerializationDomain; + + _dynamicArraySerializer ??= _serializationDomain.BsonDefaults.DynamicArraySerializer; + _dynamicDocumentSerializer ??= _serializationDomain.BsonDefaults.DynamicDocumentSerializer; } // public properties @@ -54,6 +63,11 @@ public bool AllowDuplicateElementNames get { return _allowDuplicateElementNames; } } + /// + /// //TODO + /// + internal IBsonSerializationDomain SerializationDomain => _serializationDomain; + /// /// Gets the dynamic array serializer. /// @@ -87,6 +101,7 @@ public IBsonReader Reader get { return _reader; } } + // //DOMAIN-API We should remove this version of the CreateRoot method, and use the one that takes a serialization domain. // public static methods /// /// Creates a root context. @@ -99,8 +114,14 @@ public IBsonReader Reader public static BsonDeserializationContext CreateRoot( IBsonReader reader, Action configurator = null) + => CreateRoot(reader, BsonSerializer.DefaultSerializationDomain, configurator); + + internal static BsonDeserializationContext CreateRoot( + IBsonReader reader, + IBsonSerializationDomain serializationDomain, + Action configurator = null) { - var builder = new Builder(null, reader); + var builder = new Builder(null, reader, serializationDomain); if (configurator != null) { configurator(builder); @@ -119,7 +140,7 @@ public static BsonDeserializationContext CreateRoot( public BsonDeserializationContext With( Action configurator = null) { - var builder = new Builder(this, _reader); + var builder = new Builder(this, _reader, _serializationDomain); if (configurator != null) { configurator(builder); @@ -138,9 +159,10 @@ public class Builder private IBsonSerializer _dynamicArraySerializer; private IBsonSerializer _dynamicDocumentSerializer; private IBsonReader _reader; + private IBsonSerializationDomain _serializationDomain; // constructors - internal Builder(BsonDeserializationContext other, IBsonReader reader) + internal Builder(BsonDeserializationContext other, IBsonReader reader, IBsonSerializationDomain serializationDomain) { if (reader == null) { @@ -148,17 +170,17 @@ internal Builder(BsonDeserializationContext other, IBsonReader reader) } _reader = reader; + _serializationDomain = serializationDomain; if (other != null) { _allowDuplicateElementNames = other.AllowDuplicateElementNames; _dynamicArraySerializer = other.DynamicArraySerializer; _dynamicDocumentSerializer = other.DynamicDocumentSerializer; } - else - { - _dynamicArraySerializer = BsonDefaults.DynamicArraySerializer; - _dynamicDocumentSerializer = BsonDefaults.DynamicDocumentSerializer; - } + + /* QUESTION I removed the part where we set the dynamic serializers from the BsonDefaults, and delay it until we have a serialization domain (when we build the DeserializationContext). + * This is technically changing the public behaviour, but it's in a builder, I do not thing it will affect anyone. Same done for the serialization context. + */ } // properties @@ -209,6 +231,8 @@ public IBsonReader Reader get { return _reader; } } + internal IBsonSerializationDomain SerializationDomain => _serializationDomain; + // public methods /// /// Builds the BsonDeserializationContext instance. @@ -216,7 +240,7 @@ public IBsonReader Reader /// A BsonDeserializationContext. internal BsonDeserializationContext Build() { - return new BsonDeserializationContext(_reader, _allowDuplicateElementNames, _dynamicArraySerializer, _dynamicDocumentSerializer); + return new BsonDeserializationContext(_reader, _serializationDomain, _allowDuplicateElementNames, _dynamicArraySerializer, _dynamicDocumentSerializer); } } } diff --git a/src/MongoDB.Bson/Serialization/BsonMemberMap.cs b/src/MongoDB.Bson/Serialization/BsonMemberMap.cs index b10971d5249..1181af3c7a8 100644 --- a/src/MongoDB.Bson/Serialization/BsonMemberMap.cs +++ b/src/MongoDB.Bson/Serialization/BsonMemberMap.cs @@ -56,7 +56,7 @@ public BsonMemberMap(BsonClassMap classMap, MemberInfo memberInfo) { _classMap = classMap; _memberInfo = memberInfo; - _memberType = BsonClassMap.GetMemberInfoType(memberInfo); + _memberType = BsonClassMap.GetMemberInfoType(memberInfo); //FP This is more of a utility method, it can stay like this _memberTypeIsBsonValue = typeof(BsonValue).GetTypeInfo().IsAssignableFrom(_memberType); Reset(); @@ -294,14 +294,16 @@ obj is BsonMemberMap other && /// Gets the serializer. /// /// The serializer. - public IBsonSerializer GetSerializer() + public IBsonSerializer GetSerializer() => GetSerializer(BsonSerializer.DefaultSerializationDomain); + + internal IBsonSerializer GetSerializer(IBsonSerializationDomain domain) { if (_serializer == null) { // return special serializer for BsonValue members that handles the _csharpnull representation if (_memberTypeIsBsonValue) { - var wrappedSerializer = BsonSerializer.LookupSerializer(_memberType); + var wrappedSerializer = domain.LookupSerializer(_memberType); var isBsonArraySerializer = wrappedSerializer is IBsonArraySerializer; var isBsonDocumentSerializer = wrappedSerializer is IBsonDocumentSerializer; @@ -329,7 +331,7 @@ public IBsonSerializer GetSerializer() } else { - _serializer = BsonSerializer.LookupSerializer(_memberType); + _serializer = domain.LookupSerializer(_memberType); } } return _serializer; diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs b/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs index a14a62322a8..8c046d91911 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs @@ -26,17 +26,31 @@ public class BsonSerializationContext // private fields private readonly Func _isDynamicType; private readonly IBsonWriter _writer; + private readonly IBsonSerializationDomain _serializationDomain; // constructors private BsonSerializationContext( IBsonWriter writer, + IBsonSerializationDomain serializationDomain, Func isDynamicType) { _writer = writer; _isDynamicType = isDynamicType; + + _serializationDomain = serializationDomain; //FP Using this version to find error in an easier way for now + //_serializationDomain = serializationDomain ?? BsonSerializer.DefaultSerializationDomain; + + _isDynamicType??= t => + (_serializationDomain.BsonDefaults.DynamicArraySerializer != null && t == _serializationDomain.BsonDefaults.DynamicArraySerializer.ValueType) || + (_serializationDomain.BsonDefaults.DynamicDocumentSerializer != null && t == _serializationDomain.BsonDefaults.DynamicDocumentSerializer.ValueType); } // public properties + /// + /// //TODO + /// + internal IBsonSerializationDomain SerializationDomain => _serializationDomain; + /// /// Gets a function that, when executed, will indicate whether the type /// is a dynamic type. @@ -57,6 +71,7 @@ public IBsonWriter Writer get { return _writer; } } + //DOMAIN-API This method should be probably removed. // public static methods /// /// Creates a root context. @@ -69,8 +84,14 @@ public IBsonWriter Writer public static BsonSerializationContext CreateRoot( IBsonWriter writer, Action configurator = null) + => CreateRoot(writer, BsonSerializer.DefaultSerializationDomain, configurator); + + internal static BsonSerializationContext CreateRoot( + IBsonWriter writer, + IBsonSerializationDomain serializationDomain, + Action configurator = null) { - var builder = new Builder(null, writer); + var builder = new Builder(null, writer, serializationDomain); if (configurator != null) { configurator(builder); @@ -88,7 +109,7 @@ public static BsonSerializationContext CreateRoot( public BsonSerializationContext With( Action configurator = null) { - var builder = new Builder(this, _writer); + var builder = new Builder(this, _writer, _serializationDomain); if (configurator != null) { configurator(builder); @@ -105,9 +126,10 @@ public class Builder // private fields private Func _isDynamicType; private IBsonWriter _writer; + private IBsonSerializationDomain _serializationDomain; // constructors - internal Builder(BsonSerializationContext other, IBsonWriter writer) + internal Builder(BsonSerializationContext other, IBsonWriter writer, IBsonSerializationDomain serializationDomain) { if (writer == null) { @@ -115,16 +137,15 @@ internal Builder(BsonSerializationContext other, IBsonWriter writer) } _writer = writer; + _serializationDomain = serializationDomain; if (other != null) { _isDynamicType = other._isDynamicType; } - else - { - _isDynamicType = t => - (BsonDefaults.DynamicArraySerializer != null && t == BsonDefaults.DynamicArraySerializer.ValueType) || - (BsonDefaults.DynamicDocumentSerializer != null && t == BsonDefaults.DynamicDocumentSerializer.ValueType); - } + + /* QUESTION I removed the part where we set _isDynamicType from the BsonDefaults, and delay it until we have a serialization domain (when we build the SerializationContext). + * This is technically changing the public behaviour, but it's in a builder, I do not thing it will affect anyone. Same done for the deserialization context. + */ } // properties @@ -155,7 +176,7 @@ public IBsonWriter Writer /// A BsonSerializationContext. internal BsonSerializationContext Build() { - return new BsonSerializationContext(_writer, _isDynamicType); + return new BsonSerializationContext(_writer, _serializationDomain, _isDynamicType); } } } diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationDomain.cs b/src/MongoDB.Bson/Serialization/BsonSerializationDomain.cs new file mode 100644 index 00000000000..8ffebd8b08d --- /dev/null +++ b/src/MongoDB.Bson/Serialization/BsonSerializationDomain.cs @@ -0,0 +1,878 @@ +/* Copyright 2010-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Conventions; +using MongoDB.Bson.Serialization.IdGenerators; + +namespace MongoDB.Bson.Serialization +{ + /// + /// A class that represents the BSON serialization functionality. + /// + internal class BsonSerializationDomain : IBsonSerializationDomain, IDisposable + { + // private fields + private IBsonDefaults _bsonDefaults; + private ReaderWriterLockSlim _configLock = new(LockRecursionPolicy.SupportsRecursion); + private IBsonClassMapDomain _classMapDomain; + private IConventionRegistryDomain _conventionRegistryDomain; + private Dictionary _idGenerators = new(); + private Dictionary _discriminatorConventions = new(); + private Dictionary> _discriminators = new(); + private HashSet _discriminatedTypes = new(); + private BsonSerializerRegistry _serializerRegistry; + private TypeMappingSerializationProvider _typeMappingSerializationProvider; + // ConcurrentDictionary is being used as a concurrent set of Type. The values will always be null. + private ConcurrentDictionary _typesWithRegisteredKnownTypes = new(); + + private bool _useNullIdChecker; + private bool _useZeroIdChecker; + + // constructor + public BsonSerializationDomain(string name = null) + { + CreateSerializerRegistry(); + CreateSubDomains(); + RegisterIdGenerators(); + Name = name ?? "CUSTOM"; + } + + public string Name { get; } + + // public properties + /// + /// Gets the serializer registry. + /// + public IBsonSerializerRegistry SerializerRegistry + { + get { return _serializerRegistry; } + } + + /// + /// Gets or sets whether to use the NullIdChecker on reference Id types that don't have an IdGenerator registered. + /// + public bool UseNullIdChecker + { + get { return _useNullIdChecker; } + set { _useNullIdChecker = value; } + } + + public bool UseNullIdCheckerEnabled => UseNullIdChecker; + + /// + /// Gets or sets whether to use the ZeroIdChecker on value Id types that don't have an IdGenerator registered. + /// + public bool UseZeroIdChecker + { + get { return _useZeroIdChecker; } + set { _useZeroIdChecker = value; } + } + + public bool UseZeroIdCheckerEnabled => UseZeroIdChecker; + + // internal properties + public ReaderWriterLockSlim ConfigLock + { + get { return _configLock; } + } + + /// + /// Deserializes an object from a BsonDocument. + /// + /// The nominal type of the object. + /// The BsonDocument. + /// The configurator. + /// A deserialized value. + public TNominalType Deserialize(BsonDocument document, + Action configurator = null) + { + using (var bsonReader = new BsonDocumentReader(document)) + { + return Deserialize(bsonReader, configurator); + } + } + + /// + /// Deserializes a value. + /// + /// The nominal type of the object. + /// The BsonReader. + /// The configurator. + /// A deserialized value. + public TNominalType Deserialize(IBsonReader bsonReader, + Action configurator = null) + { + var serializer = LookupSerializer(); + var context = BsonDeserializationContext.CreateRoot(bsonReader, this, configurator); + return serializer.Deserialize(context); + } + + /// + /// Deserializes an object from a BSON byte array. + /// + /// The nominal type of the object. + /// The BSON byte array. + /// The configurator. + /// A deserialized value. + public TNominalType Deserialize(byte[] bytes, + Action configurator = null) + { + using (var buffer = new ByteArrayBuffer(bytes, isReadOnly: true)) + using (var stream = new ByteBufferStream(buffer)) + { + return Deserialize(stream, configurator); + } + } + + /// + /// Deserializes an object from a BSON Stream. + /// + /// The nominal type of the object. + /// The BSON Stream. + /// The configurator. + /// A deserialized value. + public TNominalType Deserialize(Stream stream, + Action configurator = null) + { + using (var bsonReader = new BsonBinaryReader(stream)) + { + return Deserialize(bsonReader, configurator); + } + } + + /// + /// Deserializes an object from a JSON string. + /// + /// The nominal type of the object. + /// The JSON string. + /// The configurator. + /// A deserialized value. + public TNominalType Deserialize(string json, + Action configurator = null) + { + using (var bsonReader = new JsonReader(json)) + { + return Deserialize(bsonReader, configurator); + } + } + + /// + /// Deserializes an object from a JSON TextReader. + /// + /// The nominal type of the object. + /// The JSON TextReader. + /// The configurator. + /// A deserialized value. + public TNominalType Deserialize(TextReader textReader, + Action configurator = null) + { + using (var bsonReader = new JsonReader(textReader)) + { + return Deserialize(bsonReader, configurator); + } + } + + /// + /// Deserializes an object from a BsonDocument. + /// + /// The BsonDocument. + /// The nominal type of the object. + /// The configurator. + /// A deserialized value. + public object Deserialize(BsonDocument document, Type nominalType, + Action configurator = null) + { + using (var bsonReader = new BsonDocumentReader(document)) + { + return Deserialize(bsonReader, nominalType, configurator); + } + } + + /// + /// Deserializes a value. + /// + /// The BsonReader. + /// The nominal type of the object. + /// The configurator. + /// A deserialized value. + public object Deserialize(IBsonReader bsonReader, Type nominalType, + Action configurator = null) + { + var serializer = LookupSerializer(nominalType); + var context = BsonDeserializationContext.CreateRoot(bsonReader, this, configurator); + return serializer.Deserialize(context); + } + + /// + /// Deserializes an object from a BSON byte array. + /// + /// The BSON byte array. + /// The nominal type of the object. + /// The configurator. + /// A deserialized value. + public object Deserialize(byte[] bytes, Type nominalType, + Action configurator = null) + { + using (var buffer = new ByteArrayBuffer(bytes, isReadOnly: true)) + using (var stream = new ByteBufferStream(buffer)) + { + return Deserialize(stream, nominalType, configurator); + } + } + + /// + /// Deserializes an object from a BSON Stream. + /// + /// The BSON Stream. + /// The nominal type of the object. + /// The configurator. + /// A deserialized value. + public object Deserialize(Stream stream, Type nominalType, + Action configurator = null) + { + using (var bsonReader = new BsonBinaryReader(stream)) + { + return Deserialize(bsonReader, nominalType, configurator); + } + } + + /// + /// Deserializes an object from a JSON string. + /// + /// The JSON string. + /// The nominal type of the object. + /// The configurator. + /// A deserialized value. + public object Deserialize(string json, Type nominalType, + Action configurator = null) + { + using (var bsonReader = new JsonReader(json)) + { + return Deserialize(bsonReader, nominalType, configurator); + } + } + + /// + /// Deserializes an object from a JSON TextReader. + /// + /// The JSON TextReader. + /// The nominal type of the object. + /// The configurator. + /// A deserialized value. + public object Deserialize(TextReader textReader, Type nominalType, + Action configurator = null) + { + using (var bsonReader = new JsonReader(textReader)) + { + return Deserialize(bsonReader, nominalType, configurator); + } + } + + public BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type) + { + // note: EnsureKnownTypesAreRegistered handles its own locking so call from outside any lock + EnsureKnownTypesAreRegistered(type); + + var discriminators = new List(); + + _configLock.EnterReadLock(); + try + { + foreach (var entry in _discriminators) + { + var discriminator = entry.Key; + var actualTypes = entry.Value; + + var matchingType = actualTypes.SingleOrDefault(t => t == type || t.IsSubclassOf(type)); + if (matchingType != null) + { + discriminators.Add(discriminator); + } + } + } + finally + { + _configLock.ExitReadLock(); + } + + return discriminators.OrderBy(x => x).ToArray(); + } + + public IDiscriminatorConvention GetOrRegisterDiscriminatorConvention(Type type, + IDiscriminatorConvention discriminatorConvention) + { + _configLock.EnterReadLock(); + try + { + if (_discriminatorConventions.TryGetValue(type, out var registeredDiscriminatorConvention)) + { + return registeredDiscriminatorConvention; + } + } + finally + { + _configLock.ExitReadLock(); + } + + _configLock.EnterWriteLock(); + try + { + if (_discriminatorConventions.TryGetValue(type, out var registeredDiscrimantorConvention)) + { + return registeredDiscrimantorConvention; + } + + RegisterDiscriminatorConvention(type, discriminatorConvention); + return discriminatorConvention; + } + finally + { + _configLock.ExitWriteLock(); + } + } + + public bool IsDiscriminatorConventionRegisteredAtThisLevel(Type type) + { + _configLock.EnterReadLock(); + try + { + return _discriminatorConventions.ContainsKey(type); + } + finally + { + _configLock.ExitReadLock(); + } + } + + /// + /// Returns whether the given type has any discriminators registered for any of its subclasses. + /// + /// A Type. + /// True if the type is discriminated. + public bool IsTypeDiscriminated(Type type) + { + var typeInfo = type.GetTypeInfo(); + return typeInfo.IsInterface || _discriminatedTypes.Contains(type); + } + + /// + /// Looks up the actual type of an object to be deserialized. + /// + /// The nominal type of the object. + /// The discriminator. + /// The actual type of the object. + public Type LookupActualType(Type nominalType, BsonValue discriminator) + { + if (discriminator == null) + { + return nominalType; + } + + // note: EnsureKnownTypesAreRegistered handles its own locking so call from outside any lock + EnsureKnownTypesAreRegistered(nominalType); + + _configLock.EnterReadLock(); + try + { + Type actualType = null; + + HashSet hashSet; + var nominalTypeInfo = nominalType.GetTypeInfo(); + if (_discriminators.TryGetValue(discriminator, out hashSet)) + { + foreach (var type in hashSet) + { + if (nominalTypeInfo.IsAssignableFrom(type)) + { + if (actualType == null) + { + actualType = type; + } + else + { + string message = string.Format("Ambiguous discriminator '{0}'.", discriminator); + throw new BsonSerializationException(message); + } + } + } + + // no need for additional checks, we found the right type + if (actualType != null) + { + return actualType; + } + } + + if (discriminator.IsString) + { + actualType = TypeNameDiscriminator.GetActualType(discriminator.AsString); // see if it's a Type name + } + + if (actualType == null) + { + string message = string.Format("Unknown discriminator value '{0}'.", discriminator); + throw new BsonSerializationException(message); + } + + if (!nominalTypeInfo.IsAssignableFrom(actualType)) + { + string message = string.Format( + "Actual type {0} is not assignable to expected type {1}.", + actualType.FullName, nominalType.FullName); + throw new BsonSerializationException(message); + } + + return actualType; + } + finally + { + _configLock.ExitReadLock(); + } + } + + /// + /// Looks up the discriminator convention for a type. + /// + /// The type. + /// A discriminator convention. + public IDiscriminatorConvention LookupDiscriminatorConvention(Type type) + { + _configLock.EnterReadLock(); + try + { + IDiscriminatorConvention convention; + if (_discriminatorConventions.TryGetValue(type, out convention)) + { + return convention; + } + } + finally + { + _configLock.ExitReadLock(); + } + + _configLock.EnterWriteLock(); + try + { + IDiscriminatorConvention convention; + if (!_discriminatorConventions.TryGetValue(type, out convention)) + { + var typeInfo = type.GetTypeInfo(); + if (type == typeof(object)) + { + // if there is no convention registered for object register the default one + convention = new ObjectDiscriminatorConvention("_t"); + RegisterDiscriminatorConvention(typeof(object), convention); + } + else if (typeInfo.IsInterface) + { + // TODO: should convention for interfaces be inherited from parent interfaces? + convention = LookupDiscriminatorConvention(typeof(object)); + RegisterDiscriminatorConvention(type, convention); + } + else + { + // inherit the discriminator convention from the closest parent (that isn't object) that has one + // otherwise default to the standard scalar convention + Type parentType = typeInfo.BaseType; + while (true) + { + if (parentType == typeof(object)) + { + convention = StandardDiscriminatorConvention.Scalar; + break; + } + + if (_discriminatorConventions.TryGetValue(parentType, out convention)) + { + break; + } + + parentType = parentType.GetTypeInfo().BaseType; + } + + // register this convention for all types between this and the parent type where we found the convention + var unregisteredType = type; + while (unregisteredType != parentType) + { + RegisterDiscriminatorConvention(unregisteredType, convention); + unregisteredType = unregisteredType.GetTypeInfo().BaseType; + } + } + } + + return convention; + } + finally + { + _configLock.ExitWriteLock(); + } + } + + /// + /// Looks up an IdGenerator. + /// + /// The Id type. + /// An IdGenerator for the Id type. + public IIdGenerator LookupIdGenerator(Type type) + { + _configLock.EnterReadLock(); + try + { + IIdGenerator idGenerator; + if (_idGenerators.TryGetValue(type, out idGenerator)) + { + return idGenerator; + } + } + finally + { + _configLock.ExitReadLock(); + } + + _configLock.EnterWriteLock(); + try + { + IIdGenerator idGenerator; + if (!_idGenerators.TryGetValue(type, out idGenerator)) + { + var typeInfo = type.GetTypeInfo(); + if (typeInfo.IsValueType && _useZeroIdChecker) + { + var iEquatableDefinition = typeof(IEquatable<>); + var iEquatableType = iEquatableDefinition.MakeGenericType(type); + if (iEquatableType.GetTypeInfo().IsAssignableFrom(type)) + { + var zeroIdCheckerDefinition = typeof(ZeroIdChecker<>); + var zeroIdCheckerType = zeroIdCheckerDefinition.MakeGenericType(type); + idGenerator = (IIdGenerator)Activator.CreateInstance(zeroIdCheckerType); + } + } + else if (_useNullIdChecker) + { + idGenerator = NullIdChecker.Instance; + } + else + { + idGenerator = null; + } + + _idGenerators[type] = idGenerator; // remember it even if it's null + } + + return idGenerator; + } + finally + { + _configLock.ExitWriteLock(); + } + } + + /// + /// Looks up a serializer for a Type. + /// + /// The type. + /// A serializer for type T. + public IBsonSerializer LookupSerializer() + { + return (IBsonSerializer)LookupSerializer(typeof(T)); + } + + /// + /// Looks up a serializer for a Type. + /// + /// The Type. + /// A serializer for the Type. + public IBsonSerializer LookupSerializer(Type type) + { + return _serializerRegistry.GetSerializer(type); + } + + /// + /// Registers the discriminator for a type. + /// + /// The type. + /// The discriminator. + public void RegisterDiscriminator(Type type, BsonValue discriminator) + { + var typeInfo = type.GetTypeInfo(); + if (typeInfo.IsInterface) + { + var message = string.Format("Discriminators can only be registered for classes, not for interface {0}.", + type.FullName); + throw new BsonSerializationException(message); + } + + _configLock.EnterWriteLock(); + try + { + HashSet hashSet; + if (!_discriminators.TryGetValue(discriminator, out hashSet)) + { + hashSet = new HashSet(); + _discriminators.Add(discriminator, hashSet); + } + + if (!hashSet.Contains(type)) + { + hashSet.Add(type); + + // mark all base types as discriminated (so we know that it's worth reading a discriminator) + for (var baseType = typeInfo.BaseType; baseType != null; baseType = baseType.GetTypeInfo().BaseType) + { + _discriminatedTypes.Add(baseType); + } + } + } + finally + { + _configLock.ExitWriteLock(); + } + } + + /// + /// Registers the discriminator convention for a type. + /// + /// Type type. + /// The discriminator convention. + public void RegisterDiscriminatorConvention(Type type, IDiscriminatorConvention convention) + { + _configLock.EnterWriteLock(); + try + { + if (!_discriminatorConventions.ContainsKey(type)) + { + _discriminatorConventions.Add(type, convention); + } + else + { + var message = string.Format("There is already a discriminator convention registered for type {0}.", + type.FullName); + throw new BsonSerializationException(message); + } + } + finally + { + _configLock.ExitWriteLock(); + } + } + + /// + /// Registers a generic serializer definition for a generic type. + /// + /// The generic type. + /// The generic serializer definition. + public void RegisterGenericSerializerDefinition( + Type genericTypeDefinition, + Type genericSerializerDefinition) + { + _typeMappingSerializationProvider.RegisterMapping(genericTypeDefinition, genericSerializerDefinition); + } + + /// + /// Registers an IdGenerator for an Id Type. + /// + /// The Id Type. + /// The IdGenerator for the Id Type. + public void RegisterIdGenerator(Type type, IIdGenerator idGenerator) + { + _configLock.EnterWriteLock(); + try + { + _idGenerators[type] = idGenerator; + } + finally + { + _configLock.ExitWriteLock(); + } + } + + /// + /// Registers a serialization provider. + /// + /// The serialization provider. + public void RegisterSerializationProvider(IBsonSerializationProvider provider) + { + _serializerRegistry.RegisterSerializationProvider(provider); + } + + /// + /// Registers a serializer for a type. + /// + /// The type. + /// The serializer. + public void RegisterSerializer(IBsonSerializer serializer) + { + RegisterSerializer(typeof(T), serializer); + } + + /// + /// Registers a serializer for a type. + /// + /// The type. + /// The serializer. + public void RegisterSerializer(Type type, IBsonSerializer serializer) + { + _serializerRegistry.RegisterSerializer(type, serializer); + } + + /// + /// Serializes a value. + /// + /// The nominal type of the object. + /// The BsonWriter. + /// The object. + /// The serialization context configurator. + /// The serialization args. + public void Serialize( + IBsonWriter bsonWriter, + TNominalType value, + Action configurator = null, + BsonSerializationArgs args = default(BsonSerializationArgs)) + { + args.SetOrValidateNominalType(typeof(TNominalType), ""); + var serializer = LookupSerializer(); + var context = BsonSerializationContext.CreateRoot(bsonWriter, this, configurator); + serializer.Serialize(context, args, value); + } + + /// + /// Serializes a value. + /// + /// The BsonWriter. + /// The nominal type of the object. + /// The object. + /// The serialization context configurator. + /// The serialization args. + public void Serialize( + IBsonWriter bsonWriter, + Type nominalType, + object value, + Action configurator = null, + BsonSerializationArgs args = default(BsonSerializationArgs)) + { + args.SetOrValidateNominalType(nominalType, "nominalType"); + var serializer = LookupSerializer(nominalType); + var context = BsonSerializationContext.CreateRoot(bsonWriter, this, configurator); + serializer.Serialize(context, args, value); + } + + public IBsonClassMapDomain BsonClassMap => _classMapDomain; + + public IConventionRegistryDomain ConventionRegistry => _conventionRegistryDomain; + + public IBsonDefaults BsonDefaults => _bsonDefaults; + + /// + /// Tries to register a serializer for a type. + /// + /// The serializer. + /// The type. + /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered. + public bool TryRegisterSerializer(Type type, IBsonSerializer serializer) + { + return _serializerRegistry.TryRegisterSerializer(type, serializer); + } + + /// + /// Tries to register a serializer for a type. + /// + /// The type. + /// The serializer. + /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered. + public bool TryRegisterSerializer(IBsonSerializer serializer) + { + return TryRegisterSerializer(typeof(T), serializer); + } + + // internal methods + public void EnsureKnownTypesAreRegistered(Type nominalType) + { + if (_typesWithRegisteredKnownTypes.ContainsKey(nominalType)) + { + return; + } + + _configLock.EnterWriteLock(); + try + { + if (!_typesWithRegisteredKnownTypes.ContainsKey(nominalType)) + { + // only call LookupClassMap for classes with a BsonKnownTypesAttribute + var hasKnownTypesAttribute = nominalType.GetTypeInfo() + .GetCustomAttributes(typeof(BsonKnownTypesAttribute), inherit: false).Any(); + if (hasKnownTypesAttribute) + { + // try and force a scan of the known types + LookupSerializer(nominalType); + } + + // NOTE: The nominalType MUST be added to __typesWithRegisteredKnownTypes after all registration + // work is done to ensure that other threads don't access a partially registered nominalType + // when performing the initial check above outside the __config lock. + _typesWithRegisteredKnownTypes[nominalType] = null; + } + } + finally + { + _configLock.ExitWriteLock(); + } + } + + public void Dispose() + { + _configLock.Dispose(); + } + + // private methods + private void CreateSerializerRegistry() + { + _serializerRegistry = new BsonSerializerRegistry(this); + _typeMappingSerializationProvider = new TypeMappingSerializationProvider(); + + // order matters. It's in reverse order of how they'll get consumed + _serializerRegistry.RegisterSerializationProvider(new BsonClassMapSerializationProvider(this)); + _serializerRegistry.RegisterSerializationProvider(new DiscriminatedInterfaceSerializationProvider()); + _serializerRegistry.RegisterSerializationProvider(new CollectionsSerializationProvider()); + _serializerRegistry.RegisterSerializationProvider(new PrimitiveSerializationProvider()); + _serializerRegistry.RegisterSerializationProvider(new AttributedSerializationProvider()); + _serializerRegistry.RegisterSerializationProvider(_typeMappingSerializationProvider); + _serializerRegistry.RegisterSerializationProvider(new BsonObjectModelSerializationProvider()); + } + + private void CreateSubDomains() + { + _classMapDomain = new BsonClassMapDomain(this); + _conventionRegistryDomain = new ConventionRegistryDomain(); + _bsonDefaults = new BsonDefaultsDomain(this); + } + + private void RegisterIdGenerators() + { + RegisterIdGenerator(typeof(BsonObjectId), BsonObjectIdGenerator.Instance); + RegisterIdGenerator(typeof(Guid), GuidGenerator.Instance); + RegisterIdGenerator(typeof(ObjectId), ObjectIdGenerator.Instance); + } + } +} \ No newline at end of file diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs b/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs index 01a5b9315de..f91a52ea4e2 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs @@ -118,7 +118,8 @@ public object DeserializeValue(BsonValue value) var tempDocument = new BsonDocument("value", value); using (var reader = new BsonDocumentReader(tempDocument)) { - var context = BsonDeserializationContext.CreateRoot(reader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(reader, BsonSerializer.DefaultSerializationDomain); reader.ReadStartDocument(); reader.ReadName("value"); var deserializedValue = _serializer.Deserialize(context); @@ -154,7 +155,8 @@ public BsonValue SerializeValue(object value) var tempDocument = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(tempDocument)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + //QUESTION Is it correct we only need a default domain here? + var context = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("value"); _serializer.Serialize(context, value); @@ -173,7 +175,8 @@ public BsonArray SerializeValues(IEnumerable values) var tempDocument = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(tempDocument)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + //QUESTION Is it correct we only need a default domain here? + var context = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("values"); bsonWriter.WriteStartArray(); diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationProviderBase.cs b/src/MongoDB.Bson/Serialization/BsonSerializationProviderBase.cs index b2ffb587183..de65cd9ad1d 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializationProviderBase.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializationProviderBase.cs @@ -23,15 +23,17 @@ namespace MongoDB.Bson.Serialization /// public abstract class BsonSerializationProviderBase : IRegistryAwareBsonSerializationProvider { + //DOMAIN-API We should remove this and use the overload that takes a serializer registry instead. /// public virtual IBsonSerializer GetSerializer(Type type) { - return GetSerializer(type, BsonSerializer.SerializerRegistry); + return GetSerializer(type, BsonSerializer.DefaultSerializationDomain.SerializerRegistry); } /// public abstract IBsonSerializer GetSerializer(Type type, IBsonSerializerRegistry serializerRegistry); + //DOMAIN-API We should remove this and use the overload that takes a serializer registry instead. /// /// Creates the serializer from a serializer type definition and type arguments. /// @@ -40,7 +42,7 @@ public virtual IBsonSerializer GetSerializer(Type type) /// A serializer. protected virtual IBsonSerializer CreateGenericSerializer(Type serializerTypeDefinition, params Type[] typeArguments) { - return CreateGenericSerializer(serializerTypeDefinition, typeArguments, BsonSerializer.SerializerRegistry); + return CreateGenericSerializer(serializerTypeDefinition, typeArguments, BsonSerializer.DefaultSerializationDomain.SerializerRegistry); } /// @@ -58,6 +60,7 @@ protected virtual IBsonSerializer CreateGenericSerializer(Type serializerTypeDef return CreateSerializer(serializerType, serializerRegistry); } + //DOMAIN-API We should remove this and use the overload that takes a serializer registry instead. /// /// Creates the serializer. /// diff --git a/src/MongoDB.Bson/Serialization/BsonSerializer.cs b/src/MongoDB.Bson/Serialization/BsonSerializer.cs index df21c6f6bb5..a862d05cb81 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializer.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializer.cs @@ -14,18 +14,10 @@ */ using System; -using System.Collections.Concurrent; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Reflection; using System.Threading; - -// don't add using statement for MongoDB.Bson.Serialization.Serializers to minimize dependencies on DefaultSerializer using MongoDB.Bson.IO; -using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Conventions; -using MongoDB.Bson.Serialization.IdGenerators; namespace MongoDB.Bson.Serialization { @@ -34,43 +26,29 @@ namespace MongoDB.Bson.Serialization /// public static class BsonSerializer { - // private static fields - private static ReaderWriterLockSlim __configLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - private static Dictionary __idGenerators = new Dictionary(); - private static Dictionary __discriminatorConventions = new Dictionary(); - private static Dictionary> __discriminators = new Dictionary>(); - private static ConcurrentDictionary __discriminatedTypes = new (); - private static BsonSerializerRegistry __serializerRegistry; - private static TypeMappingSerializationProvider __typeMappingSerializationProvider; - // ConcurrentDictionary is being used as a concurrent set of Type. The values will always be null. - private static ConcurrentDictionary __typesWithRegisteredKnownTypes = new ConcurrentDictionary(); - - private static bool __useNullIdChecker = false; - private static bool __useZeroIdChecker = false; + private static readonly IBsonSerializationDomain _serializationDomain; // static constructor static BsonSerializer() { - CreateSerializerRegistry(); - RegisterIdGenerators(); + _serializationDomain = new BsonSerializationDomain("MAIN"); } + internal static IBsonSerializationDomain DefaultSerializationDomain => _serializationDomain; + // public static properties /// /// Gets the serializer registry. /// - public static IBsonSerializerRegistry SerializerRegistry - { - get { return __serializerRegistry; } - } + public static IBsonSerializerRegistry SerializerRegistry => _serializationDomain.SerializerRegistry; /// /// Gets or sets whether to use the NullIdChecker on reference Id types that don't have an IdGenerator registered. /// public static bool UseNullIdChecker { - get { return __useNullIdChecker; } - set { __useNullIdChecker = value; } + get => _serializationDomain.UseNullIdChecker; + set => _serializationDomain.UseNullIdChecker = value; } /// @@ -78,17 +56,21 @@ public static bool UseNullIdChecker /// public static bool UseZeroIdChecker { - get { return __useZeroIdChecker; } - set { __useZeroIdChecker = value; } + get => _serializationDomain.UseZeroIdChecker; + set => _serializationDomain.UseZeroIdChecker = value; } // internal static properties - internal static ReaderWriterLockSlim ConfigLock - { - get { return __configLock; } - } + internal static ReaderWriterLockSlim ConfigLock => _serializationDomain.ConfigLock; // public static methods + + /// + /// //TODO + /// + /// + internal static IBsonSerializationDomain CreateSerializationDomain() => new BsonSerializationDomain(); + /// /// Deserializes an object from a BsonDocument. /// @@ -97,12 +79,7 @@ internal static ReaderWriterLockSlim ConfigLock /// The configurator. /// A deserialized value. public static TNominalType Deserialize(BsonDocument document, Action configurator = null) - { - using (var bsonReader = new BsonDocumentReader(document)) - { - return Deserialize(bsonReader, configurator); - } - } + => _serializationDomain.Deserialize(document, configurator); /// /// Deserializes a value. @@ -112,11 +89,7 @@ public static TNominalType Deserialize(BsonDocument document, Acti /// The configurator. /// A deserialized value. public static TNominalType Deserialize(IBsonReader bsonReader, Action configurator = null) - { - var serializer = LookupSerializer(); - var context = BsonDeserializationContext.CreateRoot(bsonReader, configurator); - return serializer.Deserialize(context); - } + => _serializationDomain.Deserialize(bsonReader, configurator); /// /// Deserializes an object from a BSON byte array. @@ -126,13 +99,7 @@ public static TNominalType Deserialize(IBsonReader bsonReader, Act /// The configurator. /// A deserialized value. public static TNominalType Deserialize(byte[] bytes, Action configurator = null) - { - using (var buffer = new ByteArrayBuffer(bytes, isReadOnly: true)) - using (var stream = new ByteBufferStream(buffer)) - { - return Deserialize(stream, configurator); - } - } + => _serializationDomain.Deserialize(bytes, configurator); /// /// Deserializes an object from a BSON Stream. @@ -142,12 +109,7 @@ public static TNominalType Deserialize(byte[] bytes, ActionThe configurator. /// A deserialized value. public static TNominalType Deserialize(Stream stream, Action configurator = null) - { - using (var bsonReader = new BsonBinaryReader(stream)) - { - return Deserialize(bsonReader, configurator); - } - } + => _serializationDomain.Deserialize(stream, configurator); /// /// Deserializes an object from a JSON string. @@ -157,12 +119,7 @@ public static TNominalType Deserialize(Stream stream, ActionThe configurator. /// A deserialized value. public static TNominalType Deserialize(string json, Action configurator = null) - { - using (var bsonReader = new JsonReader(json)) - { - return Deserialize(bsonReader, configurator); - } - } + => _serializationDomain.Deserialize(json, configurator); /// /// Deserializes an object from a JSON TextReader. @@ -172,12 +129,7 @@ public static TNominalType Deserialize(string json, ActionThe configurator. /// A deserialized value. public static TNominalType Deserialize(TextReader textReader, Action configurator = null) - { - using (var bsonReader = new JsonReader(textReader)) - { - return Deserialize(bsonReader, configurator); - } - } + => _serializationDomain.Deserialize(textReader, configurator); /// /// Deserializes an object from a BsonDocument. @@ -187,12 +139,7 @@ public static TNominalType Deserialize(TextReader textReader, Acti /// The configurator. /// A deserialized value. public static object Deserialize(BsonDocument document, Type nominalType, Action configurator = null) - { - using (var bsonReader = new BsonDocumentReader(document)) - { - return Deserialize(bsonReader, nominalType, configurator); - } - } + => _serializationDomain.Deserialize(document, nominalType, configurator); /// /// Deserializes a value. @@ -202,11 +149,7 @@ public static object Deserialize(BsonDocument document, Type nominalType, Action /// The configurator. /// A deserialized value. public static object Deserialize(IBsonReader bsonReader, Type nominalType, Action configurator = null) - { - var serializer = LookupSerializer(nominalType); - var context = BsonDeserializationContext.CreateRoot(bsonReader, configurator); - return serializer.Deserialize(context); - } + => _serializationDomain.Deserialize(bsonReader, nominalType, configurator); /// /// Deserializes an object from a BSON byte array. @@ -216,13 +159,7 @@ public static object Deserialize(IBsonReader bsonReader, Type nominalType, Actio /// The configurator. /// A deserialized value. public static object Deserialize(byte[] bytes, Type nominalType, Action configurator = null) - { - using (var buffer = new ByteArrayBuffer(bytes, isReadOnly: true)) - using (var stream = new ByteBufferStream(buffer)) - { - return Deserialize(stream, nominalType, configurator); - } - } + => _serializationDomain.Deserialize(bytes, nominalType, configurator); /// /// Deserializes an object from a BSON Stream. @@ -232,12 +169,7 @@ public static object Deserialize(byte[] bytes, Type nominalType, ActionThe configurator. /// A deserialized value. public static object Deserialize(Stream stream, Type nominalType, Action configurator = null) - { - using (var bsonReader = new BsonBinaryReader(stream)) - { - return Deserialize(bsonReader, nominalType, configurator); - } - } + => _serializationDomain.Deserialize(stream, nominalType, configurator); /// /// Deserializes an object from a JSON string. @@ -247,12 +179,7 @@ public static object Deserialize(Stream stream, Type nominalType, ActionThe configurator. /// A deserialized value. public static object Deserialize(string json, Type nominalType, Action configurator = null) - { - using (var bsonReader = new JsonReader(json)) - { - return Deserialize(bsonReader, nominalType, configurator); - } - } + => _serializationDomain.Deserialize(json, nominalType, configurator); /// /// Deserializes an object from a JSON TextReader. @@ -262,57 +189,13 @@ public static object Deserialize(string json, Type nominalType, ActionThe configurator. /// A deserialized value. public static object Deserialize(TextReader textReader, Type nominalType, Action configurator = null) - { - using (var bsonReader = new JsonReader(textReader)) - { - return Deserialize(bsonReader, nominalType, configurator); - } - } + => _serializationDomain.Deserialize(textReader, nominalType, configurator); internal static IDiscriminatorConvention GetOrRegisterDiscriminatorConvention(Type type, IDiscriminatorConvention discriminatorConvention) - { - __configLock.EnterReadLock(); - try - { - if (__discriminatorConventions.TryGetValue(type, out var registeredDiscriminatorConvention)) - { - return registeredDiscriminatorConvention; - } - } - finally - { - __configLock.ExitReadLock(); - } - - __configLock.EnterWriteLock(); - try - { - if (__discriminatorConventions.TryGetValue(type, out var registeredDiscrimantorConvention)) - { - return registeredDiscrimantorConvention; - } - - RegisterDiscriminatorConvention(type, discriminatorConvention); - return discriminatorConvention; - } - finally - { - __configLock.ExitWriteLock(); - } - } + => _serializationDomain.GetOrRegisterDiscriminatorConvention(type, discriminatorConvention); internal static bool IsDiscriminatorConventionRegisteredAtThisLevel(Type type) - { - __configLock.EnterReadLock(); - try - { - return __discriminatorConventions.ContainsKey(type); - } - finally - { - __configLock.ExitReadLock(); - } - } + => _serializationDomain.IsDiscriminatorConventionRegisteredAtThisLevel(type); /// /// Returns whether the given type has any discriminators registered for any of its subclasses. @@ -320,9 +203,7 @@ internal static bool IsDiscriminatorConventionRegisteredAtThisLevel(Type type) /// A Type. /// True if the type is discriminated. public static bool IsTypeDiscriminated(Type type) - { - return type.IsInterface || __discriminatedTypes.ContainsKey(type); - } + => _serializationDomain.IsTypeDiscriminated(type); /// /// Looks up the actual type of an object to be deserialized. @@ -331,73 +212,7 @@ public static bool IsTypeDiscriminated(Type type) /// The discriminator. /// The actual type of the object. public static Type LookupActualType(Type nominalType, BsonValue discriminator) - { - if (discriminator == null) - { - return nominalType; - } - - // note: EnsureKnownTypesAreRegistered handles its own locking so call from outside any lock - EnsureKnownTypesAreRegistered(nominalType); - - __configLock.EnterReadLock(); - try - { - Type actualType = null; - - HashSet hashSet; - var nominalTypeInfo = nominalType.GetTypeInfo(); - if (__discriminators.TryGetValue(discriminator, out hashSet)) - { - foreach (var type in hashSet) - { - if (nominalTypeInfo.IsAssignableFrom(type)) - { - if (actualType == null) - { - actualType = type; - } - else - { - string message = string.Format("Ambiguous discriminator '{0}'.", discriminator); - throw new BsonSerializationException(message); - } - } - } - - // no need for additional checks, we found the right type - if (actualType != null) - { - return actualType; - } - } - - if (discriminator.IsString) - { - actualType = TypeNameDiscriminator.GetActualType(discriminator.AsString); // see if it's a Type name - } - - if (actualType == null) - { - string message = string.Format("Unknown discriminator value '{0}'.", discriminator); - throw new BsonSerializationException(message); - } - - if (!nominalTypeInfo.IsAssignableFrom(actualType)) - { - string message = string.Format( - "Actual type {0} is not assignable to expected type {1}.", - actualType.FullName, nominalType.FullName); - throw new BsonSerializationException(message); - } - - return actualType; - } - finally - { - __configLock.ExitReadLock(); - } - } + => _serializationDomain.LookupActualType(nominalType, discriminator); /// /// Looks up the discriminator convention for a type. @@ -405,76 +220,7 @@ public static Type LookupActualType(Type nominalType, BsonValue discriminator) /// The type. /// A discriminator convention. public static IDiscriminatorConvention LookupDiscriminatorConvention(Type type) - { - __configLock.EnterReadLock(); - try - { - IDiscriminatorConvention convention; - if (__discriminatorConventions.TryGetValue(type, out convention)) - { - return convention; - } - } - finally - { - __configLock.ExitReadLock(); - } - - __configLock.EnterWriteLock(); - try - { - IDiscriminatorConvention convention; - if (!__discriminatorConventions.TryGetValue(type, out convention)) - { - var typeInfo = type.GetTypeInfo(); - if (type == typeof(object)) - { - // if there is no convention registered for object register the default one - convention = new ObjectDiscriminatorConvention("_t"); - RegisterDiscriminatorConvention(typeof(object), convention); - } - else if (typeInfo.IsInterface) - { - // TODO: should convention for interfaces be inherited from parent interfaces? - convention = LookupDiscriminatorConvention(typeof(object)); - RegisterDiscriminatorConvention(type, convention); - } - else - { - // inherit the discriminator convention from the closest parent (that isn't object) that has one - // otherwise default to the standard scalar convention - Type parentType = typeInfo.BaseType; - while (true) - { - if (parentType == typeof(object)) - { - convention = StandardDiscriminatorConvention.Scalar; - break; - } - if (__discriminatorConventions.TryGetValue(parentType, out convention)) - { - break; - } - parentType = parentType.GetTypeInfo().BaseType; - } - - // register this convention for all types between this and the parent type where we found the convention - var unregisteredType = type; - while (unregisteredType != parentType) - { - RegisterDiscriminatorConvention(unregisteredType, convention); - unregisteredType = unregisteredType.GetTypeInfo().BaseType; - } - } - } - - return convention; - } - finally - { - __configLock.ExitWriteLock(); - } - } + => _serializationDomain.LookupDiscriminatorConvention(type); /// /// Looks up an IdGenerator. @@ -482,78 +228,21 @@ public static IDiscriminatorConvention LookupDiscriminatorConvention(Type type) /// The Id type. /// An IdGenerator for the Id type. public static IIdGenerator LookupIdGenerator(Type type) - { - __configLock.EnterReadLock(); - try - { - IIdGenerator idGenerator; - if (__idGenerators.TryGetValue(type, out idGenerator)) - { - return idGenerator; - } - } - finally - { - __configLock.ExitReadLock(); - } - - __configLock.EnterWriteLock(); - try - { - IIdGenerator idGenerator; - if (!__idGenerators.TryGetValue(type, out idGenerator)) - { - var typeInfo = type.GetTypeInfo(); - if (typeInfo.IsValueType && __useZeroIdChecker) - { - var iEquatableDefinition = typeof(IEquatable<>); - var iEquatableType = iEquatableDefinition.MakeGenericType(type); - if (iEquatableType.GetTypeInfo().IsAssignableFrom(type)) - { - var zeroIdCheckerDefinition = typeof(ZeroIdChecker<>); - var zeroIdCheckerType = zeroIdCheckerDefinition.MakeGenericType(type); - idGenerator = (IIdGenerator)Activator.CreateInstance(zeroIdCheckerType); - } - } - else if (__useNullIdChecker) - { - idGenerator = NullIdChecker.Instance; - } - else - { - idGenerator = null; - } - - __idGenerators[type] = idGenerator; // remember it even if it's null - } - - return idGenerator; - } - finally - { - __configLock.ExitWriteLock(); - } - } + => _serializationDomain.LookupIdGenerator(type); /// /// Looks up a serializer for a Type. /// /// The type. /// A serializer for type T. - public static IBsonSerializer LookupSerializer() - { - return (IBsonSerializer)LookupSerializer(typeof(T)); - } + public static IBsonSerializer LookupSerializer() => _serializationDomain.LookupSerializer(); /// /// Looks up a serializer for a Type. /// /// The Type. /// A serializer for the Type. - public static IBsonSerializer LookupSerializer(Type type) - { - return __serializerRegistry.GetSerializer(type); - } + public static IBsonSerializer LookupSerializer(Type type) => _serializationDomain.LookupSerializer(type); /// /// Registers the discriminator for a type. @@ -561,41 +250,7 @@ public static IBsonSerializer LookupSerializer(Type type) /// The type. /// The discriminator. public static void RegisterDiscriminator(Type type, BsonValue discriminator) - { - var typeInfo = type.GetTypeInfo(); - if (typeInfo.IsInterface) - { - var message = string.Format("Discriminators can only be registered for classes, not for interface {0}.", type.FullName); - throw new BsonSerializationException(message); - } - - __configLock.EnterWriteLock(); - try - { - HashSet hashSet; - if (!__discriminators.TryGetValue(discriminator, out hashSet)) - { - hashSet = new HashSet(); - __discriminators.Add(discriminator, hashSet); - } - - if (!hashSet.Contains(type)) - { - hashSet.Add(type); - - // mark all base types as discriminated (so we know that it's worth reading a discriminator) - for (var baseType = typeInfo.BaseType; baseType != null; baseType = baseType.GetTypeInfo().BaseType) - { - // We expect that TryAdd will always return true, so no need to check the return value. - __discriminatedTypes.TryAdd(baseType, true); - } - } - } - finally - { - __configLock.ExitWriteLock(); - } - } + => _serializationDomain.RegisterDiscriminator(type, discriminator); /// /// Registers the discriminator convention for a type. @@ -603,37 +258,15 @@ public static void RegisterDiscriminator(Type type, BsonValue discriminator) /// Type type. /// The discriminator convention. public static void RegisterDiscriminatorConvention(Type type, IDiscriminatorConvention convention) - { - __configLock.EnterWriteLock(); - try - { - if (!__discriminatorConventions.ContainsKey(type)) - { - __discriminatorConventions.Add(type, convention); - } - else - { - var message = string.Format("There is already a discriminator convention registered for type {0}.", type.FullName); - throw new BsonSerializationException(message); - } - } - finally - { - __configLock.ExitWriteLock(); - } - } + => _serializationDomain.RegisterDiscriminatorConvention(type, convention); /// /// Registers a generic serializer definition for a generic type. /// /// The generic type. /// The generic serializer definition. - public static void RegisterGenericSerializerDefinition( - Type genericTypeDefinition, - Type genericSerializerDefinition) - { - __typeMappingSerializationProvider.RegisterMapping(genericTypeDefinition, genericSerializerDefinition); - } + public static void RegisterGenericSerializerDefinition(Type genericTypeDefinition, Type genericSerializerDefinition) + => _serializationDomain.RegisterGenericSerializerDefinition(genericTypeDefinition, genericSerializerDefinition); /// /// Registers an IdGenerator for an Id Type. @@ -641,26 +274,14 @@ public static void RegisterGenericSerializerDefinition( /// The Id Type. /// The IdGenerator for the Id Type. public static void RegisterIdGenerator(Type type, IIdGenerator idGenerator) - { - __configLock.EnterWriteLock(); - try - { - __idGenerators[type] = idGenerator; - } - finally - { - __configLock.ExitWriteLock(); - } - } + => _serializationDomain.RegisterIdGenerator(type, idGenerator); /// /// Registers a serialization provider. /// /// The serialization provider. public static void RegisterSerializationProvider(IBsonSerializationProvider provider) - { - __serializerRegistry.RegisterSerializationProvider(provider); - } + => _serializationDomain.RegisterSerializationProvider(provider); /// /// Registers a serializer for a type. @@ -668,9 +289,7 @@ public static void RegisterSerializationProvider(IBsonSerializationProvider prov /// The type. /// The serializer. public static void RegisterSerializer(IBsonSerializer serializer) - { - RegisterSerializer(typeof(T), serializer); - } + => _serializationDomain.RegisterSerializer(serializer); /// /// Registers a serializer for a type. @@ -678,9 +297,7 @@ public static void RegisterSerializer(IBsonSerializer serializer) /// The type. /// The serializer. public static void RegisterSerializer(Type type, IBsonSerializer serializer) - { - __serializerRegistry.RegisterSerializer(type, serializer); - } + => _serializationDomain.RegisterSerializer(type, serializer); /// /// Serializes a value. @@ -694,13 +311,8 @@ public static void Serialize( IBsonWriter bsonWriter, TNominalType value, Action configurator = null, - BsonSerializationArgs args = default(BsonSerializationArgs)) - { - args.SetOrValidateNominalType(typeof(TNominalType), ""); - var serializer = LookupSerializer(); - var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator); - serializer.Serialize(context, args, value); - } + BsonSerializationArgs args = default) + => _serializationDomain.Serialize(bsonWriter, value, configurator, args); /// /// Serializes a value. @@ -716,12 +328,7 @@ public static void Serialize( object value, Action configurator = null, BsonSerializationArgs args = default(BsonSerializationArgs)) - { - args.SetOrValidateNominalType(nominalType, "nominalType"); - var serializer = LookupSerializer(nominalType); - var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator); - serializer.Serialize(context, args, value); - } + => _serializationDomain.Serialize(bsonWriter, nominalType, value, configurator, args); /// /// Tries to register a serializer for a type. @@ -730,9 +337,7 @@ public static void Serialize( /// The type. /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered. public static bool TryRegisterSerializer(Type type, IBsonSerializer serializer) - { - return __serializerRegistry.TryRegisterSerializer(type, serializer); - } + => _serializationDomain.TryRegisterSerializer(type, serializer); /// /// Tries to register a serializer for a type. @@ -741,95 +346,13 @@ public static bool TryRegisterSerializer(Type type, IBsonSerializer serializer) /// The serializer. /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered. public static bool TryRegisterSerializer(IBsonSerializer serializer) - { - return TryRegisterSerializer(typeof(T), serializer); - } + => _serializationDomain.TryRegisterSerializer(serializer); // internal static methods internal static void EnsureKnownTypesAreRegistered(Type nominalType) - { - if (__typesWithRegisteredKnownTypes.ContainsKey(nominalType)) - { - return; - } - - __configLock.EnterWriteLock(); - try - { - if (!__typesWithRegisteredKnownTypes.ContainsKey(nominalType)) - { - // only call LookupClassMap for classes with a BsonKnownTypesAttribute - var hasKnownTypesAttribute = nominalType.GetTypeInfo().GetCustomAttributes(typeof(BsonKnownTypesAttribute), inherit: false).Any(); - if (hasKnownTypesAttribute) - { - // try and force a scan of the known types - LookupSerializer(nominalType); - } - - // NOTE: The nominalType MUST be added to __typesWithRegisteredKnownTypes after all registration - // work is done to ensure that other threads don't access a partially registered nominalType - // when performing the initial check above outside the __config lock. - __typesWithRegisteredKnownTypes[nominalType] = null; - } - } - finally - { - __configLock.ExitWriteLock(); - } - } + => _serializationDomain.EnsureKnownTypesAreRegistered(nominalType); - // internal static methods internal static BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type) - { - // note: EnsureKnownTypesAreRegistered handles its own locking so call from outside any lock - EnsureKnownTypesAreRegistered(type); - - var discriminators = new List(); - - __configLock.EnterReadLock(); - try - { - foreach (var entry in __discriminators) - { - var discriminator = entry.Key; - var actualTypes = entry.Value; - - var matchingType = actualTypes.SingleOrDefault(t => t == type || t.IsSubclassOf(type)); - if (matchingType != null) - { - discriminators.Add(discriminator); - } - } - } - finally - { - __configLock.ExitReadLock(); - } - - return discriminators.OrderBy(x => x).ToArray(); - } - - // private static methods - private static void CreateSerializerRegistry() - { - __serializerRegistry = new BsonSerializerRegistry(); - __typeMappingSerializationProvider = new TypeMappingSerializationProvider(); - - // order matters. It's in reverse order of how they'll get consumed - __serializerRegistry.RegisterSerializationProvider(new BsonClassMapSerializationProvider()); - __serializerRegistry.RegisterSerializationProvider(new DiscriminatedInterfaceSerializationProvider()); - __serializerRegistry.RegisterSerializationProvider(new CollectionsSerializationProvider()); - __serializerRegistry.RegisterSerializationProvider(new PrimitiveSerializationProvider()); - __serializerRegistry.RegisterSerializationProvider(new AttributedSerializationProvider()); - __serializerRegistry.RegisterSerializationProvider(__typeMappingSerializationProvider); - __serializerRegistry.RegisterSerializationProvider(new BsonObjectModelSerializationProvider()); - } - - private static void RegisterIdGenerators() - { - RegisterIdGenerator(typeof(BsonObjectId), BsonObjectIdGenerator.Instance); - RegisterIdGenerator(typeof(Guid), GuidGenerator.Instance); - RegisterIdGenerator(typeof(ObjectId), ObjectIdGenerator.Instance); - } + => _serializationDomain.GetDiscriminatorsForTypeAndSubTypes(type); } } diff --git a/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs b/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs index 429386f6019..e5b9aad1caa 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs @@ -33,14 +33,22 @@ public sealed class BsonSerializerRegistry : IBsonSerializerRegistry /// /// Initializes a new instance of the class. /// - public BsonSerializerRegistry() + public BsonSerializerRegistry(): + this(BsonSerializer.DefaultSerializationDomain) + { + } + + /// + /// //TODO + /// + /// + internal BsonSerializerRegistry(IBsonSerializationDomain serializationDomain) { _cache = new ConcurrentDictionary(); _serializationProviders = new ConcurrentStack(); _createSerializer = CreateSerializer; } - // public methods /// /// Gets the serializer for the specified . /// If none is already registered, the serialization providers will be used to create a serializer and it will be automatically registered. @@ -156,17 +164,14 @@ private IBsonSerializer CreateSerializer(Type type) { foreach (var serializationProvider in _serializationProviders) { - IBsonSerializer serializer; - - var registryAwareSerializationProvider = serializationProvider as IRegistryAwareBsonSerializationProvider; - if (registryAwareSerializationProvider != null) - { - serializer = registryAwareSerializationProvider.GetSerializer(type, this); - } - else + var serializer = serializationProvider switch { - serializer = serializationProvider.GetSerializer(type); - } + IDomainAwareBsonSerializationProvider domainAwareBsonSerializationProvider => + domainAwareBsonSerializationProvider.GetSerializerWithDomain(type), + IRegistryAwareBsonSerializationProvider registryAwareSerializationProvider => + registryAwareSerializationProvider.GetSerializer(type, this), + _ => serializationProvider.GetSerializer(type) + }; if (serializer != null) { diff --git a/src/MongoDB.Bson/Serialization/Conventions/AttributeConventionPack.cs b/src/MongoDB.Bson/Serialization/Conventions/AttributeConventionPack.cs index 77f0bc0cb78..b5646e41489 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/AttributeConventionPack.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/AttributeConventionPack.cs @@ -60,7 +60,7 @@ public IEnumerable Conventions } // nested classes - private class AttributeConvention : ConventionBase, IClassMapConvention, ICreatorMapConvention, IMemberMapConvention, IPostProcessingConvention + private class AttributeConvention : ConventionBase, IClassMapConvention, ICreatorMapConvention, IMemberMapConventionInternal, IPostProcessingConventionInternal { // public methods public void Apply(BsonClassMap classMap) @@ -87,7 +87,9 @@ public void Apply(BsonCreatorMap creatorMap) } } - public void Apply(BsonMemberMap memberMap) + public void Apply(BsonMemberMap memberMap) => Apply(memberMap, BsonSerializer.DefaultSerializationDomain); + + public void Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain) { var attributes = memberMap.MemberInfo.GetCustomAttributes(inherit: false).OfType(); var groupings = attributes.GroupBy(a => (a is BsonSerializerAttribute) ? 1 : 2); @@ -100,7 +102,9 @@ public void Apply(BsonMemberMap memberMap) } } - public void PostProcess(BsonClassMap classMap) + public void PostProcess(BsonClassMap classMap) => PostProcess(classMap, BsonSerializer.DefaultSerializationDomain); + + public void PostProcess(BsonClassMap classMap, IBsonSerializationDomain domain) { foreach (var attribute in classMap.ClassType.GetTypeInfo().GetCustomAttributes(inherit: false).OfType()) { diff --git a/src/MongoDB.Bson/Serialization/Conventions/CamelCaseElementNameConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/CamelCaseElementNameConvention.cs index dd249c11359..9154e353deb 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/CamelCaseElementNameConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/CamelCaseElementNameConvention.cs @@ -14,21 +14,20 @@ */ using System; -using System.Reflection; namespace MongoDB.Bson.Serialization.Conventions { /// /// A convention that sets the element name the same as the member name with the first character lower cased. /// - public class CamelCaseElementNameConvention : ConventionBase, IMemberMapConvention + public class CamelCaseElementNameConvention : ConventionBase, IMemberMapConventionInternal { // public methods - /// - /// Applies a modification to the member map. - /// - /// The member map. - public void Apply(BsonMemberMap memberMap) + /// + public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain) { string name = memberMap.MemberName; name = GetElementName(name); diff --git a/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistry.cs b/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistry.cs index 217a7b69d86..d389df271ef 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistry.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistry.cs @@ -14,7 +14,6 @@ */ using System; -using System.Collections.Generic; namespace MongoDB.Bson.Serialization.Conventions { @@ -23,60 +22,14 @@ namespace MongoDB.Bson.Serialization.Conventions /// public static class ConventionRegistry { - // private static fields - private readonly static List __conventionPacks = new List(); - private readonly static object __lock = new object(); - - // static constructors - static ConventionRegistry() - { - Register("__defaults__", DefaultConventionPack.Instance, t => true); - Register("__attributes__", AttributeConventionPack.Instance, t => true); - } - // public static methods /// /// Looks up the effective set of conventions that apply to a type. /// /// The type. /// The conventions for that type. - public static IConventionPack Lookup(Type type) - { - if (type == null) - { - throw new ArgumentNullException("type"); - } - - lock (__lock) - { - var pack = new ConventionPack(); - - // append any attribute packs (usually just one) at the end so attributes are processed last - var attributePacks = new List(); - foreach (var container in __conventionPacks) - { - if (container.Filter(type)) - { - - if (container.Name == "__attributes__") - { - attributePacks.Add(container.Pack); - } - else - { - pack.Append(container.Pack); - } - } - } - - foreach (var attributePack in attributePacks) - { - pack.Append(attributePack); - } - - return pack; - } - } + public static IConventionPack Lookup(Type type) => + BsonSerializer.DefaultSerializationDomain.ConventionRegistry.Lookup(type); /// /// Registers the conventions. @@ -84,33 +37,8 @@ public static IConventionPack Lookup(Type type) /// The name. /// The conventions. /// The filter. - public static void Register(string name, IConventionPack conventions, Func filter) - { - if (name == null) - { - throw new ArgumentNullException("name"); - } - if (conventions == null) - { - throw new ArgumentNullException("conventions"); - } - if (filter == null) - { - throw new ArgumentNullException("filter"); - } - - lock (__lock) - { - var container = new ConventionPackContainer - { - Filter = filter, - Name = name, - Pack = conventions - }; - - __conventionPacks.Add(container); - } - } + public static void Register(string name, IConventionPack conventions, Func filter) => + BsonSerializer.DefaultSerializationDomain.ConventionRegistry.Register(name, conventions, filter); /// /// Removes the conventions specified by the given name. @@ -119,25 +47,7 @@ public static void Register(string name, IConventionPack conventions, FuncRemoving a convention allows the removal of the special __defaults__ conventions /// and the __attributes__ conventions for those who want to completely customize the /// experience. - public static void Remove(string name) - { - if (name == null) - { - throw new ArgumentNullException("name"); - } - - lock (__lock) - { - __conventionPacks.RemoveAll(x => x.Name == name); - } - } - - // private class - private class ConventionPackContainer - { - public Func Filter; - public string Name; - public IConventionPack Pack; - } + public static void Remove(string name) => + BsonSerializer.DefaultSerializationDomain.ConventionRegistry.Remove(name); } } diff --git a/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistryDomain.cs b/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistryDomain.cs new file mode 100644 index 00000000000..fec96b02e31 --- /dev/null +++ b/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistryDomain.cs @@ -0,0 +1,141 @@ +/* Copyright 2010-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; + +namespace MongoDB.Bson.Serialization.Conventions +{ + internal class ConventionRegistryDomain : IConventionRegistryDomain + { + private readonly List _conventionPacks = []; + private readonly object _lock = new(); + + // constructors + internal ConventionRegistryDomain() + { + Register("__defaults__", DefaultConventionPack.Instance, t => true); + Register("__attributes__", AttributeConventionPack.Instance, t => true); + } + + // public static methods + /// + /// Looks up the effective set of conventions that apply to a type. + /// + /// The type. + /// The conventions for that type. + public IConventionPack Lookup(Type type) + { + if (type == null) + { + throw new ArgumentNullException("type"); + } + + lock (_lock) + { + var pack = new ConventionPack(); + + // append any attribute packs (usually just one) at the end so attributes are processed last + var attributePacks = new List(); + foreach (var container in _conventionPacks) + { + if (container.Filter(type)) + { + + if (container.Name == "__attributes__") + { + attributePacks.Add(container.Pack); + } + else + { + pack.Append(container.Pack); + } + } + } + + foreach (var attributePack in attributePacks) + { + pack.Append(attributePack); + } + + return pack; + } + } + + /// + /// Registers the conventions. + /// + /// The name. + /// The conventions. + /// The filter. + public void Register(string name, IConventionPack conventions, Func filter) + { + if (name == null) + { + throw new ArgumentNullException("name"); + } + + if (conventions == null) + { + throw new ArgumentNullException("conventions"); + } + + if (filter == null) + { + throw new ArgumentNullException("filter"); + } + + lock (_lock) + { + var container = new ConventionPackContainer + { + Filter = filter, + Name = name, + Pack = conventions + }; + + _conventionPacks.Add(container); + } + } + + /// + /// Removes the conventions specified by the given name. + /// + /// The name. + /// Removing a convention allows the removal of the special __defaults__ conventions + /// and the __attributes__ conventions for those who want to completely customize the + /// experience. + public void Remove(string name) + { + if (name == null) + { + throw new ArgumentNullException("name"); + } + + lock (_lock) + { + _conventionPacks.RemoveAll(x => x.Name == name); + } + } + + // private class + private class ConventionPackContainer + { + public Func Filter; + public string Name; + public IConventionPack Pack; + } + } +} \ No newline at end of file diff --git a/src/MongoDB.Bson/Serialization/Conventions/ConventionRunner.cs b/src/MongoDB.Bson/Serialization/Conventions/ConventionRunner.cs index 091be418810..8b8431bae16 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/ConventionRunner.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/ConventionRunner.cs @@ -47,7 +47,9 @@ public ConventionRunner(IConventionPack conventions) /// Applies a modification to the class map. /// /// The class map. - public void Apply(BsonClassMap classMap) + public void Apply(BsonClassMap classMap) => Apply(classMap, BsonSerializer.DefaultSerializationDomain); + + internal void Apply(BsonClassMap classMap, IBsonSerializationDomain serializationDomain) { foreach (var convention in _conventions.OfType()) { @@ -58,7 +60,7 @@ public void Apply(BsonClassMap classMap) { foreach (var memberMap in classMap.DeclaredMemberMaps) { - convention.Apply(memberMap); + convention.ApplyInternal(memberMap, serializationDomain); } } @@ -72,7 +74,7 @@ public void Apply(BsonClassMap classMap) foreach (var convention in _conventions.OfType()) { - convention.PostProcess(classMap); + convention.PostProcessInternal(classMap, serializationDomain); } } } diff --git a/src/MongoDB.Bson/Serialization/Conventions/DelegateMemberMapConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/DelegateMemberMapConvention.cs index 80cafe70046..f2c90e32fe5 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/DelegateMemberMapConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/DelegateMemberMapConvention.cs @@ -20,7 +20,7 @@ namespace MongoDB.Bson.Serialization.Conventions /// /// A member map convention that wraps a delegate. /// - public class DelegateMemberMapConvention : ConventionBase, IMemberMapConvention + public class DelegateMemberMapConvention : ConventionBase, IMemberMapConventionInternal { // private fields private readonly Action _action; @@ -46,7 +46,10 @@ public DelegateMemberMapConvention(string name, Action action) /// Applies a modification to the member map. /// /// The member map. - public void Apply(BsonMemberMap memberMap) + public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain) { _action(memberMap); } diff --git a/src/MongoDB.Bson/Serialization/Conventions/DelegatePostProcessingConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/DelegatePostProcessingConvention.cs index 8c535f842f0..d8e6c1408f8 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/DelegatePostProcessingConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/DelegatePostProcessingConvention.cs @@ -20,7 +20,7 @@ namespace MongoDB.Bson.Serialization.Conventions /// /// A post processing convention that wraps a delegate. /// - public class DelegatePostProcessingConvention : ConventionBase, IPostProcessingConvention + public class DelegatePostProcessingConvention : ConventionBase, IPostProcessingConventionInternal { // private fields private readonly Action _action; @@ -46,7 +46,10 @@ public DelegatePostProcessingConvention(string name, Action action /// Applies a post processing modification to the class map. /// /// The class map. - public void PostProcess(BsonClassMap classMap) + public void PostProcess(BsonClassMap classMap) => (this as IPostProcessingConventionInternal).PostProcess(classMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IPostProcessingConventionInternal.PostProcess(BsonClassMap classMap, IBsonSerializationDomain domain) { _action(classMap); } diff --git a/src/MongoDB.Bson/Serialization/Conventions/EnumRepresentationConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/EnumRepresentationConvention.cs index 4f5274a0664..b0c6bfabd5a 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/EnumRepresentationConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/EnumRepresentationConvention.cs @@ -21,7 +21,7 @@ namespace MongoDB.Bson.Serialization.Conventions /// /// A convention that allows you to set the Enum serialization representation /// - public class EnumRepresentationConvention : ConventionBase, IMemberMapConvention + public class EnumRepresentationConvention : ConventionBase, IMemberMapConventionInternal { // private fields private readonly BsonType _representation; @@ -66,7 +66,10 @@ public EnumRepresentationConvention(BsonType representation, bool topLevelOnly) /// Applies a modification to the member map. /// /// The member map. - public void Apply(BsonMemberMap memberMap) + public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain) { var memberType = memberMap.MemberType; diff --git a/src/MongoDB.Bson/Serialization/Conventions/HierarchicalDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/HierarchicalDiscriminatorConvention.cs index beebf06230e..85751240e74 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/HierarchicalDiscriminatorConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/HierarchicalDiscriminatorConvention.cs @@ -16,13 +16,14 @@ using System; using System.Collections.Generic; using System.Linq; +using MongoDB.Bson.IO; namespace MongoDB.Bson.Serialization.Conventions { /// /// Represents a discriminator convention where the discriminator is an array of all the discriminators provided by the class maps of the root class down to the actual type. /// - public class HierarchicalDiscriminatorConvention : StandardDiscriminatorConvention, IHierarchicalDiscriminatorConvention + public class HierarchicalDiscriminatorConvention : StandardDiscriminatorConvention, IHierarchicalDiscriminatorConvention, IDiscriminatorConventionInternal { // constructors /// @@ -34,6 +35,11 @@ public HierarchicalDiscriminatorConvention(string elementName) { } + Type IDiscriminatorConventionInternal.GetActualType(IBsonReader bsonReader, Type nominalType, IBsonSerializationDomain domain) + { + return base.GetActualType(bsonReader, nominalType, domain); + } + // public methods /// /// Gets the discriminator value for an actual type. @@ -41,10 +47,14 @@ public HierarchicalDiscriminatorConvention(string elementName) /// The nominal type. /// The actual type. /// The discriminator value. - public override BsonValue GetDiscriminator(Type nominalType, Type actualType) + public override BsonValue GetDiscriminator(Type nominalType, Type actualType) => + (this as IDiscriminatorConventionInternal).GetDiscriminator(nominalType, actualType, BsonSerializer.DefaultSerializationDomain); + + /// + BsonValue IDiscriminatorConventionInternal.GetDiscriminator(Type nominalType, Type actualType, IBsonSerializationDomain domain) { // TODO: this isn't quite right, not all classes are serialized using a class map serializer - var classMap = BsonClassMap.LookupClassMap(actualType); + var classMap = domain.BsonClassMap.LookupClassMap(actualType); if (actualType != nominalType || classMap.DiscriminatorIsRequired || classMap.HasRootClass) { if (classMap.HasRootClass && !classMap.IsRootClass) diff --git a/src/MongoDB.Bson/Serialization/Conventions/IConventionRegistryDomain.cs b/src/MongoDB.Bson/Serialization/Conventions/IConventionRegistryDomain.cs new file mode 100644 index 00000000000..b2720052419 --- /dev/null +++ b/src/MongoDB.Bson/Serialization/Conventions/IConventionRegistryDomain.cs @@ -0,0 +1,28 @@ +using System; + +namespace MongoDB.Bson.Serialization.Conventions +{ + internal interface IConventionRegistryDomain + { + /// + /// //TODO + /// + /// + /// + IConventionPack Lookup(Type type); + + /// + /// //TODO + /// + /// + /// + /// + void Register(string name, IConventionPack conventions, Func filter); + + /// + /// //TODO + /// + /// + void Remove(string name); + } +} \ No newline at end of file diff --git a/src/MongoDB.Bson/Serialization/Conventions/IDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/IDiscriminatorConvention.cs index 242d0b557b2..cfd44ef8936 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/IDiscriminatorConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/IDiscriminatorConvention.cs @@ -44,4 +44,26 @@ public interface IDiscriminatorConvention /// The discriminator value. BsonValue GetDiscriminator(Type nominalType, Type actualType); } + + //DOMAIN-API These methods should be substitute the above methods in the interface + internal interface IDiscriminatorConventionInternal : IDiscriminatorConvention + { + /// + /// //TODO + /// + /// + /// + /// + /// + Type GetActualType(IBsonReader bsonReader, Type nominalType, IBsonSerializationDomain domain); + + /// + /// //TODO + /// + /// + /// + /// + /// + BsonValue GetDiscriminator(Type nominalType, Type actualType, IBsonSerializationDomain domain); + } } diff --git a/src/MongoDB.Bson/Serialization/Conventions/IMemberMapConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/IMemberMapConvention.cs index b05f40d64ad..dfb138ea4d2 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/IMemberMapConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/IMemberMapConvention.cs @@ -26,4 +26,14 @@ public interface IMemberMapConvention : IConvention /// The member map. void Apply(BsonMemberMap memberMap); } + + internal interface IMemberMapConventionInternal : IMemberMapConvention + { + /// + /// //TODO + /// + /// + /// + void Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain); + } } diff --git a/src/MongoDB.Bson/Serialization/Conventions/IPostProcessingConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/IPostProcessingConvention.cs index ddb7a095df5..ea43f926c4a 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/IPostProcessingConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/IPostProcessingConvention.cs @@ -26,4 +26,14 @@ public interface IPostProcessingConvention : IConvention /// The class map. void PostProcess(BsonClassMap classMap); } + + internal interface IPostProcessingConventionInternal : IPostProcessingConvention + { + /// + /// //TODO + /// + /// + /// + void PostProcess(BsonClassMap classMap, IBsonSerializationDomain domain); + } } diff --git a/src/MongoDB.Bson/Serialization/Conventions/IScalarDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/IScalarDiscriminatorConvention.cs index 82c2e794626..4d09b977b01 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/IScalarDiscriminatorConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/IScalarDiscriminatorConvention.cs @@ -29,4 +29,9 @@ public interface IScalarDiscriminatorConvention : IDiscriminatorConvention /// The discriminators. BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type); } + + internal interface IScalarDiscriminatorConventionInternal : IScalarDiscriminatorConvention + { + BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type, IBsonSerializationDomain serializationDomain); + } } diff --git a/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfDefaultConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfDefaultConvention.cs index aede146fe8c..a7d855cf2e0 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfDefaultConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfDefaultConvention.cs @@ -18,7 +18,7 @@ namespace MongoDB.Bson.Serialization.Conventions /// /// A convention that sets whether to ignore default values during serialization. /// - public class IgnoreIfDefaultConvention : ConventionBase, IMemberMapConvention + public class IgnoreIfDefaultConvention : ConventionBase, IMemberMapConventionInternal { // private fields private bool _ignoreIfDefault; @@ -37,7 +37,10 @@ public IgnoreIfDefaultConvention(bool ignoreIfDefault) /// Applies a modification to the member map. /// /// The member map. - public void Apply(BsonMemberMap memberMap) + public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain) { memberMap.SetIgnoreIfDefault(_ignoreIfDefault); } diff --git a/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfNullConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfNullConvention.cs index c99f694fe81..cebcd8dc86d 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfNullConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfNullConvention.cs @@ -18,7 +18,7 @@ namespace MongoDB.Bson.Serialization.Conventions /// /// A convention that sets whether to ignore nulls during serialization. /// - public class IgnoreIfNullConvention : ConventionBase, IMemberMapConvention + public class IgnoreIfNullConvention : ConventionBase, IMemberMapConventionInternal { // private fields private bool _ignoreIfNull; @@ -37,7 +37,10 @@ public IgnoreIfNullConvention(bool ignoreIfNull) /// Applies a modification to the member map. /// /// The member map. - public void Apply(BsonMemberMap memberMap) + public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain) { memberMap.SetIgnoreIfNull(_ignoreIfNull); } diff --git a/src/MongoDB.Bson/Serialization/Conventions/LookupIdGeneratorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/LookupIdGeneratorConvention.cs index 81f31d14444..19eb4ee2058 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/LookupIdGeneratorConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/LookupIdGeneratorConvention.cs @@ -13,29 +13,26 @@ * limitations under the License. */ -using System; -using System.Reflection; - namespace MongoDB.Bson.Serialization.Conventions { /// /// A convention that looks up an id generator for the id member. /// - public class LookupIdGeneratorConvention : ConventionBase, IPostProcessingConvention + public class LookupIdGeneratorConvention : ConventionBase, IPostProcessingConventionInternal { - // public methods - /// - /// Applies a post processing modification to the class map. - /// - /// The class map. - public void PostProcess(BsonClassMap classMap) + /// + public void PostProcess(BsonClassMap classMap) => (this as IPostProcessingConventionInternal).PostProcess(classMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IPostProcessingConventionInternal.PostProcess(BsonClassMap classMap, IBsonSerializationDomain domain) { var idMemberMap = classMap.IdMemberMap; if (idMemberMap != null) { if (idMemberMap.IdGenerator == null) { - var idGenerator = BsonSerializer.LookupIdGenerator(idMemberMap.MemberType); + //or we pass the domain to the BsonClassMap. The first probably makes more sense, but it's messier. + var idGenerator = domain.LookupIdGenerator(idMemberMap.MemberType); if (idGenerator != null) { idMemberMap.SetIdGenerator(idGenerator); diff --git a/src/MongoDB.Bson/Serialization/Conventions/MemberDefaultValueConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/MemberDefaultValueConvention.cs index 51ff212c300..29076be1b2c 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/MemberDefaultValueConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/MemberDefaultValueConvention.cs @@ -20,7 +20,7 @@ namespace MongoDB.Bson.Serialization.Conventions /// /// A convention that sets the default value for members of a given type. /// - public class MemberDefaultValueConvention : ConventionBase, IMemberMapConvention + public class MemberDefaultValueConvention : ConventionBase, IMemberMapConventionInternal { // private fields private readonly Type _type; @@ -43,7 +43,10 @@ public MemberDefaultValueConvention(Type type, object defaultValue) /// Applies a modification to the member map. /// /// The member map. - public void Apply(BsonMemberMap memberMap) + public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain) { if (memberMap.MemberType == _type) { diff --git a/src/MongoDB.Bson/Serialization/Conventions/MemberNameElementNameConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/MemberNameElementNameConvention.cs index bdee9118a15..daa0a1314a9 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/MemberNameElementNameConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/MemberNameElementNameConvention.cs @@ -13,22 +13,22 @@ * limitations under the License. */ -using System; -using System.Reflection; - namespace MongoDB.Bson.Serialization.Conventions { /// /// A convention that sets the element name the same as the member name. /// - public class MemberNameElementNameConvention : ConventionBase, IMemberMapConvention + public class MemberNameElementNameConvention : ConventionBase, IMemberMapConventionInternal { // public methods /// /// Applies a modification to the member map. /// /// The member map. - public void Apply(BsonMemberMap memberMap) + public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain) { memberMap.SetElementName(memberMap.MemberName); } diff --git a/src/MongoDB.Bson/Serialization/Conventions/NoIdMemberConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/NoIdMemberConvention.cs index 82d295cb42f..4a4b4a829ff 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/NoIdMemberConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/NoIdMemberConvention.cs @@ -13,24 +13,22 @@ * limitations under the License. */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - namespace MongoDB.Bson.Serialization.Conventions { /// /// A convention that sets a class's IdMember to null. /// - public class NoIdMemberConvention : ConventionBase, IPostProcessingConvention + public class NoIdMemberConvention : ConventionBase, IPostProcessingConventionInternal { // public methods /// /// Applies a post processing modification to the class map. /// /// The class map. - public void PostProcess(BsonClassMap classMap) + public void PostProcess(BsonClassMap classMap) => (this as IPostProcessingConventionInternal).PostProcess(classMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IPostProcessingConventionInternal.PostProcess(BsonClassMap classMap, IBsonSerializationDomain domain) { classMap.SetIdMember(null); } diff --git a/src/MongoDB.Bson/Serialization/Conventions/ObjectDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/ObjectDiscriminatorConvention.cs index 9a0a7683368..f732a04ea3f 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/ObjectDiscriminatorConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/ObjectDiscriminatorConvention.cs @@ -86,7 +86,11 @@ obj is ObjectDiscriminatorConvention other && /// The reader. /// The nominal type. /// The actual type. - public Type GetActualType(IBsonReader bsonReader, Type nominalType) + public Type GetActualType(IBsonReader bsonReader, Type nominalType) => + GetActualType(bsonReader, nominalType, BsonSerializer.DefaultSerializationDomain); + + /// + internal Type GetActualType(IBsonReader bsonReader, Type nominalType, IBsonSerializationDomain domain) { // the BsonReader is sitting at the value whose actual type needs to be found var bsonType = bsonReader.GetCurrentBsonType(); @@ -129,13 +133,13 @@ public Type GetActualType(IBsonReader bsonReader, Type nominalType) var actualType = nominalType; if (bsonReader.FindElement(_elementName)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + var context = BsonDeserializationContext.CreateRoot(bsonReader, domain); var discriminator = BsonValueSerializer.Instance.Deserialize(context); if (discriminator.IsBsonArray) { discriminator = discriminator.AsBsonArray.Last(); // last item is leaf class discriminator } - actualType = BsonSerializer.LookupActualType(nominalType, discriminator); + actualType = domain.LookupActualType(nominalType, discriminator); } bsonReader.ReturnToBookmark(bookmark); return actualType; diff --git a/src/MongoDB.Bson/Serialization/Conventions/ObjectSerializerAllowedTypesConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/ObjectSerializerAllowedTypesConvention.cs index f4860f81c9f..5da3436d025 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/ObjectSerializerAllowedTypesConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/ObjectSerializerAllowedTypesConvention.cs @@ -25,7 +25,7 @@ namespace MongoDB.Bson.Serialization.Conventions /// /// A convention that allows to set the types that can be safely serialized and deserialized with the . /// - public sealed class ObjectSerializerAllowedTypesConvention : ConventionBase, IMemberMapConvention + public sealed class ObjectSerializerAllowedTypesConvention : ConventionBase, IMemberMapConventionInternal { // static properties @@ -151,7 +151,10 @@ public bool AllowDefaultFrameworkTypes /// Applies a modification to the member map. /// /// The member map. - public void Apply(BsonMemberMap memberMap) + public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain) { var memberType = memberMap.MemberType; diff --git a/src/MongoDB.Bson/Serialization/Conventions/ResetMemberMapsConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/ResetMemberMapsConvention.cs index ef21036c3e3..959aecc0900 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/ResetMemberMapsConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/ResetMemberMapsConvention.cs @@ -18,14 +18,17 @@ namespace MongoDB.Bson.Serialization.Conventions /// /// A convention that resets class members (resetting any changes that earlier conventions may have applied). /// - public class ResetMemberMapsConvention : ConventionBase, IMemberMapConvention + public class ResetMemberMapsConvention : ConventionBase, IMemberMapConventionInternal { // public methods /// /// Applies a modification to the member map. /// /// The member map. - public void Apply(BsonMemberMap memberMap) + public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain) { memberMap.Reset(); } diff --git a/src/MongoDB.Bson/Serialization/Conventions/ScalarDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/ScalarDiscriminatorConvention.cs index 521aff9b1f7..d9259824a24 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/ScalarDiscriminatorConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/ScalarDiscriminatorConvention.cs @@ -15,13 +15,14 @@ using System; using System.Collections.Concurrent; +using MongoDB.Bson.IO; namespace MongoDB.Bson.Serialization.Conventions { /// /// Represents a discriminator convention where the discriminator is provided by the class map of the actual type. /// - public class ScalarDiscriminatorConvention : StandardDiscriminatorConvention, IScalarDiscriminatorConvention + public class ScalarDiscriminatorConvention : StandardDiscriminatorConvention, IScalarDiscriminatorConventionInternal, IDiscriminatorConventionInternal { private readonly ConcurrentDictionary _cachedTypeAndSubTypeDiscriminators = new(); @@ -35,6 +36,11 @@ public ScalarDiscriminatorConvention(string elementName) { } + Type IDiscriminatorConventionInternal.GetActualType(IBsonReader bsonReader, Type nominalType, IBsonSerializationDomain domain) + { + return base.GetActualType(bsonReader, nominalType, domain); + } + // public methods /// /// Gets the discriminator value for an actual type. @@ -42,10 +48,14 @@ public ScalarDiscriminatorConvention(string elementName) /// The nominal type. /// The actual type. /// The discriminator value. - public override BsonValue GetDiscriminator(Type nominalType, Type actualType) + public override BsonValue GetDiscriminator(Type nominalType, Type actualType) => + (this as IDiscriminatorConventionInternal).GetDiscriminator(nominalType, actualType, BsonSerializer.DefaultSerializationDomain); + + /// + BsonValue IDiscriminatorConventionInternal.GetDiscriminator(Type nominalType, Type actualType, IBsonSerializationDomain domain) { // TODO: this isn't quite right, not all classes are serialized using a class map serializer - var classMap = BsonClassMap.LookupClassMap(actualType); + var classMap = domain.BsonClassMap.LookupClassMap(actualType); if (actualType != nominalType || classMap.DiscriminatorIsRequired) { return classMap.Discriminator; @@ -57,9 +67,12 @@ public override BsonValue GetDiscriminator(Type nominalType, Type actualType) } /// - public BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type) + public BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type) => + (this as IScalarDiscriminatorConventionInternal).GetDiscriminatorsForTypeAndSubTypes(type, BsonSerializer.DefaultSerializationDomain); + + BsonValue[] IScalarDiscriminatorConventionInternal.GetDiscriminatorsForTypeAndSubTypes(Type type, IBsonSerializationDomain serializationDomain) { - return _cachedTypeAndSubTypeDiscriminators.GetOrAdd(type, BsonSerializer.GetDiscriminatorsForTypeAndSubTypes); + return _cachedTypeAndSubTypeDiscriminators.GetOrAdd(type, serializationDomain.GetDiscriminatorsForTypeAndSubTypes); } } } diff --git a/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs index d2b042d1fc0..e215da6d68c 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs @@ -95,30 +95,33 @@ obj is StandardDiscriminatorConvention other && /// The reader. /// The nominal type. /// The actual type. - public Type GetActualType(IBsonReader bsonReader, Type nominalType) + public Type GetActualType(IBsonReader bsonReader, Type nominalType) => //TODO This one should not be used + GetActualType(bsonReader, nominalType, BsonSerializer.DefaultSerializationDomain); + + internal Type GetActualType(IBsonReader bsonReader, Type nominalType, IBsonSerializationDomain domain) { // the BsonReader is sitting at the value whose actual type needs to be found var bsonType = bsonReader.GetCurrentBsonType(); if (bsonType == BsonType.Document) { // ensure KnownTypes of nominalType are registered (so IsTypeDiscriminated returns correct answer) - BsonSerializer.EnsureKnownTypesAreRegistered(nominalType); + domain.EnsureKnownTypesAreRegistered(nominalType); // we can skip looking for a discriminator if nominalType has no discriminated sub types - if (BsonSerializer.IsTypeDiscriminated(nominalType)) + if (domain.IsTypeDiscriminated(nominalType)) { var bookmark = bsonReader.GetBookmark(); bsonReader.ReadStartDocument(); var actualType = nominalType; if (bsonReader.FindElement(_elementName)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + var context = BsonDeserializationContext.CreateRoot(bsonReader, domain); var discriminator = BsonValueSerializer.Instance.Deserialize(context); if (discriminator.IsBsonArray) { discriminator = discriminator.AsBsonArray.Last(); // last item is leaf class discriminator } - actualType = BsonSerializer.LookupActualType(nominalType, discriminator); + actualType = domain.LookupActualType(nominalType, discriminator); } bsonReader.ReturnToBookmark(bookmark); return actualType; diff --git a/src/MongoDB.Bson/Serialization/Conventions/StringIdStoredAsObjectIdConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/StringIdStoredAsObjectIdConvention.cs index 923936d1508..d757e33b6f4 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/StringIdStoredAsObjectIdConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/StringIdStoredAsObjectIdConvention.cs @@ -23,10 +23,13 @@ namespace MongoDB.Bson.Serialization.Conventions /// This convention is only responsible for setting the serializer and idGenerator. It is assumed that this convention runs after /// other conventions that identify which member is the _id and that the _id has already been added to the class map. /// - public class StringIdStoredAsObjectIdConvention : ConventionBase, IMemberMapConvention + public class StringIdStoredAsObjectIdConvention : ConventionBase, IMemberMapConventionInternal { /// - public void Apply(BsonMemberMap memberMap) + public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain) { if (memberMap != memberMap.ClassMap.IdMemberMap) { @@ -38,7 +41,7 @@ public void Apply(BsonMemberMap memberMap) return; } - var defaultStringSerializer = BsonSerializer.LookupSerializer(typeof(string)); + var defaultStringSerializer = domain.LookupSerializer(typeof(string)); if (memberMap.GetSerializer() != defaultStringSerializer) { return; diff --git a/src/MongoDB.Bson/Serialization/Conventions/StringObjectIdIdGeneratorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/StringObjectIdIdGeneratorConvention.cs index 618d7213aec..0a8f48cf3db 100644 --- a/src/MongoDB.Bson/Serialization/Conventions/StringObjectIdIdGeneratorConvention.cs +++ b/src/MongoDB.Bson/Serialization/Conventions/StringObjectIdIdGeneratorConvention.cs @@ -14,7 +14,6 @@ */ using MongoDB.Bson.Serialization.IdGenerators; -using MongoDB.Bson.Serialization.Options; using MongoDB.Bson.Serialization.Serializers; namespace MongoDB.Bson.Serialization.Conventions @@ -22,14 +21,17 @@ namespace MongoDB.Bson.Serialization.Conventions /// /// A convention that sets the id generator for a string member with a BSON representation of ObjectId. /// - public class StringObjectIdIdGeneratorConvention : ConventionBase, IPostProcessingConvention + public class StringObjectIdIdGeneratorConvention : ConventionBase, IPostProcessingConventionInternal { // public methods /// /// Applies a post processing modification to the class map. /// /// The class map. - public void PostProcess(BsonClassMap classMap) + public void PostProcess(BsonClassMap classMap) => (this as IPostProcessingConventionInternal).PostProcess(classMap, BsonSerializer.DefaultSerializationDomain); + + /// + void IPostProcessingConventionInternal.PostProcess(BsonClassMap classMap, IBsonSerializationDomain domain) { var idMemberMap = classMap.IdMemberMap; if (idMemberMap != null) diff --git a/src/MongoDB.Bson/Serialization/IBsonClassMapDomain.cs b/src/MongoDB.Bson/Serialization/IBsonClassMapDomain.cs new file mode 100644 index 00000000000..6a0df68e291 --- /dev/null +++ b/src/MongoDB.Bson/Serialization/IBsonClassMapDomain.cs @@ -0,0 +1,96 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace MongoDB.Bson.Serialization +{ + internal interface IBsonClassMapDomain + { + /// + /// Gets all registered class maps. + /// + /// All registered class maps. + IEnumerable GetRegisteredClassMaps(); + + /// + /// Checks whether a class map is registered for a type. + /// + /// The type to check. + /// True if there is a class map registered for the type. + bool IsClassMapRegistered(Type type); + + /// + /// Looks up a class map (will AutoMap the class if no class map is registered). + /// + /// The class type. + /// The class map. + BsonClassMap LookupClassMap(Type classType); + + /// + /// Creates and registers a class map. + /// + /// The class. + /// The class map. + BsonClassMap RegisterClassMap(); + + /// + /// Creates and registers a class map. + /// + /// The class. + /// The class map initializer. + /// The class map. + BsonClassMap RegisterClassMap(Action> classMapInitializer); + + /// + /// Registers a class map. + /// + /// The class map. + void RegisterClassMap(BsonClassMap classMap); + + /// + /// Registers a class map if it is not already registered. + /// + /// The class. + /// True if this call registered the class map, false if the class map was already registered. + bool TryRegisterClassMap(); + + /// + /// Registers a class map if it is not already registered. + /// + /// The class. + /// The class map. + /// True if this call registered the class map, false if the class map was already registered. + bool TryRegisterClassMap(BsonClassMap classMap); + + /// + /// Registers a class map if it is not already registered. + /// + /// The class. + /// The class map initializer (only called if the class map is not already registered). + /// True if this call registered the class map, false if the class map was already registered. + bool TryRegisterClassMap(Action> classMapInitializer); + + /// + /// Registers a class map if it is not already registered. + /// + /// The class. + /// The class map factory (only called if the class map is not already registered). + /// True if this call registered the class map, false if the class map was already registered. + bool TryRegisterClassMap(Func> classMapFactory); + } +} \ No newline at end of file diff --git a/src/MongoDB.Bson/Serialization/IBsonIdProvider.cs b/src/MongoDB.Bson/Serialization/IBsonIdProvider.cs index 6cb9ba4a811..d63d71a0c10 100644 --- a/src/MongoDB.Bson/Serialization/IBsonIdProvider.cs +++ b/src/MongoDB.Bson/Serialization/IBsonIdProvider.cs @@ -39,4 +39,9 @@ public interface IBsonIdProvider /// The Id. void SetDocumentId(object document, object id); } + + internal interface IBsonIdProviderInternal : IBsonIdProvider + { + bool GetDocumentId(object document, IBsonSerializationDomain serializationDomain, out object id, out Type idNominalType, out IIdGenerator idGenerator); + } } diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs b/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs new file mode 100644 index 00000000000..34315129a4d --- /dev/null +++ b/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs @@ -0,0 +1,317 @@ +using System; +using System.IO; +using System.Threading; +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization.Conventions; + +namespace MongoDB.Bson.Serialization +{ + /// + /// //TODO + /// + internal interface IBsonSerializationDomain + { + string Name { get; } //FP This is used for debugging purposes, but we could decide to make it public if needed. + + /// + /// Returns whether the given type has any discriminators registered for any of its subclasses. + /// + /// A Type. + /// True if the type is discriminated. + bool IsTypeDiscriminated(Type type); + + /// + /// Looks up the actual type of an object to be deserialized. + /// + /// The nominal type of the object. + /// The discriminator. + /// The actual type of the object. + Type LookupActualType(Type nominalType, BsonValue discriminator); + + /// + /// Looks up the discriminator convention for a type. + /// + /// The type. + /// A discriminator convention. + IDiscriminatorConvention LookupDiscriminatorConvention(Type type); + + /// + /// Looks up an IdGenerator. + /// + /// The Id type. + /// An IdGenerator for the Id type. + IIdGenerator LookupIdGenerator(Type type); + + /// + /// Looks up a serializer for a Type. + /// + /// The type. + /// A serializer for type T. + IBsonSerializer LookupSerializer(); + + /// + /// Looks up a serializer for a Type. + /// + /// The Type. + /// A serializer for the Type. + IBsonSerializer LookupSerializer(Type type); + + /// + /// Gets the serializer registry. + /// + IBsonSerializerRegistry SerializerRegistry { get; } + + /// + /// Registers the discriminator for a type. + /// + /// The type. + /// The discriminator. + void RegisterDiscriminator(Type type, BsonValue discriminator); + + /// + /// Registers the discriminator convention for a type. + /// + /// Type type. + /// The discriminator convention. + void RegisterDiscriminatorConvention(Type type, IDiscriminatorConvention convention); + + /// + /// Registers a generic serializer definition for a generic type. + /// + /// The generic type. + /// The generic serializer definition. + void RegisterGenericSerializerDefinition( + Type genericTypeDefinition, + Type genericSerializerDefinition); + + /// + /// Registers an IdGenerator for an Id Type. + /// + /// The Id Type. + /// The IdGenerator for the Id Type. + void RegisterIdGenerator(Type type, IIdGenerator idGenerator); + + /// + /// Registers a serialization provider. + /// + /// The serialization provider. + void RegisterSerializationProvider(IBsonSerializationProvider provider); + + /// + /// Registers a serializer for a type. + /// + /// The type. + /// The serializer. + void RegisterSerializer(IBsonSerializer serializer); + + /// + /// Registers a serializer for a type. + /// + /// The type. + /// The serializer. + void RegisterSerializer(Type type, IBsonSerializer serializer); + + /// + /// Tries to register a serializer for a type. + /// + /// The serializer. + /// The type. + /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered. + bool TryRegisterSerializer(Type type, IBsonSerializer serializer); + + /// + /// Tries to register a serializer for a type. + /// + /// The type. + /// The serializer. + /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered. + bool TryRegisterSerializer(IBsonSerializer serializer); + + /// + /// Gets or sets whether to use the NullIdChecker on reference Id types that don't have an IdGenerator registered. + /// + bool UseNullIdChecker { get; set; } + + /// + /// Gets or sets whether to use the ZeroIdChecker on value Id types that don't have an IdGenerator registered. + /// + bool UseZeroIdChecker { get; set; } + + /// + /// Deserializes an object from a BsonDocument. + /// + /// The nominal type of the object. + /// The BsonDocument. + /// The configurator. + /// A deserialized value. + TNominalType Deserialize(BsonDocument document, + Action configurator = null); + + /// + /// Deserializes a value. + /// + /// The nominal type of the object. + /// The BsonReader. + /// The configurator. + /// A deserialized value. + TNominalType Deserialize(IBsonReader bsonReader, + Action configurator = null); + + /// + /// Deserializes an object from a BSON byte array. + /// + /// The nominal type of the object. + /// The BSON byte array. + /// The configurator. + /// A deserialized value. + TNominalType Deserialize(byte[] bytes, + Action configurator = null); + + /// + /// Deserializes an object from a BSON Stream. + /// + /// The nominal type of the object. + /// The BSON Stream. + /// The configurator. + /// A deserialized value. + TNominalType Deserialize(Stream stream, + Action configurator = null); + + /// + /// Deserializes an object from a JSON string. + /// + /// The nominal type of the object. + /// The JSON string. + /// The configurator. + /// A deserialized value. + TNominalType Deserialize(string json, + Action configurator = null); + + /// + /// Deserializes an object from a JSON TextReader. + /// + /// The nominal type of the object. + /// The JSON TextReader. + /// The configurator. + /// A deserialized value. + TNominalType Deserialize(TextReader textReader, + Action configurator = null); + + /// + /// Deserializes an object from a BsonDocument. + /// + /// The BsonDocument. + /// The nominal type of the object. + /// The configurator. + /// A deserialized value. + object Deserialize(BsonDocument document, Type nominalType, + Action configurator = null); + + /// + /// Deserializes a value. + /// + /// The BsonReader. + /// The nominal type of the object. + /// The configurator. + /// A deserialized value. + object Deserialize(IBsonReader bsonReader, Type nominalType, + Action configurator = null); + + /// + /// Deserializes an object from a BSON byte array. + /// + /// The BSON byte array. + /// The nominal type of the object. + /// The configurator. + /// A deserialized value. + object Deserialize(byte[] bytes, Type nominalType, + Action configurator = null); + + /// + /// Deserializes an object from a BSON Stream. + /// + /// The BSON Stream. + /// The nominal type of the object. + /// The configurator. + /// A deserialized value. + object Deserialize(Stream stream, Type nominalType, + Action configurator = null); + + /// + /// Deserializes an object from a JSON string. + /// + /// The JSON string. + /// The nominal type of the object. + /// The configurator. + /// A deserialized value. + object Deserialize(string json, Type nominalType, + Action configurator = null); + + /// + /// Deserializes an object from a JSON TextReader. + /// + /// The JSON TextReader. + /// The nominal type of the object. + /// The configurator. + /// A deserialized value. + object Deserialize(TextReader textReader, Type nominalType, + Action configurator = null); + + /// + /// Serializes a value. + /// + /// The nominal type of the object. + /// The BsonWriter. + /// The object. + /// The serialization context configurator. + /// The serialization args. + void Serialize( + IBsonWriter bsonWriter, + TNominalType value, + Action configurator = null, + BsonSerializationArgs args = default(BsonSerializationArgs)); + + /// + /// Serializes a value. + /// + /// The BsonWriter. + /// The nominal type of the object. + /// The object. + /// The serialization context configurator. + /// The serialization args. + void Serialize( + IBsonWriter bsonWriter, + Type nominalType, + object value, + Action configurator = null, + BsonSerializationArgs args = default(BsonSerializationArgs)); + + /// + /// //TODO + /// + IBsonClassMapDomain BsonClassMap { get; } + + /// + /// //TODO + /// + IConventionRegistryDomain ConventionRegistry { get; } + + /// + /// //TODO + /// + IBsonDefaults BsonDefaults { get; } + + //DOMAIN-API The following methods and properties were not public on BsonSerializer + + void EnsureKnownTypesAreRegistered(Type nominalType); + + BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type); + + IDiscriminatorConvention GetOrRegisterDiscriminatorConvention(Type type, + IDiscriminatorConvention discriminatorConvention); + + bool IsDiscriminatorConventionRegisteredAtThisLevel(Type type); + + ReaderWriterLockSlim ConfigLock { get; } + } +} \ No newline at end of file diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs b/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs index cdfca5d0676..6d1472eccea 100644 --- a/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs +++ b/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs @@ -17,6 +17,7 @@ namespace MongoDB.Bson.Serialization { + //DOMAIN-API We should remove this interface and merge it with IRegistryAwareBsonSerializationProvider. /// /// An interface implemented by serialization providers. /// @@ -48,4 +49,13 @@ public interface IRegistryAwareBsonSerializationProvider : IBsonSerializationPro /// IBsonSerializer GetSerializer(Type type, IBsonSerializerRegistry serializerRegistry); } + + //DOMAIN-API We should use this interface the default one, and remove the previous two. + internal interface IDomainAwareBsonSerializationProvider : IRegistryAwareBsonSerializationProvider + { + IBsonSerializationDomain SerializationDomain { get; } + + //FP Can't use just GetSerializer because it's already used by the base interface. + IBsonSerializer GetSerializerWithDomain(Type type); + } } diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs b/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs index fd5998c93b3..aa11d7bef91 100644 --- a/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs +++ b/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs @@ -13,7 +13,6 @@ * limitations under the License. */ -using System; using MongoDB.Bson.IO; using MongoDB.Bson.Serialization.Conventions; @@ -56,9 +55,18 @@ public static TValue Deserialize(this IBsonSerializer serializer /// The serializer. /// The discriminator convention. public static IDiscriminatorConvention GetDiscriminatorConvention(this IBsonSerializer serializer) => + GetDiscriminatorConvention(serializer, BsonSerializer.DefaultSerializationDomain); + + /// + /// //TODO + /// + /// + /// + /// + internal static IDiscriminatorConvention GetDiscriminatorConvention(this IBsonSerializer serializer, IBsonSerializationDomain serializationDomain) => serializer is IHasDiscriminatorConvention hasDiscriminatorConvention ? hasDiscriminatorConvention.DiscriminatorConvention - : BsonSerializer.LookupDiscriminatorConvention(serializer.ValueType); + : serializationDomain.LookupDiscriminatorConvention(serializer.ValueType); /// /// Serializes a value. @@ -96,7 +104,8 @@ public static BsonValue ToBsonValue(this IBsonSerializer serializer, object valu var document = new BsonDocument(); using (var writer = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(writer); + //QUESTION Is it correct we only need a default domain here? + var context = BsonSerializationContext.CreateRoot(writer, BsonSerializer.DefaultSerializationDomain); writer.WriteStartDocument(); writer.WriteName("x"); serializer.Serialize(context, value); @@ -117,7 +126,8 @@ public static BsonValue ToBsonValue(this IBsonSerializer seriali var document = new BsonDocument(); using (var writer = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(writer); + //QUESTION Is it correct we only need a default domain here? + var context = BsonSerializationContext.CreateRoot(writer, BsonSerializer.DefaultSerializationDomain); writer.WriteStartDocument(); writer.WriteName("x"); serializer.Serialize(context, value); diff --git a/src/MongoDB.Bson/Serialization/IIdGenerator.cs b/src/MongoDB.Bson/Serialization/IIdGenerator.cs index 5361038d9e3..2ff3c57d46c 100644 --- a/src/MongoDB.Bson/Serialization/IIdGenerator.cs +++ b/src/MongoDB.Bson/Serialization/IIdGenerator.cs @@ -27,6 +27,7 @@ public interface IIdGenerator /// The document. /// An Id. object GenerateId(object container, object document); + /// /// Tests whether an Id is empty. /// diff --git a/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs index fdcd59916ed..74d37b0069d 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs @@ -58,7 +58,7 @@ public BsonClassMapSerializer(BsonClassMap classMap) // public properties /// - public IDiscriminatorConvention DiscriminatorConvention => _classMap.GetDiscriminatorConvention(); + public IDiscriminatorConvention DiscriminatorConvention => _classMap.GetDiscriminatorConvention(); //TODO This should be removed, because we need to have the serialization domain. /// /// Gets a value indicating whether this serializer's discriminator is compatible with the object serializer. @@ -88,15 +88,16 @@ public override TClass Deserialize(BsonDeserializationContext context, BsonDeser return default(TClass); } - var discriminatorConvention = _classMap.GetDiscriminatorConvention(); + var discriminatorConvention = _classMap.GetDiscriminatorConvention(context.SerializationDomain); + + var actualType = discriminatorConvention.GetActualTypeInternal(bsonReader, args.NominalType, context.SerializationDomain); - var actualType = discriminatorConvention.GetActualType(bsonReader, args.NominalType); if (actualType == typeof(TClass)) { return DeserializeClass(context); } - var serializer = BsonSerializer.LookupSerializer(actualType); + var serializer = context.SerializationDomain.LookupSerializer(actualType); return (TClass)serializer.Deserialize(context); } @@ -146,7 +147,7 @@ public TClass DeserializeClass(BsonDeserializationContext context) } } - var discriminatorConvention = _classMap.GetDiscriminatorConvention(); + var discriminatorConvention = _classMap.GetDiscriminatorConvention(context.SerializationDomain); var allMemberMaps = _classMap.AllMemberMaps; var extraElementsMemberMapIndex = _classMap.ExtraElementsMemberMapIndex; var memberMapBitArray = FastMemberMapHelper.GetBitArray(allMemberMaps.Count); @@ -326,6 +327,10 @@ public bool GetDocumentId( out object id, out Type idNominalType, out IIdGenerator idGenerator) + => GetDocumentId(document, BsonSerializer.DefaultSerializationDomain, out id, out idNominalType, out idGenerator); + + internal bool GetDocumentId(object document, IBsonSerializationDomain serializationDomain, out object id, out Type idNominalType, + out IIdGenerator idGenerator) { var idMemberMap = _classMap.IdMemberMap; if (idMemberMap != null) @@ -392,7 +397,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati return; } - var serializer = BsonSerializer.LookupSerializer(actualType); + var serializer = context.SerializationDomain.LookupSerializer(actualType); serializer.Serialize(context, args, value); } @@ -566,7 +571,7 @@ private object DeserializeMemberValue(BsonDeserializationContext context, BsonMe { try { - return memberMap.GetSerializer().Deserialize(context); + return memberMap.GetSerializer(context.SerializationDomain).Deserialize(context); } catch (Exception ex) { @@ -637,11 +642,12 @@ private void SerializeExtraElements(BsonSerializationContext context, object obj private void SerializeDiscriminator(BsonSerializationContext context, Type nominalType, object obj) { - var discriminatorConvention = _classMap.GetDiscriminatorConvention(); + var discriminatorConvention = _classMap.GetDiscriminatorConvention(context.SerializationDomain); if (discriminatorConvention != null) { var actualType = obj.GetType(); - var discriminator = discriminatorConvention.GetDiscriminator(nominalType, actualType); + var discriminator = discriminatorConvention.GetDiscriminatorInternal(nominalType, actualType, context.SerializationDomain); + if (discriminator != null) { context.Writer.WriteName(discriminatorConvention.ElementName); @@ -684,7 +690,7 @@ private void SerializeNormalMember(BsonSerializationContext context, object obj, } bsonWriter.WriteName(memberMap.ElementName); - memberMap.GetSerializer().Serialize(context, value); + memberMap.GetSerializer(context.SerializationDomain).Serialize(context, value); } private bool ShouldSerializeDiscriminator(Type nominalType) diff --git a/src/MongoDB.Bson/Serialization/Serializers/BsonDocumentSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/BsonDocumentSerializer.cs index 2ba62a8294c..a3e7417ee06 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/BsonDocumentSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/BsonDocumentSerializer.cs @@ -81,6 +81,10 @@ public bool GetDocumentId( object document, out object id, out Type idNominalType, + out IIdGenerator idGenerator) => GetDocumentId(document, BsonSerializer.DefaultSerializationDomain, out id, + out idNominalType, out idGenerator); + + internal bool GetDocumentId(object document, IBsonSerializationDomain serializationDomain, out object id, out Type idNominalType, out IIdGenerator idGenerator) { var bsonDocument = (BsonDocument)document; @@ -89,7 +93,7 @@ public bool GetDocumentId( if (bsonDocument.TryGetValue("_id", out idBsonValue)) { id = idBsonValue; - idGenerator = BsonSerializer.LookupIdGenerator(id.GetType()); + idGenerator = serializationDomain.LookupIdGenerator(id.GetType()); if (idGenerator == null) { diff --git a/src/MongoDB.Bson/Serialization/Serializers/BsonValueSerializerBase.cs b/src/MongoDB.Bson/Serialization/Serializers/BsonValueSerializerBase.cs index e3a5776870c..0f636ae834b 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/BsonValueSerializerBase.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/BsonValueSerializerBase.cs @@ -70,7 +70,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati var actualType = value.GetType(); if (actualType != ValueType && !args.SerializeAsNominalType) { - var serializer = BsonSerializer.LookupSerializer(actualType); + var serializer = context.SerializationDomain.LookupSerializer(actualType); serializer.Serialize(context, value); return; } diff --git a/src/MongoDB.Bson/Serialization/Serializers/ClassSerializerBase.cs b/src/MongoDB.Bson/Serialization/Serializers/ClassSerializerBase.cs index 07723b9cddb..f21cd498ddf 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/ClassSerializerBase.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/ClassSerializerBase.cs @@ -47,7 +47,7 @@ public override TValue Deserialize(BsonDeserializationContext context, BsonDeser } else { - var serializer = BsonSerializer.LookupSerializer(actualType); + var serializer = context.SerializationDomain.LookupSerializer(actualType); return (TValue)serializer.Deserialize(context, args); } } @@ -75,7 +75,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati } else { - var serializer = BsonSerializer.LookupSerializer(actualType); + var serializer = context.SerializationDomain.LookupSerializer(actualType); serializer.Serialize(context, value); } } @@ -100,8 +100,8 @@ protected virtual TValue DeserializeValue(BsonDeserializationContext context, Bs /// The actual type. protected virtual Type GetActualType(BsonDeserializationContext context) { - var discriminatorConvention = this.GetDiscriminatorConvention(); - return discriminatorConvention.GetActualType(context.Reader, typeof(TValue)); + var discriminatorConvention = this.GetDiscriminatorConvention(context.SerializationDomain); + return discriminatorConvention.GetActualTypeInternal(context.Reader, typeof(TValue), context.SerializationDomain); } /// diff --git a/src/MongoDB.Bson/Serialization/Serializers/DictionaryInterfaceImplementerSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/DictionaryInterfaceImplementerSerializer.cs index 59e6cb42365..e1c60e22b3f 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/DictionaryInterfaceImplementerSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/DictionaryInterfaceImplementerSerializer.cs @@ -31,6 +31,7 @@ public sealed class DictionaryInterfaceImplementerSerializer : IDictionaryRepresentationConfigurable where TDictionary : class, IDictionary, new() { + //DOMAIN-API This version should be removed in the future. /// /// Initializes a new instance of the class. /// @@ -38,6 +39,7 @@ public DictionaryInterfaceImplementerSerializer() { } + //DOMAIN-API This version should be removed in the future. /// /// Initializes a new instance of the class. /// diff --git a/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs b/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs index 96b708d8aa6..da4be08eae8 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs @@ -45,6 +45,7 @@ private static class Flags private readonly IBsonSerializer _valueSerializer; // constructors + //DOMAIN-API This version should be removed in the future. /// /// Initializes a new instance of the class. /// @@ -53,6 +54,7 @@ public DictionarySerializerBase() { } + //DOMAIN-API This version should be removed in the future. /// /// Initializes a new instance of the class. /// @@ -273,7 +275,8 @@ private object DeserializeKeyString(string keyString) var keyDocument = new BsonDocument("k", keyString); using (var keyReader = new BsonDocumentReader(keyDocument)) { - var context = BsonDeserializationContext.CreateRoot(keyReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(keyReader, BsonSerializer.DefaultSerializationDomain); keyReader.ReadStartDocument(); keyReader.ReadName("k"); var key = _keySerializer.Deserialize(context); @@ -329,7 +332,8 @@ private string SerializeKeyString(object key) var keyDocument = new BsonDocument(); using (var keyWriter = new BsonDocumentWriter(keyDocument)) { - var context = BsonSerializationContext.CreateRoot(keyWriter); + //QUESTION Is it correct we only need a default domain here? + var context = BsonSerializationContext.CreateRoot(keyWriter, BsonSerializer.DefaultSerializationDomain); keyWriter.WriteStartDocument(); keyWriter.WriteName("k"); _keySerializer.Serialize(context, key); @@ -373,6 +377,7 @@ private static class Flags private readonly Lazy> _lazyValueSerializer; // constructors + //DOMAIN-API This version should be removed in the future. /// /// Initializes a new instance of the class. /// @@ -381,6 +386,8 @@ public DictionarySerializerBase() { } + //DOMAIN-API This version should be removed in the future. + //FP Fortunately it seems that all the constructors that should not be used are actually not used in the codebase. /// /// Initializes a new instance of the class. /// @@ -676,7 +683,8 @@ private TKey DeserializeKeyString(string keyString) var keyDocument = new BsonDocument("k", keyString); using (var keyReader = new BsonDocumentReader(keyDocument)) { - var context = BsonDeserializationContext.CreateRoot(keyReader); + //QUESTION Is it correct we only need a default domain here? + var context = BsonDeserializationContext.CreateRoot(keyReader, BsonSerializer.DefaultSerializationDomain); keyReader.ReadStartDocument(); keyReader.ReadName("k"); var key = _lazyKeySerializer.Value.Deserialize(context); @@ -732,7 +740,8 @@ private string SerializeKeyString(TKey key) var keyDocument = new BsonDocument(); using (var keyWriter = new BsonDocumentWriter(keyDocument)) { - var context = BsonSerializationContext.CreateRoot(keyWriter); + //QUESTION Is it correct we only need a default domain here? + var context = BsonSerializationContext.CreateRoot(keyWriter, BsonSerializer.DefaultSerializationDomain); keyWriter.WriteStartDocument(); keyWriter.WriteName("k"); _lazyKeySerializer.Value.Serialize(context, key); diff --git a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs index eb0035489e0..36719d18b57 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs @@ -41,14 +41,14 @@ public sealed class DiscriminatedInterfaceSerializer : // where TInterface is an interface { #region static - private static IBsonSerializer CreateInterfaceSerializer() + private static IBsonSerializer CreateInterfaceSerializer(IBsonSerializationDomain serializationDomain) { var classMapDefinition = typeof(BsonClassMap<>); var classMapType = classMapDefinition.MakeGenericType(typeof(TInterface)); var classMap = (BsonClassMap)Activator.CreateInstance(classMapType); classMap.AutoMap(); - classMap.SetDiscriminatorConvention(BsonSerializer.LookupDiscriminatorConvention(typeof(TInterface))); - classMap.Freeze(); + classMap.SetDiscriminatorConvention(serializationDomain.LookupDiscriminatorConvention(typeof(TInterface))); + classMap.Freeze(serializationDomain); return new BsonClassMapSerializer(classMap); } #endregion @@ -75,7 +75,7 @@ public DiscriminatedInterfaceSerializer() /// interfaceType /// interfaceType public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorConvention) - : this(discriminatorConvention, CreateInterfaceSerializer(), objectSerializer: null) + : this(discriminatorConvention, CreateInterfaceSerializer(BsonSerializer.DefaultSerializationDomain), objectSerializer: null) //TODO Is this ok? { } @@ -109,12 +109,12 @@ public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorCo } _interfaceType = typeof(TInterface); - _discriminatorConvention = discriminatorConvention ?? interfaceSerializer.GetDiscriminatorConvention(); + _discriminatorConvention = discriminatorConvention ?? interfaceSerializer.GetDiscriminatorConvention(); //QUESTION What do we do here? We don't have the domain close by, should we lazy initialize it during serialization/deserialization? _interfaceSerializer = interfaceSerializer; if (objectSerializer == null) { - objectSerializer = BsonSerializer.LookupSerializer(); + objectSerializer = BsonSerializer.LookupSerializer(); //QUESTION What do we do here? We don't have the domain close by, should we lazy initialize it during serialization/deserialization? if (objectSerializer is ObjectSerializer standardObjectSerializer) { Func allowedTypes = (Type type) => typeof(TInterface).IsAssignableFrom(type); @@ -158,7 +158,7 @@ public override TInterface Deserialize(BsonDeserializationContext context, BsonD } else { - var actualType = _discriminatorConvention.GetActualType(bsonReader, typeof(TInterface)); + var actualType = _discriminatorConvention.GetActualTypeInternal(bsonReader, typeof(TInterface), context.SerializationDomain); if (actualType == _interfaceType) { var message = string.Format("Unable to determine actual type of object to deserialize for interface type {0}.", _interfaceType.FullName); diff --git a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedWrapperSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedWrapperSerializer.cs index d7d5be76596..b85342a1f46 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedWrapperSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedWrapperSerializer.cs @@ -73,8 +73,8 @@ public override TValue Deserialize(BsonDeserializationContext context, BsonDeser { var bsonReader = context.Reader; var nominalType = args.NominalType; - var actualType = _discriminatorConvention.GetActualType(bsonReader, nominalType); - var serializer = BsonSerializer.LookupSerializer(actualType); + var actualType = _discriminatorConvention.GetActualTypeInternal(bsonReader, nominalType, context.SerializationDomain); + var serializer = context.SerializationDomain.LookupSerializer(actualType); TValue value = default(TValue); _helper.DeserializeMembers(context, (elementName, flag) => @@ -145,7 +145,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati var bsonWriter = context.Writer; var nominalType = args.NominalType; var actualType = value.GetType(); - var discriminator = _discriminatorConvention.GetDiscriminator(nominalType, actualType); + var discriminator = _discriminatorConvention.GetDiscriminatorInternal(nominalType, actualType, context.SerializationDomain); bsonWriter.WriteStartDocument(); if (discriminator != null) diff --git a/src/MongoDB.Bson/Serialization/Serializers/DynamicDocumentBaseSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/DynamicDocumentBaseSerializer.cs index d020fd3895d..1a283d437bf 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/DynamicDocumentBaseSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/DynamicDocumentBaseSerializer.cs @@ -26,8 +26,8 @@ namespace MongoDB.Bson.Serialization.Serializers /// The dynamic type. public abstract class DynamicDocumentBaseSerializer : SerializerBase where T : class, IDynamicMetaObjectProvider { - // private static fields - private static readonly IBsonSerializer __objectSerializer = BsonSerializer.LookupSerializer(); + // private fields + private IBsonSerializer _objectSerializer; // constructors /// @@ -58,7 +58,7 @@ public override T Deserialize(BsonDeserializationContext context, BsonDeserializ while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) { var name = bsonReader.ReadName(); - var value = __objectSerializer.Deserialize(dynamicContext); + var value = GetObjectSerializer(context.SerializationDomain).Deserialize(dynamicContext); SetValueForMember(document, name, value); } bsonReader.ReadEndDocument(); @@ -101,7 +101,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati if (TryGetValueForMember(value, memberName, out memberValue)) { bsonWriter.WriteName(memberName); - __objectSerializer.Serialize(dynamicContext, memberValue); + GetObjectSerializer(context.SerializationDomain).Serialize(dynamicContext, memberValue); } } bsonWriter.WriteEndDocument(); @@ -142,5 +142,11 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati /// The value. /// true if the member should be serialized; otherwise false. protected abstract bool TryGetValueForMember(T document, string memberName, out object value); + + //private methods + private IBsonSerializer GetObjectSerializer(IBsonSerializationDomain domain) + { + return _objectSerializer ??= domain.LookupSerializer(); + } } } diff --git a/src/MongoDB.Bson/Serialization/Serializers/ElementAppendingSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/ElementAppendingSerializer.cs index 168a757ee98..5fac80165e6 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/ElementAppendingSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/ElementAppendingSerializer.cs @@ -89,7 +89,7 @@ public void Serialize(BsonSerializationContext context, BsonSerializationArgs ar { var writer = context.Writer; var elementAppendingWriter = new ElementAppendingBsonWriter(writer, _elements, _writerSettingsConfigurator); - var elementAppendingContext = BsonSerializationContext.CreateRoot(elementAppendingWriter, builder => ConfigureElementAppendingContext(builder, context)); + var elementAppendingContext = BsonSerializationContext.CreateRoot(elementAppendingWriter, context.SerializationDomain, builder => ConfigureElementAppendingContext(builder, context)); _documentSerializer.Serialize(elementAppendingContext, args, value); } diff --git a/src/MongoDB.Bson/Serialization/Serializers/EnumerableSerializerBase.cs b/src/MongoDB.Bson/Serialization/Serializers/EnumerableSerializerBase.cs index 5d810b01861..6fd4130815f 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/EnumerableSerializerBase.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/EnumerableSerializerBase.cs @@ -31,6 +31,7 @@ public abstract class EnumerableSerializerBase : SerializerBase, private readonly Lazy _lazyItemSerializer; // constructors + //DOMAIN-API This version should be removed in the future. /// /// Initializes a new instance of the class. /// @@ -230,6 +231,7 @@ public abstract class EnumerableSerializerBase : SerializerBase> _lazyItemSerializer; // constructors + //DOMAIN-API This version should be removed in the future. /// /// Initializes a new instance of the class. /// diff --git a/src/MongoDB.Bson/Serialization/Serializers/ExpandoObjectSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/ExpandoObjectSerializer.cs index 4ac504304e5..f153c47f98f 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/ExpandoObjectSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/ExpandoObjectSerializer.cs @@ -31,12 +31,18 @@ public sealed class ExpandoObjectSerializer : DynamicDocumentBaseSerializer> _listSerializer; + //DOMAIN-API This version should be removed in the future. /// /// Initializes a new instance of the class. /// public ExpandoObjectSerializer() + :this(BsonSerializer.DefaultSerializationDomain.SerializerRegistry) { - _listSerializer = BsonSerializer.LookupSerializer>(); + } + + internal ExpandoObjectSerializer(IBsonSerializerRegistry serializerRegistry) + { + _listSerializer = serializerRegistry.GetSerializer>(); } /// diff --git a/src/MongoDB.Bson/Serialization/Serializers/IEnumerableDeserializingAsCollectionSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/IEnumerableDeserializingAsCollectionSerializer.cs index ca9ec6a771b..8009b37a0d1 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/IEnumerableDeserializingAsCollectionSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/IEnumerableDeserializingAsCollectionSerializer.cs @@ -45,6 +45,7 @@ private static void EnsureTIEnumerableIsAnInterface() // private fields private readonly Lazy> _lazyItemSerializer; + //DOMAIN-API This should be removed in the future. // constructors /// /// Initializes a new instance of the IEnumerableDeserializingAsCollectionSerializer class. diff --git a/src/MongoDB.Bson/Serialization/Serializers/ImpliedImplementationInterfaceSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/ImpliedImplementationInterfaceSerializer.cs index fc8cdf81829..e8cd662d937 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/ImpliedImplementationInterfaceSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/ImpliedImplementationInterfaceSerializer.cs @@ -48,6 +48,7 @@ public sealed class ImpliedImplementationInterfaceSerializer> _lazyImplementationSerializer; // constructors + //DOMAIN-API This should be removed in the future. /// /// Initializes a new instance of the class. /// @@ -279,7 +280,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati } else { - var serializer = BsonSerializer.LookupSerializer(actualType); + var serializer = context.SerializationDomain.LookupSerializer(actualType); serializer.Serialize(context, value); } } diff --git a/src/MongoDB.Bson/Serialization/Serializers/KeyValuePairSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/KeyValuePairSerializer.cs index ea1f59ac971..dc084978b70 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/KeyValuePairSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/KeyValuePairSerializer.cs @@ -53,6 +53,7 @@ private static class Flags private readonly Lazy> _lazyValueSerializer; // constructors + //DOMAIN-API This should be removed in the future. /// /// Initializes a new instance of the class. /// @@ -61,6 +62,7 @@ public KeyValuePairSerializer() { } + //DOMAIN-API This should be removed in the future. /// /// Initializes a new instance of the class. /// diff --git a/src/MongoDB.Bson/Serialization/Serializers/NullableSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/NullableSerializer.cs index 8740bdd3a9b..fafceb0d91b 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/NullableSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/NullableSerializer.cs @@ -60,6 +60,7 @@ public sealed class NullableSerializer : private Lazy> _lazySerializer; // constructors + //DOMAIN-API This should be removed in the future. /// /// Initializes a new instance of the class. /// diff --git a/src/MongoDB.Bson/Serialization/Serializers/ObjectSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/ObjectSerializer.cs index 36e4403718c..e3b9dc16c7a 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/ObjectSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/ObjectSerializer.cs @@ -47,7 +47,7 @@ public sealed class ObjectSerializer : ClassSerializerBase, IHasDiscrimi /// /// Gets the standard instance. /// - public static ObjectSerializer Instance => __instance; + public static ObjectSerializer Instance => __instance; //FP This is problematic, but can't do much about it now. /// /// An allowed types function that returns false for all types. @@ -63,6 +63,7 @@ public sealed class ObjectSerializer : ClassSerializerBase, IHasDiscrimi private readonly GuidSerializer _guidSerializer; // constructors + //DOMAIN-API This should be removed in the future. /// /// Initializes a new instance of the class. /// @@ -91,6 +92,7 @@ public ObjectSerializer(IDiscriminatorConvention discriminatorConvention, GuidRe { } + //DOMAIN-API This should be removed in the future. /// /// Initializes a new instance of the class. /// @@ -364,7 +366,8 @@ private object DeserializeDiscriminatedValue(BsonDeserializationContext context, { var bsonReader = context.Reader; - var actualType = _discriminatorConvention.GetActualType(bsonReader, typeof(object)); + var actualType = _discriminatorConvention.GetActualTypeInternal(bsonReader, args.NominalType, context.SerializationDomain); + if (!_allowedDeserializationTypes(actualType)) { throw new BsonSerializationException($"Type {actualType.FullName} is not configured as a type that is allowed to be deserialized for this instance of ObjectSerializer."); @@ -389,7 +392,7 @@ private object DeserializeDiscriminatedValue(BsonDeserializationContext context, } else { - var serializer = BsonSerializer.LookupSerializer(actualType); + var serializer = context.SerializationDomain.LookupSerializer(actualType); var polymorphicSerializer = serializer as IBsonPolymorphicSerializer; if (polymorphicSerializer != null && polymorphicSerializer.IsDiscriminatorCompatibleWithObjectSerializer) { @@ -438,7 +441,7 @@ private void SerializeDiscriminatedValue(BsonSerializationContext context, BsonS throw new BsonSerializationException($"Type {actualType.FullName} is not configured as a type that is allowed to be serialized for this instance of ObjectSerializer."); } - var serializer = BsonSerializer.LookupSerializer(actualType); + var serializer = context.SerializationDomain.LookupSerializer(actualType); var polymorphicSerializer = serializer as IBsonPolymorphicSerializer; if (polymorphicSerializer != null && polymorphicSerializer.IsDiscriminatorCompatibleWithObjectSerializer) @@ -455,7 +458,7 @@ private void SerializeDiscriminatedValue(BsonSerializationContext context, BsonS else { var bsonWriter = context.Writer; - var discriminator = _discriminatorConvention.GetDiscriminator(typeof(object), actualType); + var discriminator = _discriminatorConvention.GetDiscriminatorInternal(typeof(object), actualType, context.SerializationDomain); bsonWriter.WriteStartDocument(); if (discriminator != null) diff --git a/src/MongoDB.Bson/Serialization/Serializers/SerializeAsNominalTypeSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/SerializeAsNominalTypeSerializer.cs index 065ae3873f9..fd17ba37426 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/SerializeAsNominalTypeSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/SerializeAsNominalTypeSerializer.cs @@ -28,6 +28,7 @@ public sealed class SerializeAsNominalTypeSerializer private readonly Lazy> _lazyNominalTypeSerializer; // constructors + //DOMAIN-API This should be removed in the future. /// /// Initializes a new instance of the class. /// diff --git a/src/MongoDB.Bson/Serialization/Serializers/ThreeDimensionalArraySerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/ThreeDimensionalArraySerializer.cs index c2aaf3998fb..02ed938633f 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/ThreeDimensionalArraySerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/ThreeDimensionalArraySerializer.cs @@ -30,6 +30,7 @@ public sealed class ThreeDimensionalArraySerializer : private readonly Lazy> _lazyItemSerializer; // constructors + //DOMAIN-API This should be removed in the future. /// /// Initializes a new instance of the class. /// diff --git a/src/MongoDB.Bson/Serialization/Serializers/TupleSerializers.cs b/src/MongoDB.Bson/Serialization/Serializers/TupleSerializers.cs index a5b1e5f290a..140f40c9259 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/TupleSerializers.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/TupleSerializers.cs @@ -114,7 +114,7 @@ public sealed class TupleSerializer : SealedClassSerializerBase>, /// Initializes a new instance of the class. /// public TupleSerializer() - : this(BsonSerializer.SerializerRegistry) + : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is { } @@ -208,7 +208,7 @@ public sealed class TupleSerializer : SealedClassSerializerBase class. /// public TupleSerializer() - : this(BsonSerializer.SerializerRegistry) + : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is { } @@ -318,7 +318,7 @@ public sealed class TupleSerializer : SealedClassSerializerBase class. /// public TupleSerializer() - : this(BsonSerializer.SerializerRegistry) + : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is { } @@ -443,7 +443,7 @@ public sealed class TupleSerializer : SealedClassSerializerBase< /// Initializes a new instance of the class. /// public TupleSerializer() - : this(BsonSerializer.SerializerRegistry) + : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is { } @@ -585,7 +585,7 @@ public sealed class TupleSerializer : SealedClassSerializerB /// Initializes a new instance of the class. /// public TupleSerializer() - : this(BsonSerializer.SerializerRegistry) + : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is { } @@ -743,7 +743,7 @@ public sealed class TupleSerializer : SealedClassSeriali /// Initializes a new instance of the class. /// public TupleSerializer() - : this(BsonSerializer.SerializerRegistry) + : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is { } @@ -917,7 +917,7 @@ public sealed class TupleSerializer : SealedClassSer /// Initializes a new instance of the class. /// public TupleSerializer() - : this(BsonSerializer.SerializerRegistry) + : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is { } @@ -1107,7 +1107,7 @@ public sealed class TupleSerializer : SealedC /// Initializes a new instance of the class. /// public TupleSerializer() - : this(BsonSerializer.SerializerRegistry) + : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is { } diff --git a/src/MongoDB.Bson/Serialization/Serializers/TwoDimensionalArraySerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/TwoDimensionalArraySerializer.cs index afe701dd1c3..db1dc30d5e8 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/TwoDimensionalArraySerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/TwoDimensionalArraySerializer.cs @@ -30,6 +30,7 @@ public sealed class TwoDimensionalArraySerializer : private readonly Lazy> _lazyItemSerializer; // constructors + //DOMAIN-API This should be removed in the future. /// /// Initializes a new instance of the class. /// diff --git a/src/MongoDB.Bson/Serialization/Serializers/UndiscriminatedActualTypeSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/UndiscriminatedActualTypeSerializer.cs index 1587a979163..240ac575b1b 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/UndiscriminatedActualTypeSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/UndiscriminatedActualTypeSerializer.cs @@ -62,7 +62,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati else { var actualType = value.GetType(); - var serializer = BsonSerializer.LookupSerializer(actualType); + var serializer = context.SerializationDomain.LookupSerializer(actualType); args.NominalType = actualType; serializer.Serialize(context, args, value); } diff --git a/src/MongoDB.Bson/Serialization/Serializers/ValueTupleSerializers.cs b/src/MongoDB.Bson/Serialization/Serializers/ValueTupleSerializers.cs index d0f52484e58..db9cc0ae18f 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/ValueTupleSerializers.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/ValueTupleSerializers.cs @@ -71,6 +71,7 @@ public sealed class ValueTupleSerializer : StructSerializerBase> _lazyItem1Serializer; // constructors + //DOMAIN-API This should be removed in the future (also for the other versions) /// /// Initializes a new instance of the class. /// diff --git a/src/MongoDB.Driver.Authentication.AWS/SaslSteps/AWSLastSaslStep.cs b/src/MongoDB.Driver.Authentication.AWS/SaslSteps/AWSLastSaslStep.cs index 7d81604edf6..8a73478fd19 100644 --- a/src/MongoDB.Driver.Authentication.AWS/SaslSteps/AWSLastSaslStep.cs +++ b/src/MongoDB.Driver.Authentication.AWS/SaslSteps/AWSLastSaslStep.cs @@ -82,7 +82,7 @@ private byte[] PreparePayload(AWSCredentials credentials, byte[] serverNonce, st private void ParseServerResponse(SaslConversation conversation, byte[] bytesReceivedFromServer, out byte[] serverNonce, out string host) { - var serverFirstMessageDocument = BsonSerializer.Deserialize(bytesReceivedFromServer); + var serverFirstMessageDocument = BsonSerializer.Deserialize(bytesReceivedFromServer); //FP I think this is fine, as it should be default configuration. if (serverFirstMessageDocument.Names.Any(n => !__serverResponseExpectedNames.Contains(n))) { var unexpectedNames = serverFirstMessageDocument.Names.Except(__serverResponseExpectedNames); diff --git a/src/MongoDB.Driver.Encryption/ExplicitEncryptionLibMongoCryptController.cs b/src/MongoDB.Driver.Encryption/ExplicitEncryptionLibMongoCryptController.cs index cdb671f15e3..5a12564dfcd 100644 --- a/src/MongoDB.Driver.Encryption/ExplicitEncryptionLibMongoCryptController.cs +++ b/src/MongoDB.Driver.Encryption/ExplicitEncryptionLibMongoCryptController.cs @@ -102,7 +102,7 @@ public Guid CreateDataKey( { var wrappedKeyBytes = ProcessStates(context, _keyVaultNamespace.DatabaseNamespace.DatabaseName, cancellationToken); - var wrappedKeyDocument = BsonSerializer.Deserialize(wrappedKeyBytes); + var wrappedKeyDocument = BsonSerializer.Deserialize(wrappedKeyBytes); //FP I think this is fine, as it should be default configuration. var keyId = UnwrapKeyId(wrappedKeyDocument); _keyVaultCollection.Value.InsertOne(wrappedKeyDocument, cancellationToken: cancellationToken); @@ -131,7 +131,7 @@ public async Task CreateDataKeyAsync( { var wrappedKeyBytes = await ProcessStatesAsync(context, _keyVaultNamespace.DatabaseNamespace.DatabaseName, cancellationToken).ConfigureAwait(false); - var wrappedKeyDocument = BsonSerializer.Deserialize(wrappedKeyBytes); + var wrappedKeyDocument = BsonSerializer.Deserialize(wrappedKeyBytes); //FP I think this is fine, as it should be default configuration. var keyId = UnwrapKeyId(wrappedKeyDocument); await _keyVaultCollection.Value.InsertOneAsync(wrappedKeyDocument, cancellationToken: cancellationToken).ConfigureAwait(false); @@ -555,7 +555,7 @@ private byte[] GetWrappedValueBytes(BsonValue value) private static BsonValue RenderFilter(FilterDefinition filter) { - var registry = BsonSerializer.SerializerRegistry; + var registry = BsonSerializer.SerializerRegistry; //FP I think this is fine, as it should be default configuration. var serializer = registry.GetSerializer(); return filter.Render(new(serializer, registry)); } @@ -572,7 +572,7 @@ private static Guid UnwrapKeyId(BsonDocument wrappedKeyDocument) private static BsonValue UnwrapValue(byte[] encryptedWrappedBytes) { - var bsonDocument = BsonSerializer.Deserialize(encryptedWrappedBytes); + var bsonDocument = BsonSerializer.Deserialize(encryptedWrappedBytes); //FP I think this is fine, as it should be default configuration. return bsonDocument["v"]; } } diff --git a/src/MongoDB.Driver/AggregateExpressionDefinition.cs b/src/MongoDB.Driver/AggregateExpressionDefinition.cs index 85ae3f37e6a..eb898f917f0 100644 --- a/src/MongoDB.Driver/AggregateExpressionDefinition.cs +++ b/src/MongoDB.Driver/AggregateExpressionDefinition.cs @@ -140,7 +140,7 @@ internal ExpressionAggregateExpressionDefinition( public override BsonValue Render(RenderArgs args) { var contextData = _contextData?.With("SerializerRegistry", args.SerializerRegistry); - return LinqProviderAdapter.TranslateExpressionToAggregateExpression(_expression, args.DocumentSerializer, args.SerializerRegistry, args.TranslationOptions, contextData); + return LinqProviderAdapter.TranslateExpressionToAggregateExpression(_expression, args.DocumentSerializer, args.SerializationDomain, args.TranslationOptions, contextData); } } diff --git a/src/MongoDB.Driver/Authentication/MongoDBX509Authenticator.cs b/src/MongoDB.Driver/Authentication/MongoDBX509Authenticator.cs index 68d3379bb4b..ee7a68c199b 100644 --- a/src/MongoDB.Driver/Authentication/MongoDBX509Authenticator.cs +++ b/src/MongoDB.Driver/Authentication/MongoDBX509Authenticator.cs @@ -16,6 +16,7 @@ using System; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Connections; using MongoDB.Driver.Core.Misc; @@ -29,7 +30,6 @@ public static string MechanismName { get { return "MONGODB-X509"; } } - private readonly string _username; private readonly ServerApi _serverApi; @@ -112,7 +112,8 @@ private CommandWireProtocol CreateAuthenticateProtocol() secondaryOk: true, resultSerializer: BsonDocumentSerializer.Instance, messageEncoderSettings: null, - serverApi: _serverApi); + serverApi: _serverApi, + serializationDomain: BsonSerializer.DefaultSerializationDomain); //QUESTION Is this correct? Using a default serialization domain? return protocol; } diff --git a/src/MongoDB.Driver/Authentication/Oidc/AzureOidcCallback.cs b/src/MongoDB.Driver/Authentication/Oidc/AzureOidcCallback.cs index 8b4c3100ee0..ab4c8a11571 100644 --- a/src/MongoDB.Driver/Authentication/Oidc/AzureOidcCallback.cs +++ b/src/MongoDB.Driver/Authentication/Oidc/AzureOidcCallback.cs @@ -46,7 +46,7 @@ protected override OidcAccessToken ProcessHttpResponse(Stream responseStream) using var responseReader = new StreamReader(responseStream); using var jsonReader = new JsonReader(responseReader); - var context = BsonDeserializationContext.CreateRoot(jsonReader); + var context = BsonDeserializationContext.CreateRoot(jsonReader, BsonSerializer.DefaultSerializationDomain); //QUESTION Is it ok to use the default domain here? var document = BsonDocumentSerializer.Instance.Deserialize(context); var accessToken = document.GetValue("access_token"); diff --git a/src/MongoDB.Driver/Authentication/SaslAuthenticator.cs b/src/MongoDB.Driver/Authentication/SaslAuthenticator.cs index 96209fd8d9b..d7aefdc4653 100644 --- a/src/MongoDB.Driver/Authentication/SaslAuthenticator.cs +++ b/src/MongoDB.Driver/Authentication/SaslAuthenticator.cs @@ -18,6 +18,7 @@ using System.Net; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Connections; using MongoDB.Driver.Core.Misc; @@ -255,7 +256,8 @@ private CommandWireProtocol CreateCommandProtocol(BsonDocument com secondaryOk: true, resultSerializer: BsonDocumentSerializer.Instance, messageEncoderSettings: null, - serverApi: _serverApi); + serverApi: _serverApi, + serializationDomain: BsonSerializer.DefaultSerializationDomain); //QUESTION Is it correct to use the default serialization domain here? private BsonDocument CreateStartCommand(byte[] bytesToSendToServer) { diff --git a/src/MongoDB.Driver/BsonSerializerExtensions.cs b/src/MongoDB.Driver/BsonSerializerExtensions.cs index f71b12a2d50..93e520a85a6 100644 --- a/src/MongoDB.Driver/BsonSerializerExtensions.cs +++ b/src/MongoDB.Driver/BsonSerializerExtensions.cs @@ -13,20 +13,21 @@ * limitations under the License. */ +using MongoDB.Bson; using MongoDB.Bson.Serialization; namespace MongoDB.Driver { internal static class BsonSerializerExtensions { - public static object SetDocumentIdIfMissing(this IBsonSerializer serializer, object container, TDocument document) + public static object SetDocumentIdIfMissing(this IBsonSerializer serializer, object container, TDocument document, IBsonSerializationDomain serializationDomain) { var idProvider = serializer as IBsonIdProvider; if (idProvider != null) { object id; IIdGenerator idGenerator; - if (idProvider.GetDocumentId(document, out id, out _, out idGenerator)) + if (idProvider.GetDocumentIdInternal(document, serializationDomain, out id, out _, out idGenerator)) { if (idGenerator != null && idGenerator.IsEmpty(id)) { diff --git a/src/MongoDB.Driver/ChangeStreamHelper.cs b/src/MongoDB.Driver/ChangeStreamHelper.cs index a92825e6d99..6c526742699 100644 --- a/src/MongoDB.Driver/ChangeStreamHelper.cs +++ b/src/MongoDB.Driver/ChangeStreamHelper.cs @@ -30,14 +30,16 @@ public static ChangeStreamOperation CreateChangeStreamOperation( renderedPipeline.Documents, renderedPipeline.OutputSerializer, - messageEncoderSettings) + messageEncoderSettings, + serializationDomain) { RetryRequested = retryRequested }; @@ -53,15 +55,17 @@ public static ChangeStreamOperation CreateChangeStreamOperation( database.DatabaseNamespace, renderedPipeline.Documents, renderedPipeline.OutputSerializer, - messageEncoderSettings) + messageEncoderSettings, + serializationDomain) { RetryRequested = retryRequested }; @@ -78,15 +82,17 @@ public static ChangeStreamOperation CreateChangeStreamOperation( collection.CollectionNamespace, renderedPipeline.Documents, renderedPipeline.OutputSerializer, - messageEncoderSettings) + messageEncoderSettings, + serializationDomain) { RetryRequested = retryRequested }; @@ -99,11 +105,11 @@ public static ChangeStreamOperation CreateChangeStreamOperation RenderPipeline( PipelineDefinition, TResult> pipeline, IBsonSerializer documentSerializer, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) { var changeStreamDocumentSerializer = new ChangeStreamDocumentSerializer(documentSerializer); - var serializerRegistry = BsonSerializer.SerializerRegistry; - return pipeline.Render(new(changeStreamDocumentSerializer, serializerRegistry, translationOptions: translationOptions)); + return pipeline.Render(new(changeStreamDocumentSerializer, serializationDomain, translationOptions: translationOptions)); } private static void SetOperationOptions( diff --git a/src/MongoDB.Driver/ClusteredIndexOptions.cs b/src/MongoDB.Driver/ClusteredIndexOptions.cs index cb3b597ee19..64d886b6e1e 100644 --- a/src/MongoDB.Driver/ClusteredIndexOptions.cs +++ b/src/MongoDB.Driver/ClusteredIndexOptions.cs @@ -64,6 +64,7 @@ public bool Unique set => _unique = value; } + //DOMAIN-API This version will need to go away. internal BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry, ExpressionTranslationOptions translationOptions) { return new BsonDocument { @@ -72,5 +73,14 @@ internal BsonDocument Render(IBsonSerializer documentSerializer, IBso { "name", _name, _name != null } }; } + + internal BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) + { + return new BsonDocument { + { "key", _key.Render(new(documentSerializer, serializationDomain, translationOptions: translationOptions)) }, + { "unique", _unique }, + { "name", _name, _name != null } + }; + } } } diff --git a/src/MongoDB.Driver/Core/Bindings/CoreSession.cs b/src/MongoDB.Driver/Core/Bindings/CoreSession.cs index 954c639e244..40235c3715b 100644 --- a/src/MongoDB.Driver/Core/Bindings/CoreSession.cs +++ b/src/MongoDB.Driver/Core/Bindings/CoreSession.cs @@ -18,6 +18,7 @@ using System.Threading; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Driver.Core.Clusters; using MongoDB.Driver.Core.Misc; using MongoDB.Driver.Core.Operations; @@ -45,6 +46,7 @@ public sealed class CoreSession : ICoreSession, ICoreSessionInternal private BsonTimestamp _snapshotTime; // constructors + //FP This constructor is only used by the tests. internal CoreSession( IClusterInternal cluster, ICoreServerSession serverSession, @@ -446,6 +448,7 @@ public void WasUsed() // private methods private IReadOperation CreateAbortTransactionOperation(OperationContext operationContext) { + //QUESTION Is it correct we only need a default domain here? return new AbortTransactionOperation(_currentTransaction.RecoveryToken, GetTransactionWriteConcern(operationContext)); } @@ -453,7 +456,8 @@ private IReadOperation CreateCommitTransactionOperation(OperationC { var writeConcern = GetCommitTransactionWriteConcern(operationContext, isCommitRetry); var maxCommitTime = _currentTransaction.TransactionOptions.MaxCommitTime; - return new CommitTransactionOperation(_currentTransaction.RecoveryToken, writeConcern) { MaxCommitTime = maxCommitTime }; + //QUESTION Is it correct we only need a default domain here? + return new CommitTransactionOperation(_currentTransaction.RecoveryToken, writeConcern, BsonSerializer.DefaultSerializationDomain) { MaxCommitTime = maxCommitTime }; } private void EnsureAbortTransactionCanBeCalled(string methodName) diff --git a/src/MongoDB.Driver/Core/Bindings/IChannel.cs b/src/MongoDB.Driver/Core/Bindings/IChannel.cs index 3a1dca12020..b0dd2f7a8c5 100644 --- a/src/MongoDB.Driver/Core/Bindings/IChannel.cs +++ b/src/MongoDB.Driver/Core/Bindings/IChannel.cs @@ -31,6 +31,22 @@ internal interface IChannel : IDisposable IConnectionHandle Connection { get; } ConnectionDescription ConnectionDescription { get; } + TResult Command( + OperationContext operationContext, + ICoreSession session, + ReadPreference readPreference, + DatabaseNamespace databaseNamespace, + BsonDocument command, + IEnumerable commandPayloads, + IElementNameValidator commandValidator, + BsonDocument additionalOptions, + Action postWriteAction, + CommandResponseHandling responseHandling, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain); + + //EXIT TResult Command( OperationContext operationContext, ICoreSession session, @@ -45,6 +61,22 @@ TResult Command( IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings); + Task CommandAsync( + OperationContext operationContext, + ICoreSession session, + ReadPreference readPreference, + DatabaseNamespace databaseNamespace, + BsonDocument command, + IEnumerable commandPayloads, + IElementNameValidator commandValidator, + BsonDocument additionalOptions, + Action postWriteAction, + CommandResponseHandling responseHandling, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain); + + //EXIT Task CommandAsync( OperationContext operationContext, ICoreSession session, diff --git a/src/MongoDB.Driver/Core/Connections/ConnectionInitializer.cs b/src/MongoDB.Driver/Core/Connections/ConnectionInitializer.cs index 07616e028af..1a123ece262 100644 --- a/src/MongoDB.Driver/Core/Connections/ConnectionInitializer.cs +++ b/src/MongoDB.Driver/Core/Connections/ConnectionInitializer.cs @@ -17,6 +17,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Authentication; using MongoDB.Driver.Core.Configuration; @@ -161,7 +162,8 @@ private CommandWireProtocol CreateGetLastErrorProtocol(ServerApi s secondaryOk: true, resultSerializer: BsonDocumentSerializer.Instance, messageEncoderSettings: null, - serverApi: serverApi); + serverApi: serverApi, + serializationDomain: BsonSerializer.DefaultSerializationDomain); //QUESTION Is it correct to use the default serialization domain here? return getLastErrorProtocol; } diff --git a/src/MongoDB.Driver/Core/Connections/HelloHelper.cs b/src/MongoDB.Driver/Core/Connections/HelloHelper.cs index ee5a8caae9e..4aee3aa65fa 100644 --- a/src/MongoDB.Driver/Core/Connections/HelloHelper.cs +++ b/src/MongoDB.Driver/Core/Connections/HelloHelper.cs @@ -18,6 +18,7 @@ using System.Linq; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Authentication; using MongoDB.Driver.Core.Compression; @@ -79,7 +80,8 @@ internal static CommandWireProtocol CreateProtocol( commandResponseHandling: commandResponseHandling, resultSerializer: BsonDocumentSerializer.Instance, messageEncoderSettings: null, - serverApi); + serverApi, + serializationDomain: BsonSerializer.DefaultSerializationDomain); //QUESTION Is it correct to use the default serialization domain here? } internal static HelloResult GetResult( diff --git a/src/MongoDB.Driver/Core/Operations/AggregateOperation.cs b/src/MongoDB.Driver/Core/Operations/AggregateOperation.cs index 8f1947cc546..956ef08fc50 100644 --- a/src/MongoDB.Driver/Core/Operations/AggregateOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/AggregateOperation.cs @@ -46,6 +46,7 @@ internal sealed class AggregateOperation : IReadOperation _pipeline; private ReadConcern _readConcern = ReadConcern.Default; private readonly IBsonSerializer _resultSerializer; + private readonly IBsonSerializationDomain _serializationDomain; private bool _retryRequested; private bool? _useCursor; @@ -57,12 +58,24 @@ internal sealed class AggregateOperation : IReadOperationThe pipeline. /// The result value serializer. /// The message encoder settings. - public AggregateOperation(DatabaseNamespace databaseNamespace, IEnumerable pipeline, IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings) - : this(pipeline, resultSerializer, messageEncoderSettings) + /// The serialization domain. + public AggregateOperation(DatabaseNamespace databaseNamespace, + IEnumerable pipeline, IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : this(pipeline, resultSerializer, messageEncoderSettings, serializationDomain) { _databaseNamespace = Ensure.IsNotNull(databaseNamespace, nameof(databaseNamespace)); } + //EXIT + public AggregateOperation(DatabaseNamespace databaseNamespace, + IEnumerable pipeline, IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings) + : this(databaseNamespace, pipeline, resultSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { + } + /// /// Initializes a new instance of the class. /// @@ -70,17 +83,35 @@ public AggregateOperation(DatabaseNamespace databaseNamespace, IEnumerableThe pipeline. /// The result value serializer. /// The message encoder settings. - public AggregateOperation(CollectionNamespace collectionNamespace, IEnumerable pipeline, IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings) - : this(pipeline, resultSerializer, messageEncoderSettings) + /// The serialization domain. + public AggregateOperation(CollectionNamespace collectionNamespace, + IEnumerable pipeline, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : this(pipeline, resultSerializer, messageEncoderSettings, serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); } - private AggregateOperation(IEnumerable pipeline, IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings) + //EXIT + public AggregateOperation(CollectionNamespace collectionNamespace, + IEnumerable pipeline, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, pipeline, resultSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { + } + + private AggregateOperation(IEnumerable pipeline, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _pipeline = Ensure.IsNotNull(pipeline, nameof(pipeline)).ToList(); _resultSerializer = Ensure.IsNotNull(resultSerializer, nameof(resultSerializer)); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); } // properties @@ -359,7 +390,7 @@ private ReadCommandOperation CreateOperation(OperationContext o var databaseNamespace = _collectionNamespace == null ? _databaseNamespace : _collectionNamespace.DatabaseNamespace; var command = CreateCommand(operationContext, context.Binding.Session, context.Channel.ConnectionDescription); var serializer = new AggregateResultDeserializer(_resultSerializer); - return new ReadCommandOperation(databaseNamespace, command, serializer, MessageEncoderSettings) + return new ReadCommandOperation(databaseNamespace, command, serializer, MessageEncoderSettings, _serializationDomain) { RetryRequested = _retryRequested // might be overridden by retryable read context }; @@ -393,6 +424,7 @@ private AsyncCursor CreateCursorFromCursorResult(IChannelSourceHandle c null, // limit _resultSerializer, MessageEncoderSettings, + _serializationDomain, _maxAwaitTime); } @@ -409,6 +441,7 @@ private AsyncCursor CreateCursorFromInlineResult(AggregateResult result null, // limit _resultSerializer, MessageEncoderSettings, + _serializationDomain, _maxAwaitTime); } diff --git a/src/MongoDB.Driver/Core/Operations/AggregateToCollectionOperation.cs b/src/MongoDB.Driver/Core/Operations/AggregateToCollectionOperation.cs index 0003d2cb3ae..39317008a31 100644 --- a/src/MongoDB.Driver/Core/Operations/AggregateToCollectionOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/AggregateToCollectionOperation.cs @@ -1,4 +1,4 @@ -/* Copyright 2010-present MongoDB Inc. +/* Copyright 2013-present MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ using System.Linq; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Connections; @@ -44,19 +45,27 @@ internal sealed class AggregateToCollectionOperation : IWriteOperation pipeline, MessageEncoderSettings messageEncoderSettings) + public AggregateToCollectionOperation(DatabaseNamespace databaseNamespace, IEnumerable pipeline, MessageEncoderSettings messageEncoderSettings, IBsonSerializationDomain serializationDomain) { _databaseNamespace = Ensure.IsNotNull(databaseNamespace, nameof(databaseNamespace)); _pipeline = Ensure.IsNotNull(pipeline, nameof(pipeline)).ToList(); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); EnsureIsOutputToCollectionPipeline(); _pipeline = SimplifyOutStageIfOutputDatabaseIsSameAsInputDatabase(_pipeline); } - public AggregateToCollectionOperation(CollectionNamespace collectionNamespace, IEnumerable pipeline, MessageEncoderSettings messageEncoderSettings) - : this(Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)).DatabaseNamespace, pipeline, messageEncoderSettings) + //EXIT + public AggregateToCollectionOperation(DatabaseNamespace databaseNamespace, IEnumerable pipeline, MessageEncoderSettings messageEncoderSettings) + : this(databaseNamespace, pipeline, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { + } + + public AggregateToCollectionOperation(CollectionNamespace collectionNamespace, IEnumerable pipeline, MessageEncoderSettings messageEncoderSettings, IBsonSerializationDomain serializationDomain) + : this(Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)).DatabaseNamespace, pipeline, messageEncoderSettings, serializationDomain) { _collectionNamespace = collectionNamespace; } @@ -189,7 +198,7 @@ public BsonDocument CreateCommand(OperationContext operationContext, ICoreSessio { "pipeline", new BsonArray(_pipeline) }, { "allowDiskUse", () => _allowDiskUse.Value, _allowDiskUse.HasValue }, { "bypassDocumentValidation", () => _bypassDocumentValidation.Value, _bypassDocumentValidation.HasValue }, - { "maxTimeMS", () => MaxTimeHelper.ToMaxTimeMS(_maxTime.Value), _maxTime.HasValue && !operationContext.IsRootContextTimeoutConfigured() }, + { "maxTimeMS", () => MaxTimeHelper.ToMaxTimeMS(_maxTime.Value), _maxTime.HasValue }, { "collation", () => _collation.ToBsonDocument(), _collation != null }, { "readConcern", readConcern, readConcern != null }, { "writeConcern", writeConcern, writeConcern != null }, @@ -205,7 +214,7 @@ public BsonDocument CreateCommand(OperationContext operationContext, ICoreSessio private WriteCommandOperation CreateOperation(OperationContext operationContext, ICoreSessionHandle session, ConnectionDescription connectionDescription, ReadPreference effectiveReadPreference) { var command = CreateCommand(operationContext, session, connectionDescription); - var operation = new WriteCommandOperation(_databaseNamespace, command, BsonDocumentSerializer.Instance, MessageEncoderSettings); + var operation = new WriteCommandOperation(_databaseNamespace, command, BsonDocumentSerializer.Instance, MessageEncoderSettings, _serializationDomain); if (effectiveReadPreference != null) { operation.ReadPreference = effectiveReadPreference; diff --git a/src/MongoDB.Driver/Core/Operations/AsyncCursor.cs b/src/MongoDB.Driver/Core/Operations/AsyncCursor.cs index 6791ae3a44a..fb8fc208546 100644 --- a/src/MongoDB.Driver/Core/Operations/AsyncCursor.cs +++ b/src/MongoDB.Driver/Core/Operations/AsyncCursor.cs @@ -53,6 +53,7 @@ internal class AsyncCursor : IAsyncCursor, ICursorBatchInf private readonly int? _limit; private readonly TimeSpan? _maxTime; private readonly MessageEncoderSettings _messageEncoderSettings; + private readonly IBsonSerializationDomain _serializationDomain; private readonly long? _operationId; private BsonDocument _postBatchResumeToken; private readonly IBsonSerializer _serializer; @@ -68,6 +69,7 @@ public AsyncCursor( int? limit, IBsonSerializer serializer, MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain, TimeSpan? maxTime = null) : this( channelSource, @@ -80,6 +82,34 @@ public AsyncCursor( limit, serializer, messageEncoderSettings, + serializationDomain, + maxTime) + { + } + + //EXIT + public AsyncCursor( + IChannelSource channelSource, + CollectionNamespace collectionNamespace, + BsonValue comment, + IReadOnlyList firstBatch, + long cursorId, + int? batchSize, + int? limit, + IBsonSerializer serializer, + MessageEncoderSettings messageEncoderSettings, + TimeSpan? maxTime = null) + : this( + channelSource, + collectionNamespace, + comment, + firstBatch, + cursorId, + batchSize, // postBatchResumeToken + limit, + serializer, + messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain, maxTime) { } @@ -95,6 +125,7 @@ public AsyncCursor( int? limit, IBsonSerializer serializer, MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain, TimeSpan? maxTime) { _operationId = EventContext.OperationId; @@ -108,6 +139,7 @@ public AsyncCursor( _limit = Ensure.IsNullOrGreaterThanOrEqualToZero(limit, nameof(limit)); _serializer = Ensure.IsNotNull(serializer, nameof(serializer)); _messageEncoderSettings = messageEncoderSettings; + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); _maxTime = maxTime; if (_limit > 0 && _firstBatch.Count > _limit) @@ -120,6 +152,35 @@ public AsyncCursor( DisposeChannelSourceIfNoLongerNeeded(); } + //EXIT + public AsyncCursor( + IChannelSource channelSource, + CollectionNamespace collectionNamespace, + BsonValue comment, + IReadOnlyList firstBatch, + long cursorId, + BsonDocument postBatchResumeToken, + int? batchSize, + int? limit, + IBsonSerializer serializer, + MessageEncoderSettings messageEncoderSettings, + TimeSpan? maxTime) + : this( + channelSource, + collectionNamespace, + comment, + firstBatch, + cursorId, + postBatchResumeToken, + batchSize, + limit, + serializer, + messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain, + maxTime) + { + } + public IEnumerable Current { get @@ -183,7 +244,7 @@ private CursorBatch CreateCursorBatch(BsonDocument result) using (batch) { - var documents = CursorBatchDeserializationHelper.DeserializeBatch(batch, _serializer, _messageEncoderSettings); + var documents = CursorBatchDeserializationHelper.DeserializeBatch(batch, _serializer, _messageEncoderSettings, _serializationDomain); return new CursorBatch(cursorId, postBatchResumeToken, documents); } } @@ -233,7 +294,8 @@ private CursorBatch ExecuteGetMoreCommand(IChannelHandle channel, Can null, // postWriteAction CommandResponseHandling.Return, __getMoreCommandResultSerializer, - _messageEncoderSettings); + _messageEncoderSettings, + _serializationDomain); } catch (MongoCommandException ex) when (IsMongoCursorNotFoundException(ex)) { @@ -263,7 +325,8 @@ private async Task> ExecuteGetMoreCommandAsync(IChannelHa null, // postWriteAction CommandResponseHandling.Return, __getMoreCommandResultSerializer, - _messageEncoderSettings).ConfigureAwait(false); + _messageEncoderSettings, + _serializationDomain).ConfigureAwait(false); } catch (MongoCommandException ex) when (IsMongoCursorNotFoundException(ex)) { @@ -290,7 +353,8 @@ private void ExecuteKillCursorsCommand(IChannelHandle channel, CancellationToken null, // postWriteAction CommandResponseHandling.Return, BsonDocumentSerializer.Instance, - _messageEncoderSettings); + _messageEncoderSettings, + _serializationDomain); ThrowIfKillCursorsCommandFailed(result, channel.ConnectionDescription.ConnectionId); } @@ -312,7 +376,8 @@ private async Task ExecuteKillCursorsCommandAsync(IChannelHandle channel, Cancel null, // postWriteAction CommandResponseHandling.Return, BsonDocumentSerializer.Instance, - _messageEncoderSettings) + _messageEncoderSettings, + _serializationDomain) .ConfigureAwait(false); ThrowIfKillCursorsCommandFailed(result, channel.ConnectionDescription.ConnectionId); diff --git a/src/MongoDB.Driver/Core/Operations/ChangeStreamCursor.cs b/src/MongoDB.Driver/Core/Operations/ChangeStreamCursor.cs index f43cb30a168..61ba0eecd2c 100644 --- a/src/MongoDB.Driver/Core/Operations/ChangeStreamCursor.cs +++ b/src/MongoDB.Driver/Core/Operations/ChangeStreamCursor.cs @@ -46,6 +46,7 @@ internal sealed class ChangeStreamCursor : IChangeStreamCursor @@ -65,6 +66,7 @@ internal sealed class ChangeStreamCursor : IChangeStreamCursorThe resume after value. /// The start at operation time value. /// The maximum wire version. + /// The serialization domain. public ChangeStreamCursor( IAsyncCursor cursor, IBsonSerializer documentSerializer, @@ -75,7 +77,8 @@ public ChangeStreamCursor( BsonDocument initialStartAfter, BsonDocument initialResumeAfter, BsonTimestamp initialStartAtOperationTime, - int maxWireVersion) + int maxWireVersion, + IBsonSerializationDomain serializationDomain) { _cursor = Ensure.IsNotNull(cursor, nameof(cursor)); _documentSerializer = Ensure.IsNotNull(documentSerializer, nameof(documentSerializer)); @@ -88,6 +91,34 @@ public ChangeStreamCursor( _initialResumeAfter = initialResumeAfter; _initialStartAtOperationTime = initialStartAtOperationTime; _maxWireVersion = Ensure.IsGreaterThanOrEqualToZero(maxWireVersion, nameof(maxWireVersion)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + public ChangeStreamCursor( + IAsyncCursor cursor, + IBsonSerializer documentSerializer, + IReadBinding binding, + IChangeStreamOperation changeStreamOperation, + BsonDocument aggregatePostBatchResumeToken, + BsonTimestamp initialOperationTime, + BsonDocument initialStartAfter, + BsonDocument initialResumeAfter, + BsonTimestamp initialStartAtOperationTime, + int maxWireVersion) + : this( + cursor, + documentSerializer, + binding, + changeStreamOperation, + aggregatePostBatchResumeToken, + initialOperationTime, + initialStartAfter, + initialResumeAfter, + initialStartAtOperationTime, + maxWireVersion, + BsonSerializer.DefaultSerializationDomain) + { } // public methods @@ -165,7 +196,7 @@ private TDocument DeserializeDocument(RawBsonDocument rawDocument) using (var stream = new ByteBufferStream(rawDocument.Slice, ownsBuffer: false)) using (var reader = new BsonBinaryReader(stream)) { - var context = BsonDeserializationContext.CreateRoot(reader); + var context = BsonDeserializationContext.CreateRoot(reader, _serializationDomain); return _documentSerializer.Deserialize(context); } } diff --git a/src/MongoDB.Driver/Core/Operations/ChangeStreamOperation.cs b/src/MongoDB.Driver/Core/Operations/ChangeStreamOperation.cs index ed08f1c85e5..0fc86ffcbed 100644 --- a/src/MongoDB.Driver/Core/Operations/ChangeStreamOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/ChangeStreamOperation.cs @@ -53,6 +53,7 @@ internal sealed class ChangeStreamOperation : IChangeStreamOperation _resultSerializer; private BsonDocument _resumeAfter; private bool _retryRequested; + private readonly IBsonSerializationDomain _serializationDomain; private bool? _showExpandedEvents; private BsonDocument _startAfter; private BsonTimestamp _startAtOperationTime; @@ -60,33 +61,60 @@ internal sealed class ChangeStreamOperation : IChangeStreamOperation pipeline, IBsonSerializer resultSerializer, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _pipeline = Ensure.IsNotNull(pipeline, nameof(pipeline)).ToList(); _resultSerializer = Ensure.IsNotNull(resultSerializer, nameof(resultSerializer)); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); } + //EXIT public ChangeStreamOperation( DatabaseNamespace databaseNamespace, IEnumerable pipeline, IBsonSerializer resultSerializer, - MessageEncoderSettings messageEncoderSettings) - : this(pipeline, resultSerializer, messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : this(pipeline, resultSerializer, messageEncoderSettings, serializationDomain) { _databaseNamespace = Ensure.IsNotNull(databaseNamespace, nameof(databaseNamespace)); } + //EXIT public ChangeStreamOperation( - CollectionNamespace collectionNamespace, + DatabaseNamespace databaseNamespace, IEnumerable pipeline, IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings) - : this(pipeline, resultSerializer, messageEncoderSettings) + : this(databaseNamespace, pipeline, resultSerializer, messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain) + { + } + + public ChangeStreamOperation( + CollectionNamespace collectionNamespace, + IEnumerable pipeline, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : this(pipeline, resultSerializer, messageEncoderSettings, serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); } + //EXIT + public ChangeStreamOperation( + CollectionNamespace collectionNamespace, + IEnumerable pipeline, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, pipeline, resultSerializer, messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain) + { + } + // public properties /// /// Gets or sets the size of the batch. @@ -279,7 +307,8 @@ public IChangeStreamCursor Execute(OperationContext operationContext, I _startAfter, _resumeAfter, _startAtOperationTime, - context.Channel.ConnectionDescription.MaxWireVersion); + context.Channel.ConnectionDescription.MaxWireVersion, + _serializationDomain); } } @@ -314,7 +343,8 @@ public async Task> ExecuteAsync(OperationContext op _startAfter, _resumeAfter, _startAtOperationTime, - context.Channel.ConnectionDescription.MaxWireVersion); + context.Channel.ConnectionDescription.MaxWireVersion, + _serializationDomain); } } @@ -345,7 +375,7 @@ private AggregateOperation CreateAggregateOperation() AggregateOperation operation; if (_collectionNamespace != null) { - operation = new AggregateOperation(_collectionNamespace, combinedPipeline, RawBsonDocumentSerializer.Instance, _messageEncoderSettings) + operation = new AggregateOperation(_collectionNamespace, combinedPipeline, RawBsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain) { RetryRequested = _retryRequested // might be overridden by retryable read context }; @@ -353,7 +383,7 @@ private AggregateOperation CreateAggregateOperation() else { var databaseNamespace = _databaseNamespace ?? DatabaseNamespace.Admin; - operation = new AggregateOperation(databaseNamespace, combinedPipeline, RawBsonDocumentSerializer.Instance, _messageEncoderSettings) + operation = new AggregateOperation(databaseNamespace, combinedPipeline, RawBsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain) { RetryRequested = _retryRequested // might be overridden by retryable read context }; diff --git a/src/MongoDB.Driver/Core/Operations/ClientBulkWriteOperation.cs b/src/MongoDB.Driver/Core/Operations/ClientBulkWriteOperation.cs index f872d83bf61..58dc66f5e95 100644 --- a/src/MongoDB.Driver/Core/Operations/ClientBulkWriteOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/ClientBulkWriteOperation.cs @@ -18,6 +18,7 @@ using System.Linq; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Connections; @@ -41,8 +42,9 @@ public ClientBulkWriteOperation( IReadOnlyList writeModels, ClientBulkWriteOptions options, MessageEncoderSettings messageEncoderSettings, - RenderArgs renderArgs) - : base(DatabaseNamespace.Admin, messageEncoderSettings) + RenderArgs renderArgs, + IBsonSerializationDomain serializationDomain) + : base(DatabaseNamespace.Admin, messageEncoderSettings, serializationDomain) { Ensure.IsNotNullOrEmpty(writeModels, nameof(writeModels)); _writeModels = new BatchableSource(writeModels, true); @@ -284,7 +286,8 @@ private IAsyncCursor GetIndividualResultsCursor(RetryableWriteCont 0, 0, BsonDocumentSerializer.Instance, - MessageEncoderSettings); + MessageEncoderSettings, + SerializationDomain); } private void PopulateBulkWriteResponse(BsonDocument bulkWriteResponse, BulkWriteRawResult bulkWriteResult) diff --git a/src/MongoDB.Driver/Core/Operations/CommandOperationBase.cs b/src/MongoDB.Driver/Core/Operations/CommandOperationBase.cs index e5f94ebe200..2b3f10edde4 100644 --- a/src/MongoDB.Driver/Core/Operations/CommandOperationBase.cs +++ b/src/MongoDB.Driver/Core/Operations/CommandOperationBase.cs @@ -33,17 +33,35 @@ internal abstract class CommandOperationBase private DatabaseNamespace _databaseNamespace; private MessageEncoderSettings _messageEncoderSettings; private IBsonSerializer _resultSerializer; + private IBsonSerializationDomain _serializationDomain; protected CommandOperationBase( DatabaseNamespace databaseNamespace, BsonDocument command, IBsonSerializer resultSerializer, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _databaseNamespace = Ensure.IsNotNull(databaseNamespace, nameof(databaseNamespace)); _command = Ensure.IsNotNull(command, nameof(command)); _resultSerializer = Ensure.IsNotNull(resultSerializer, nameof(resultSerializer)); _messageEncoderSettings = messageEncoderSettings; + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + protected CommandOperationBase( + DatabaseNamespace databaseNamespace, + BsonDocument command, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings) + : this( + databaseNamespace, + command, + resultSerializer, + messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain) + { } public BsonDocument AdditionalOptions @@ -100,7 +118,8 @@ protected TCommandResult ExecuteProtocol(OperationContext operationContext, ICha null, // postWriteAction, CommandResponseHandling.Return, _resultSerializer, - _messageEncoderSettings); + _messageEncoderSettings, + _serializationDomain); } protected TCommandResult ExecuteProtocol( @@ -131,7 +150,8 @@ protected Task ExecuteProtocolAsync(OperationContext operationCo null, // postWriteAction, CommandResponseHandling.Return, _resultSerializer, - _messageEncoderSettings); + _messageEncoderSettings, + _serializationDomain); } protected async Task ExecuteProtocolAsync( diff --git a/src/MongoDB.Driver/Core/Operations/CountDocumentsOperation.cs b/src/MongoDB.Driver/Core/Operations/CountDocumentsOperation.cs index 6bcc00d33db..fd3fc747e49 100644 --- a/src/MongoDB.Driver/Core/Operations/CountDocumentsOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/CountDocumentsOperation.cs @@ -17,6 +17,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Events; @@ -38,11 +39,19 @@ internal sealed class CountDocumentsOperation : IReadOperation private ReadConcern _readConcern = ReadConcern.Default; private bool _retryRequested; private long? _skip; + private IBsonSerializationDomain _serializationDomain; - public CountDocumentsOperation(CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings) + public CountDocumentsOperation(CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings, IBsonSerializationDomain serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + public CountDocumentsOperation(CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { } public Collation Collation @@ -140,7 +149,7 @@ public async Task ExecuteAsync(OperationContext operationContext, IReadBin private AggregateOperation CreateOperation() { var pipeline = CreatePipeline(); - var operation = new AggregateOperation(_collectionNamespace, pipeline, BsonDocumentSerializer.Instance, _messageEncoderSettings) + var operation = new AggregateOperation(_collectionNamespace, pipeline, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain) { Collation = _collation, Comment = _comment, diff --git a/src/MongoDB.Driver/Core/Operations/CountOperation.cs b/src/MongoDB.Driver/Core/Operations/CountOperation.cs index 1f19a2063ac..e153f274b4a 100644 --- a/src/MongoDB.Driver/Core/Operations/CountOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/CountOperation.cs @@ -16,6 +16,7 @@ using System; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Connections; @@ -37,12 +38,20 @@ internal sealed class CountOperation : IReadOperation, IExecutableInRetrya private readonly MessageEncoderSettings _messageEncoderSettings; private ReadConcern _readConcern = ReadConcern.Default; private bool _retryRequested; + private IBsonSerializationDomain _serializationDomain; private long? _skip; - public CountOperation(CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings) + public CountOperation(CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings, IBsonSerializationDomain serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + public CountOperation(CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { } public Collation Collation @@ -167,7 +176,7 @@ public async Task ExecuteAsync(OperationContext operationContext, Retryabl private ReadCommandOperation CreateOperation(OperationContext operationContext, RetryableReadContext context) { var command = CreateCommand(operationContext, context.Binding.Session, context.Channel.ConnectionDescription); - return new ReadCommandOperation(_collectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings) + return new ReadCommandOperation(_collectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain) { RetryRequested = _retryRequested // might be overridden by retryable read context }; diff --git a/src/MongoDB.Driver/Core/Operations/CreateCollectionOperation.cs b/src/MongoDB.Driver/Core/Operations/CreateCollectionOperation.cs index a5149725bfa..89760853661 100644 --- a/src/MongoDB.Driver/Core/Operations/CreateCollectionOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/CreateCollectionOperation.cs @@ -16,6 +16,7 @@ using System; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Events; @@ -34,11 +35,13 @@ public static IWriteOperation CreateEncryptedCreateCollectionOpera CollectionNamespace collectionNamespace, BsonDocument encryptedFields, MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain, Action createCollectionOperationConfigurator) { var mainOperation = new CreateCollectionOperation( collectionNamespace, messageEncoderSettings, + serializationDomain, encryptedFields != null ? Feature.Csfle2QEv2 : null) { EncryptedFields = encryptedFields @@ -52,7 +55,7 @@ public static IWriteOperation CreateEncryptedCreateCollectionOpera (CreateInnerCollectionOperation(EncryptedCollectionHelper.GetAdditionalCollectionName(encryptedFields, collectionNamespace, HelperCollectionForEncryption.Esc)), IsMainOperation: false), (CreateInnerCollectionOperation(EncryptedCollectionHelper.GetAdditionalCollectionName(encryptedFields, collectionNamespace, HelperCollectionForEncryption.Ecos)), IsMainOperation: false), (mainOperation, IsMainOperation: true), - (new CreateIndexesOperation(collectionNamespace, new[] { new CreateIndexRequest(EncryptedCollectionHelper.AdditionalCreateIndexDocument) }, messageEncoderSettings), IsMainOperation: false)); + (new CreateIndexesOperation(collectionNamespace, new[] { new CreateIndexRequest(EncryptedCollectionHelper.AdditionalCreateIndexDocument) }, messageEncoderSettings, serializationDomain), IsMainOperation: false)); } else { @@ -60,7 +63,7 @@ public static IWriteOperation CreateEncryptedCreateCollectionOpera } CreateCollectionOperation CreateInnerCollectionOperation(string collectionName) - => new(new CollectionNamespace(collectionNamespace.DatabaseNamespace.DatabaseName, collectionName), messageEncoderSettings, Feature.Csfle2QEv2) + => new(new CollectionNamespace(collectionNamespace.DatabaseNamespace.DatabaseName, collectionName), messageEncoderSettings, serializationDomain, Feature.Csfle2QEv2) { ClusteredIndex = new BsonDocument { { "key", new BsonDocument("_id", 1) }, { "unique", true } } }; @@ -79,6 +82,7 @@ CreateCollectionOperation CreateInnerCollectionOperation(string collectionName) private long? _maxDocuments; private long? _maxSize; private readonly MessageEncoderSettings _messageEncoderSettings; + private readonly IBsonSerializationDomain _serializationDomain; private BsonDocument _storageEngine; private TimeSeriesOptions _timeSeriesOptions; private DocumentValidationAction? _validationAction; @@ -88,21 +92,32 @@ CreateCollectionOperation CreateInnerCollectionOperation(string collectionName) private readonly Feature _supportedFeature; + public CreateCollectionOperation( + CollectionNamespace collectionNamespace, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : this(collectionNamespace, messageEncoderSettings, serializationDomain, supportedFeature: null) + { + } + + //EXIT public CreateCollectionOperation( CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings) - : this(collectionNamespace, messageEncoderSettings, supportedFeature: null) + : this(collectionNamespace, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) { } private CreateCollectionOperation( CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain, Feature supportedFeature) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _messageEncoderSettings = messageEncoderSettings; _supportedFeature = supportedFeature; + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); } public bool? Capped @@ -275,7 +290,7 @@ public async Task ExecuteAsync(OperationContext operationContext, private WriteCommandOperation CreateOperation(OperationContext operationContext, ICoreSessionHandle session) { var command = CreateCommand(operationContext, session); - return new WriteCommandOperation(_collectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings); + return new WriteCommandOperation(_collectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain); } private void EnsureServerIsValid(int maxWireVersion) diff --git a/src/MongoDB.Driver/Core/Operations/CreateIndexesOperation.cs b/src/MongoDB.Driver/Core/Operations/CreateIndexesOperation.cs index 42632d712af..4c66188fd70 100644 --- a/src/MongoDB.Driver/Core/Operations/CreateIndexesOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/CreateIndexesOperation.cs @@ -18,6 +18,7 @@ using System.Linq; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Connections; @@ -35,16 +36,28 @@ internal sealed class CreateIndexesOperation : IWriteOperation private TimeSpan? _maxTime; private readonly MessageEncoderSettings _messageEncoderSettings; private readonly IEnumerable _requests; + private readonly IBsonSerializationDomain _serializationDomain; private WriteConcern _writeConcern = WriteConcern.Acknowledged; public CreateIndexesOperation( CollectionNamespace collectionNamespace, IEnumerable requests, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _requests = Ensure.IsNotNull(requests, nameof(requests)).ToList(); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + public CreateIndexesOperation( + CollectionNamespace collectionNamespace, + IEnumerable requests, + MessageEncoderSettings messageEncoderSettings) + :this(collectionNamespace, requests, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { } public CollectionNamespace CollectionNamespace @@ -137,7 +150,7 @@ private WriteCommandOperation CreateOperation(OperationContext ope var databaseNamespace = _collectionNamespace.DatabaseNamespace; var command = CreateCommand(operationContext, session, connectionDescription); var resultSerializer = BsonDocumentSerializer.Instance; - return new WriteCommandOperation(databaseNamespace, command, resultSerializer, _messageEncoderSettings); + return new WriteCommandOperation(databaseNamespace, command, resultSerializer, _messageEncoderSettings, _serializationDomain); } } } diff --git a/src/MongoDB.Driver/Core/Operations/CreateSearchIndexesOperation.cs b/src/MongoDB.Driver/Core/Operations/CreateSearchIndexesOperation.cs index edc8ae04f77..43210821099 100644 --- a/src/MongoDB.Driver/Core/Operations/CreateSearchIndexesOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/CreateSearchIndexesOperation.cs @@ -17,6 +17,7 @@ using System.Linq; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Events; @@ -34,7 +35,9 @@ internal sealed class CreateSearchIndexesOperation : IWriteOperation _requests; + private readonly IBsonSerializationDomain _serializationDomain; + //FP We should remove all the docs in those internal classes, at least for constructors. // constructors /// /// Initializes a new instance of the class. @@ -42,14 +45,17 @@ internal sealed class CreateSearchIndexesOperation : IWriteOperationThe collection namespace. /// The requests. /// The message encoder settings. + /// public CreateSearchIndexesOperation( CollectionNamespace collectionNamespace, IEnumerable requests, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _requests = Ensure.IsNotNull(requests, nameof(requests)).ToArray(); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); } // public methods @@ -88,7 +94,7 @@ private WriteCommandOperation CreateOperation() { "indexes", new BsonArray(_requests.Select(request => request.CreateIndexDocument())) } }; - return new(_collectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings); + return new(_collectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain); } } } diff --git a/src/MongoDB.Driver/Core/Operations/CreateViewOperation.cs b/src/MongoDB.Driver/Core/Operations/CreateViewOperation.cs index 148d86a2536..a94f1c4c7ca 100644 --- a/src/MongoDB.Driver/Core/Operations/CreateViewOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/CreateViewOperation.cs @@ -17,6 +17,7 @@ using System.Linq; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Connections; @@ -31,6 +32,7 @@ internal sealed class CreateViewOperation : IWriteOperation private readonly DatabaseNamespace _databaseNamespace; private readonly MessageEncoderSettings _messageEncoderSettings; private readonly IReadOnlyList _pipeline; + private readonly IBsonSerializationDomain _serializationDomain; private readonly string _viewName; private readonly string _viewOn; private WriteConcern _writeConcern; @@ -40,13 +42,26 @@ public CreateViewOperation( string viewName, string viewOn, IEnumerable pipeline, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _databaseNamespace = Ensure.IsNotNull(databaseNamespace, nameof(databaseNamespace)); _viewName = Ensure.IsNotNull(viewName, nameof(viewName)); _viewOn = Ensure.IsNotNull(viewOn, nameof(viewOn)); _pipeline = Ensure.IsNotNull(pipeline, nameof(pipeline)).ToList(); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + public CreateViewOperation( + DatabaseNamespace databaseNamespace, + string viewName, + string viewOn, + IEnumerable pipeline, + MessageEncoderSettings messageEncoderSettings) + : this(databaseNamespace, viewName, viewOn, pipeline, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { } public Collation Collation @@ -128,7 +143,7 @@ public BsonDocument CreateCommand(OperationContext operationContext, ICoreSessio private WriteCommandOperation CreateOperation(OperationContext operationContext, ICoreSessionHandle session, ConnectionDescription connectionDescription) { var command = CreateCommand(operationContext, session, connectionDescription); - return new WriteCommandOperation(_databaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings); + return new WriteCommandOperation(_databaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain); } } } diff --git a/src/MongoDB.Driver/Core/Operations/CursorBatchDeserializationHelper.cs b/src/MongoDB.Driver/Core/Operations/CursorBatchDeserializationHelper.cs index 27ff4252dc0..6b5a850e72f 100644 --- a/src/MongoDB.Driver/Core/Operations/CursorBatchDeserializationHelper.cs +++ b/src/MongoDB.Driver/Core/Operations/CursorBatchDeserializationHelper.cs @@ -34,9 +34,10 @@ internal static class CursorBatchDeserializationHelper /// The batch. /// The document serializer. /// The message encoder settings. + /// The serialization domain. /// The documents. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] - public static List DeserializeBatch(RawBsonArray batch, IBsonSerializer documentSerializer, MessageEncoderSettings messageEncoderSettings) + public static List DeserializeBatch(RawBsonArray batch, IBsonSerializer documentSerializer, MessageEncoderSettings messageEncoderSettings, IBsonSerializationDomain serializationDomain) { var documents = new List(); @@ -49,7 +50,7 @@ public static List DeserializeBatch(RawBsonArray batch, IB using (var stream = new ByteBufferStream(batch.Slice, ownsBuffer: false)) using (var reader = new BsonBinaryReader(stream, readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(reader); + var context = BsonDeserializationContext.CreateRoot(reader, serializationDomain); // BSON requires that the top level object be a document, but an array looks close enough to a document that we can pretend it is one reader.ReadStartDocument(); diff --git a/src/MongoDB.Driver/Core/Operations/DatabaseExistsOperation.cs b/src/MongoDB.Driver/Core/Operations/DatabaseExistsOperation.cs index 9b6f4cdca4d..653a04543b3 100644 --- a/src/MongoDB.Driver/Core/Operations/DatabaseExistsOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/DatabaseExistsOperation.cs @@ -15,6 +15,7 @@ using System.Linq; using System.Threading.Tasks; +using MongoDB.Bson.Serialization; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Misc; using MongoDB.Driver.Core.WireProtocol.Messages.Encoders; @@ -26,13 +27,22 @@ internal sealed class DatabaseExistsOperation : IReadOperation private DatabaseNamespace _databaseNamespace; private MessageEncoderSettings _messageEncoderSettings; private bool _retryRequested; + private IBsonSerializationDomain _serializationDomain; - public DatabaseExistsOperation(DatabaseNamespace databaseNamespace, MessageEncoderSettings messageEncoderSettings) + public DatabaseExistsOperation(DatabaseNamespace databaseNamespace, MessageEncoderSettings messageEncoderSettings, IBsonSerializationDomain serializationDomain) { _databaseNamespace = Ensure.IsNotNull(databaseNamespace, nameof(databaseNamespace)); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + // EXIT + public DatabaseExistsOperation(DatabaseNamespace databaseNamespace, MessageEncoderSettings messageEncoderSettings) + : this(databaseNamespace, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { } + public DatabaseNamespace DatabaseNamespace { get { return _databaseNamespace; } @@ -71,7 +81,7 @@ public async Task ExecuteAsync(OperationContext operationContext, IReadBin private ListDatabasesOperation CreateOperation() { - return new ListDatabasesOperation(_messageEncoderSettings) + return new ListDatabasesOperation(_messageEncoderSettings, _serializationDomain) { RetryRequested = _retryRequested }; diff --git a/src/MongoDB.Driver/Core/Operations/DistinctOperation.cs b/src/MongoDB.Driver/Core/Operations/DistinctOperation.cs index a64cee8a13c..6f98fa64539 100644 --- a/src/MongoDB.Driver/Core/Operations/DistinctOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/DistinctOperation.cs @@ -38,14 +38,29 @@ internal sealed class DistinctOperation : IReadOperation _valueSerializer; - public DistinctOperation(CollectionNamespace collectionNamespace, IBsonSerializer valueSerializer, string fieldName, MessageEncoderSettings messageEncoderSettings) + public DistinctOperation(CollectionNamespace collectionNamespace, + IBsonSerializer valueSerializer, + string fieldName, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _valueSerializer = Ensure.IsNotNull(valueSerializer, nameof(valueSerializer)); _fieldName = Ensure.IsNotNullOrEmpty(fieldName, nameof(fieldName)); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + public DistinctOperation(CollectionNamespace collectionNamespace, + IBsonSerializer valueSerializer, + string fieldName, + MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, valueSerializer, fieldName, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { } public Collation Collation @@ -158,7 +173,7 @@ private ReadCommandOperation CreateOperation(OperationContext op var command = CreateCommand(operationContext, context.Binding.Session, context.Channel.ConnectionDescription); var serializer = new DistinctResultDeserializer(_valueSerializer); - return new ReadCommandOperation(_collectionNamespace.DatabaseNamespace, command, serializer, _messageEncoderSettings) + return new ReadCommandOperation(_collectionNamespace.DatabaseNamespace, command, serializer, _messageEncoderSettings, _serializationDomain) { RetryRequested = _retryRequested // might be overridden by retryable read context }; diff --git a/src/MongoDB.Driver/Core/Operations/DropCollectionOperation.cs b/src/MongoDB.Driver/Core/Operations/DropCollectionOperation.cs index 8465a9f42eb..782fd8f8a73 100644 --- a/src/MongoDB.Driver/Core/Operations/DropCollectionOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/DropCollectionOperation.cs @@ -16,6 +16,7 @@ using System; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Events; @@ -34,9 +35,10 @@ public static IWriteOperation CreateEncryptedDropCollectionOperati CollectionNamespace collectionNamespace, BsonDocument encryptedFields, MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain, Action configureDropCollectionConfigurator) { - var mainOperation = new DropCollectionOperation(collectionNamespace, messageEncoderSettings) + var mainOperation = new DropCollectionOperation(collectionNamespace, messageEncoderSettings, serializationDomain) { EncryptedFields = encryptedFields }; @@ -56,21 +58,46 @@ public static IWriteOperation CreateEncryptedDropCollectionOperati } DropCollectionOperation CreateInnerDropOperation(string collectionName) - => new DropCollectionOperation(new CollectionNamespace(collectionNamespace.DatabaseNamespace.DatabaseName, collectionName), messageEncoderSettings); + => new DropCollectionOperation(new CollectionNamespace(collectionNamespace.DatabaseNamespace.DatabaseName, collectionName), messageEncoderSettings, serializationDomain); } + + //EXIT + public static IWriteOperation CreateEncryptedDropCollectionOperationIfConfigured( + CollectionNamespace collectionNamespace, + BsonDocument encryptedFields, + MessageEncoderSettings messageEncoderSettings, + Action configureDropCollectionConfigurator) + => CreateEncryptedDropCollectionOperationIfConfigured( + collectionNamespace, + encryptedFields, + messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain, + configureDropCollectionConfigurator); + #endregion private readonly CollectionNamespace _collectionNamespace; private BsonDocument _encryptedFields; private readonly MessageEncoderSettings _messageEncoderSettings; + private readonly IBsonSerializationDomain _serializationDomain; private WriteConcern _writeConcern; public DropCollectionOperation( CollectionNamespace collectionNamespace, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _messageEncoderSettings = messageEncoderSettings; + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + public DropCollectionOperation( + CollectionNamespace collectionNamespace, + MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { } public CollectionNamespace CollectionNamespace @@ -164,7 +191,7 @@ internal BsonDocument CreateCommand(OperationContext operationContext, ICoreSess private WriteCommandOperation CreateOperation(OperationContext operationContext, ICoreSessionHandle session) { var command = CreateCommand(operationContext, session); - return new WriteCommandOperation(_collectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings); + return new WriteCommandOperation(_collectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain); } private bool ShouldIgnoreException(MongoCommandException ex) diff --git a/src/MongoDB.Driver/Core/Operations/DropDatabaseOperation.cs b/src/MongoDB.Driver/Core/Operations/DropDatabaseOperation.cs index df6f9b1ac71..e4c6d268857 100644 --- a/src/MongoDB.Driver/Core/Operations/DropDatabaseOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/DropDatabaseOperation.cs @@ -16,6 +16,7 @@ using System; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Events; @@ -28,14 +29,25 @@ internal sealed class DropDatabaseOperation : IWriteOperation { private readonly DatabaseNamespace _databaseNamespace; private readonly MessageEncoderSettings _messageEncoderSettings; + private readonly IBsonSerializationDomain _serializationDomain; private WriteConcern _writeConcern; public DropDatabaseOperation( DatabaseNamespace databaseNamespace, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _databaseNamespace = Ensure.IsNotNull(databaseNamespace, nameof(databaseNamespace)); _messageEncoderSettings = messageEncoderSettings; + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + public DropDatabaseOperation( + DatabaseNamespace databaseNamespace, + MessageEncoderSettings messageEncoderSettings) + : this(databaseNamespace, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { } public DatabaseNamespace DatabaseNamespace @@ -97,7 +109,7 @@ public async Task ExecuteAsync(OperationContext operationContext, private WriteCommandOperation CreateOperation(OperationContext operationContext, ICoreSessionHandle session) { var command = CreateCommand(operationContext, session); - return new WriteCommandOperation(_databaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings); + return new WriteCommandOperation(_databaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain); } } } diff --git a/src/MongoDB.Driver/Core/Operations/DropIndexOperation.cs b/src/MongoDB.Driver/Core/Operations/DropIndexOperation.cs index 0c8e2fd8fda..3f7c6dc9a5e 100644 --- a/src/MongoDB.Driver/Core/Operations/DropIndexOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/DropIndexOperation.cs @@ -16,6 +16,7 @@ using System; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Events; @@ -32,23 +33,44 @@ internal sealed class DropIndexOperation : IWriteOperation private TimeSpan? _maxTime; private readonly MessageEncoderSettings _messageEncoderSettings; private WriteConcern _writeConcern; + private readonly IBsonSerializationDomain _serializationDomain; + public DropIndexOperation( + CollectionNamespace collectionNamespace, + BsonDocument keys, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : this(collectionNamespace, IndexNameHelper.GetIndexName(keys), messageEncoderSettings, serializationDomain) + { + } + + //EXIT public DropIndexOperation( CollectionNamespace collectionNamespace, BsonDocument keys, MessageEncoderSettings messageEncoderSettings) - : this(collectionNamespace, IndexNameHelper.GetIndexName(keys), messageEncoderSettings) + : this(collectionNamespace, keys, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) { } public DropIndexOperation( CollectionNamespace collectionNamespace, string indexName, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _indexName = Ensure.IsNotNullOrEmpty(indexName, nameof(indexName)); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + public DropIndexOperation( + CollectionNamespace collectionNamespace, + string indexName, + MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, indexName, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { } public CollectionNamespace CollectionNamespace @@ -156,7 +178,7 @@ public async Task ExecuteAsync(OperationContext operationContext, private WriteCommandOperation CreateOperation(OperationContext operationContext, ICoreSessionHandle session) { var command = CreateCommand(operationContext, session); - return new WriteCommandOperation(_collectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings); + return new WriteCommandOperation(_collectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain); } private bool ShouldIgnoreException(MongoCommandException ex) diff --git a/src/MongoDB.Driver/Core/Operations/DropSearchIndexOperation.cs b/src/MongoDB.Driver/Core/Operations/DropSearchIndexOperation.cs index aff890be381..79ed98a33e4 100644 --- a/src/MongoDB.Driver/Core/Operations/DropSearchIndexOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/DropSearchIndexOperation.cs @@ -15,6 +15,7 @@ using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Events; @@ -32,6 +33,7 @@ internal sealed class DropSearchIndexOperation : IWriteOperation private readonly CollectionNamespace _collectionNamespace; private readonly string _indexName; private readonly MessageEncoderSettings _messageEncoderSettings; + private readonly IBsonSerializationDomain _serializationDomain; // constructors /// @@ -40,14 +42,17 @@ internal sealed class DropSearchIndexOperation : IWriteOperation /// The collection namespace. /// The name of the index. /// The message encoder settings. + /// The serialization domain. public DropSearchIndexOperation( CollectionNamespace collectionNamespace, string indexName, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _indexName = Ensure.IsNotNullOrEmpty(indexName, nameof(indexName)); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); } // methods @@ -59,7 +64,7 @@ private BsonDocument CreateCommand() => }; private WriteCommandOperation CreateOperation() => - new(_collectionNamespace.DatabaseNamespace, CreateCommand(), BsonDocumentSerializer.Instance, _messageEncoderSettings); + new(_collectionNamespace.DatabaseNamespace, CreateCommand(), BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain); /// public BsonDocument Execute(OperationContext operationContext, IWriteBinding binding) diff --git a/src/MongoDB.Driver/Core/Operations/EndTransactionOperation.cs b/src/MongoDB.Driver/Core/Operations/EndTransactionOperation.cs index b4bc0e39171..198bea2155b 100644 --- a/src/MongoDB.Driver/Core/Operations/EndTransactionOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/EndTransactionOperation.cs @@ -16,6 +16,7 @@ using System; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Misc; @@ -28,15 +29,29 @@ internal abstract class EndTransactionOperation : IReadOperation private MessageEncoderSettings _messageEncoderSettings; private readonly BsonDocument _recoveryToken; private readonly WriteConcern _writeConcern; + private IBsonSerializationDomain _serializationDomain; - protected EndTransactionOperation(BsonDocument recoveryToken, WriteConcern writeConcern) + protected EndTransactionOperation(BsonDocument recoveryToken, WriteConcern writeConcern, IBsonSerializationDomain serializationDomain) { _recoveryToken = recoveryToken; _writeConcern = Ensure.IsNotNull(writeConcern, nameof(writeConcern)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + protected EndTransactionOperation(BsonDocument recoveryToken, WriteConcern writeConcern) + : this(recoveryToken, writeConcern, BsonSerializer.DefaultSerializationDomain) + { } + protected EndTransactionOperation(WriteConcern writeConcern, IBsonSerializationDomain serializationDomain) + : this(recoveryToken: null, writeConcern, serializationDomain) + { + } + + //EXIT protected EndTransactionOperation(WriteConcern writeConcern) - : this(recoveryToken: null, writeConcern) + : this(writeConcern, BsonSerializer.DefaultSerializationDomain) { } @@ -95,7 +110,7 @@ protected virtual BsonDocument CreateCommand(OperationContext operationContext) private IReadOperation CreateOperation(OperationContext operationContext) { var command = CreateCommand(operationContext); - return new ReadCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, _messageEncoderSettings) + return new ReadCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain) { RetryRequested = false }; @@ -104,13 +119,25 @@ private IReadOperation CreateOperation(OperationContext operationC internal sealed class AbortTransactionOperation : EndTransactionOperation { + public AbortTransactionOperation(BsonDocument recoveryToken, WriteConcern writeConcern, IBsonSerializationDomain serializationDomain) + : base(recoveryToken, writeConcern, serializationDomain) + { + } + + //EXIT public AbortTransactionOperation(BsonDocument recoveryToken, WriteConcern writeConcern) - : base(recoveryToken, writeConcern) + : this(recoveryToken, writeConcern, BsonSerializer.DefaultSerializationDomain) { } + public AbortTransactionOperation(WriteConcern writeConcern, IBsonSerializationDomain serializationDomain) + : base(writeConcern, serializationDomain) + { + } + + //EXIT public AbortTransactionOperation(WriteConcern writeConcern) - : base(writeConcern) + : this(writeConcern, BsonSerializer.DefaultSerializationDomain) { } @@ -121,16 +148,29 @@ internal sealed class CommitTransactionOperation : EndTransactionOperation { private TimeSpan? _maxCommitTime; + public CommitTransactionOperation(WriteConcern writeConcern, IBsonSerializationDomain serializationDomain) + : base(writeConcern, serializationDomain) + { + } + + //EXIT public CommitTransactionOperation(WriteConcern writeConcern) - : base(writeConcern) + : this(writeConcern, BsonSerializer.DefaultSerializationDomain) { } + public CommitTransactionOperation(BsonDocument recoveryToken, WriteConcern writeConcern, IBsonSerializationDomain serializationDomain) + : base(recoveryToken, writeConcern, serializationDomain) + { + } + + //EXIT public CommitTransactionOperation(BsonDocument recoveryToken, WriteConcern writeConcern) - : base(recoveryToken, writeConcern) + : this(recoveryToken, writeConcern, BsonSerializer.DefaultSerializationDomain) { } + public TimeSpan? MaxCommitTime { get => _maxCommitTime; diff --git a/src/MongoDB.Driver/Core/Operations/EstimatedDocumentCountOperation.cs b/src/MongoDB.Driver/Core/Operations/EstimatedDocumentCountOperation.cs index eac2d1a32a1..9f74b4bd75a 100644 --- a/src/MongoDB.Driver/Core/Operations/EstimatedDocumentCountOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/EstimatedDocumentCountOperation.cs @@ -16,6 +16,7 @@ using System; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Events; using MongoDB.Driver.Core.Misc; @@ -31,11 +32,19 @@ internal sealed class EstimatedDocumentCountOperation : IReadOperation private readonly MessageEncoderSettings _messageEncoderSettings; private ReadConcern _readConcern = ReadConcern.Default; private bool _retryRequested; + private readonly IBsonSerializationDomain _serializationDomain; - public EstimatedDocumentCountOperation(CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings) + public EstimatedDocumentCountOperation(CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings, IBsonSerializationDomain serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + public EstimatedDocumentCountOperation(CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { } public CollectionNamespace CollectionNamespace => _collectionNamespace; @@ -96,7 +105,7 @@ public async Task ExecuteAsync(OperationContext operationContext, IReadBin private IExecutableInRetryableReadContext CreateCountOperation() { - var countOperation = new CountOperation(_collectionNamespace, _messageEncoderSettings) + var countOperation = new CountOperation(_collectionNamespace, _messageEncoderSettings, _serializationDomain) { Comment = _comment, MaxTime = _maxTime, diff --git a/src/MongoDB.Driver/Core/Operations/FindAndModifyOperationBase.cs b/src/MongoDB.Driver/Core/Operations/FindAndModifyOperationBase.cs index 1b346fe013f..4e7143d116a 100644 --- a/src/MongoDB.Driver/Core/Operations/FindAndModifyOperationBase.cs +++ b/src/MongoDB.Driver/Core/Operations/FindAndModifyOperationBase.cs @@ -37,12 +37,17 @@ internal abstract class FindAndModifyOperationBase : IWriteOperation _resultSerializer; private WriteConcern _writeConcern; private bool _retryRequested; + private readonly IBsonSerializationDomain _serializationDomain; - public FindAndModifyOperationBase(CollectionNamespace collectionNamespace, IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings) + public FindAndModifyOperationBase(CollectionNamespace collectionNamespace, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _resultSerializer = Ensure.IsNotNull(resultSerializer, nameof(resultSerializer)); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); } public Collation Collation @@ -157,7 +162,7 @@ public async Task ExecuteAttemptAsync(OperationContext operationContext private WriteCommandOperation CreateOperation(OperationContext operationContext, ICoreSessionHandle session, ConnectionDescription connectionDescription, long? transactionNumber) { var command = CreateCommand(operationContext, session, connectionDescription, transactionNumber); - return new WriteCommandOperation(_collectionNamespace.DatabaseNamespace, command, RawBsonDocumentSerializer.Instance, _messageEncoderSettings) + return new WriteCommandOperation(_collectionNamespace.DatabaseNamespace, command, RawBsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain) { CommandValidator = GetCommandValidator() }; @@ -174,7 +179,7 @@ private TResult ProcessCommandResult(ConnectionId connectionId, RawBsonDocument using (var stream = new ByteBufferStream(rawBsonDocument.Slice, ownsBuffer: false)) using (var reader = new BsonBinaryReader(stream, binaryReaderSettings)) { - var context = BsonDeserializationContext.CreateRoot(reader); + var context = BsonDeserializationContext.CreateRoot(reader, _serializationDomain); return _resultSerializer.Deserialize(context); } } diff --git a/src/MongoDB.Driver/Core/Operations/FindOneAndDeleteOperation.cs b/src/MongoDB.Driver/Core/Operations/FindOneAndDeleteOperation.cs index 7af4bc6b05b..1a18e78472f 100644 --- a/src/MongoDB.Driver/Core/Operations/FindOneAndDeleteOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/FindOneAndDeleteOperation.cs @@ -33,12 +33,23 @@ internal sealed class FindOneAndDeleteOperation : FindAndModifyOperatio private BsonDocument _projection; private BsonDocument _sort; - public FindOneAndDeleteOperation(CollectionNamespace collectionNamespace, BsonDocument filter, IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings) - : base(collectionNamespace, resultSerializer, messageEncoderSettings) + public FindOneAndDeleteOperation(CollectionNamespace collectionNamespace, + BsonDocument filter, IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : base(collectionNamespace, resultSerializer, messageEncoderSettings, serializationDomain) { _filter = Ensure.IsNotNull(filter, nameof(filter)); } + //EXIT + public FindOneAndDeleteOperation(CollectionNamespace collectionNamespace, + BsonDocument filter, IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, filter, resultSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { + } + public BsonDocument Filter { get { return _filter; } diff --git a/src/MongoDB.Driver/Core/Operations/FindOneAndReplaceOperation.cs b/src/MongoDB.Driver/Core/Operations/FindOneAndReplaceOperation.cs index 6ddb3a9df04..08a660a3343 100644 --- a/src/MongoDB.Driver/Core/Operations/FindOneAndReplaceOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/FindOneAndReplaceOperation.cs @@ -37,14 +37,30 @@ internal sealed class FindOneAndReplaceOperation : FindAndModifyOperati private ReturnDocument _returnDocument; private BsonDocument _sort; - public FindOneAndReplaceOperation(CollectionNamespace collectionNamespace, BsonDocument filter, BsonDocument replacement, IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings) - : base(collectionNamespace, resultSerializer, messageEncoderSettings) + public FindOneAndReplaceOperation(CollectionNamespace collectionNamespace, + BsonDocument filter, + BsonDocument replacement, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : base(collectionNamespace, resultSerializer, messageEncoderSettings, serializationDomain) { _filter = Ensure.IsNotNull(filter, nameof(filter)); _replacement = Ensure.IsNotNull(replacement, nameof(replacement)); _returnDocument = ReturnDocument.Before; } + //EXIT + public FindOneAndReplaceOperation(CollectionNamespace collectionNamespace, + BsonDocument filter, + BsonDocument replacement, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, filter, replacement, resultSerializer, messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain) + { + } + public bool? BypassDocumentValidation { get { return _bypassDocumentValidation; } diff --git a/src/MongoDB.Driver/Core/Operations/FindOneAndUpdateOperation.cs b/src/MongoDB.Driver/Core/Operations/FindOneAndUpdateOperation.cs index 7c4281b74f6..73dcfeaa78d 100644 --- a/src/MongoDB.Driver/Core/Operations/FindOneAndUpdateOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/FindOneAndUpdateOperation.cs @@ -40,14 +40,27 @@ internal sealed class FindOneAndUpdateOperation : FindAndModifyOperatio private BsonDocument _sort; private readonly BsonValue _update; - public FindOneAndUpdateOperation(CollectionNamespace collectionNamespace, BsonDocument filter, BsonValue update, IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings) - : base(collectionNamespace, resultSerializer, messageEncoderSettings) + public FindOneAndUpdateOperation(CollectionNamespace collectionNamespace, + BsonDocument filter, BsonValue update, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : base(collectionNamespace, resultSerializer, messageEncoderSettings, serializationDomain) { _filter = Ensure.IsNotNull(filter, nameof(filter)); _update = EnsureUpdateIsValid(update); _returnDocument = ReturnDocument.Before; } + //EXIT + public FindOneAndUpdateOperation(CollectionNamespace collectionNamespace, + BsonDocument filter, BsonValue update, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, filter, update, resultSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { + } + public IEnumerable ArrayFilters { get { return _arrayFilters; } diff --git a/src/MongoDB.Driver/Core/Operations/FindOperation.cs b/src/MongoDB.Driver/Core/Operations/FindOperation.cs index 82fa1a31c9f..c9a4a30de26 100644 --- a/src/MongoDB.Driver/Core/Operations/FindOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/FindOperation.cs @@ -61,6 +61,7 @@ internal sealed class FindOperation : IReadOperation _resultSerializer; private bool _retryRequested; private bool? _returnKey; + private IBsonSerializationDomain _serializationDomain; private bool? _showRecordId; private bool? _singleBatch; private int? _skip; @@ -69,14 +70,26 @@ internal sealed class FindOperation : IReadOperation resultSerializer, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _resultSerializer = Ensure.IsNotNull(resultSerializer, nameof(resultSerializer)); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = serializationDomain ?? BsonSerializer.DefaultSerializationDomain; _cursorType = CursorType.NonTailable; } + //EXIT + public FindOperation( + CollectionNamespace collectionNamespace, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, resultSerializer, messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain) + { + } + public bool? AllowDiskUse { get { return _allowDiskUse; } @@ -348,6 +361,7 @@ private AsyncCursor CreateCursor(IChannelSourceHandle channelSource, _limit < 0 ? Math.Abs(_limit.Value) : _limit, _resultSerializer, _messageEncoderSettings, + _serializationDomain, _cursorType == CursorType.TailableAwait ? _maxAwaitTime : null); } @@ -358,7 +372,7 @@ private CursorBatch CreateFirstCursorBatch(BsonDocument cursorDocumen using (batch) { - var documents = CursorBatchDeserializationHelper.DeserializeBatch(batch, _resultSerializer, _messageEncoderSettings); + var documents = CursorBatchDeserializationHelper.DeserializeBatch(batch, _resultSerializer, _messageEncoderSettings, _serializationDomain); return new CursorBatch(cursorId, documents); } } @@ -372,7 +386,8 @@ private ReadCommandOperation CreateOperation(OperationContext oper _collectionNamespace.DatabaseNamespace, command, __findCommandResultSerializer, - _messageEncoderSettings) + _messageEncoderSettings, + _serializationDomain) { RetryRequested = _retryRequested // might be overridden by retryable read context }; diff --git a/src/MongoDB.Driver/Core/Operations/ListCollectionsOperation.cs b/src/MongoDB.Driver/Core/Operations/ListCollectionsOperation.cs index 320c1c3ea71..7e9913b8624 100644 --- a/src/MongoDB.Driver/Core/Operations/ListCollectionsOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/ListCollectionsOperation.cs @@ -17,6 +17,7 @@ using System.Linq; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Events; @@ -35,13 +36,24 @@ internal sealed class ListCollectionsOperation : IReadOperation CreateOperation() { "authorizedCollections", () => _authorizedCollections.Value, _authorizedCollections.HasValue }, { "comment", _comment, _comment != null } }; - return new ReadCommandOperation(_databaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings) + return new ReadCommandOperation(_databaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain) { RetryRequested = _retryRequested // might be overridden by retryable read context }; @@ -173,7 +185,8 @@ private IAsyncCursor CreateCursor(IChannelSourceHandle channelSour batchSize: _batchSize ?? 0, 0, BsonDocumentSerializer.Instance, - _messageEncoderSettings); + _messageEncoderSettings, + _serializationDomain); return cursor; } diff --git a/src/MongoDB.Driver/Core/Operations/ListDatabasesOperation.cs b/src/MongoDB.Driver/Core/Operations/ListDatabasesOperation.cs index e55151e5b5c..81fe21a4690 100644 --- a/src/MongoDB.Driver/Core/Operations/ListDatabasesOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/ListDatabasesOperation.cs @@ -17,6 +17,7 @@ using System.Linq; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Events; @@ -33,12 +34,21 @@ internal sealed class ListDatabasesOperation : IReadOperation CreateCursor(BsonDocument reply) private ReadCommandOperation CreateOperation() { var command = CreateCommand(); - return new ReadCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, _messageEncoderSettings) + return new ReadCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain) { RetryRequested = _retryRequested }; diff --git a/src/MongoDB.Driver/Core/Operations/ListIndexesOperation.cs b/src/MongoDB.Driver/Core/Operations/ListIndexesOperation.cs index b91633c4716..3c3777db58d 100644 --- a/src/MongoDB.Driver/Core/Operations/ListIndexesOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/ListIndexesOperation.cs @@ -16,6 +16,7 @@ using System; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Events; using MongoDB.Driver.Core.Misc; @@ -30,13 +31,24 @@ internal sealed class ListIndexesOperation : IReadOperation> ExecuteAsync(OperationContext oper private IExecutableInRetryableReadContext> CreateOperation() { - return new ListIndexesUsingCommandOperation(_collectionNamespace, _messageEncoderSettings) + return new ListIndexesUsingCommandOperation(_collectionNamespace, _messageEncoderSettings, _serializationDomain) { BatchSize = _batchSize, Comment = _comment, diff --git a/src/MongoDB.Driver/Core/Operations/ListIndexesUsingCommandOperation.cs b/src/MongoDB.Driver/Core/Operations/ListIndexesUsingCommandOperation.cs index 290bbbf00e5..3607b973d25 100644 --- a/src/MongoDB.Driver/Core/Operations/ListIndexesUsingCommandOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/ListIndexesUsingCommandOperation.cs @@ -17,6 +17,7 @@ using System.Linq; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Events; @@ -32,13 +33,24 @@ internal sealed class ListIndexesUsingCommandOperation : IReadOperation CreateOperation() { "cursor", () => new BsonDocument("batchSize", _batchSize.Value), _batchSize.HasValue }, { "comment", _comment, _comment != null }, }; - return new ReadCommandOperation(databaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings) + return new ReadCommandOperation(databaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain) { RetryRequested = _retryRequested // might be overridden by retryable read context }; @@ -156,7 +168,8 @@ private IAsyncCursor CreateCursor(IChannelSourceHandle channelSour batchSize: _batchSize ?? 0, 0, BsonDocumentSerializer.Instance, - _messageEncoderSettings); + _messageEncoderSettings, + _serializationDomain); return cursor; } diff --git a/src/MongoDB.Driver/Core/Operations/MapReduceOperation.cs b/src/MongoDB.Driver/Core/Operations/MapReduceOperation.cs index 21f2a99d684..9ff9355922b 100644 --- a/src/MongoDB.Driver/Core/Operations/MapReduceOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/MapReduceOperation.cs @@ -35,6 +35,7 @@ internal sealed class MapReduceOperation : MapReduceOperationBase, IRea // fields private ReadConcern _readConcern = ReadConcern.Default; private readonly IBsonSerializer _resultSerializer; + private readonly IBsonSerializationDomain _serializationDomain; // constructors /// @@ -45,7 +46,12 @@ internal sealed class MapReduceOperation : MapReduceOperationBase, IRea /// The reduce function. /// The result serializer. /// The message encoder settings. - public MapReduceOperation(CollectionNamespace collectionNamespace, BsonJavaScript mapFunction, BsonJavaScript reduceFunction, IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings) + /// The serialization domain. + public MapReduceOperation(CollectionNamespace collectionNamespace, + BsonJavaScript mapFunction, BsonJavaScript reduceFunction, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) : base( collectionNamespace, mapFunction, @@ -53,6 +59,22 @@ public MapReduceOperation(CollectionNamespace collectionNamespace, BsonJavaScrip messageEncoderSettings) { _resultSerializer = Ensure.IsNotNull(resultSerializer, nameof(resultSerializer)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + public MapReduceOperation(CollectionNamespace collectionNamespace, + BsonJavaScript mapFunction, BsonJavaScript reduceFunction, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings) + : this( + collectionNamespace, + mapFunction, + reduceFunction, + resultSerializer, + messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain) + { } // properties @@ -135,7 +157,7 @@ private ReadCommandOperation CreateOperation(OperationContext operati var command = CreateCommand(operationContext, session, connectionDescription); var resultArraySerializer = new ArraySerializer(_resultSerializer); var resultSerializer = new ElementDeserializer("results", resultArraySerializer); - return new ReadCommandOperation(CollectionNamespace.DatabaseNamespace, command, resultSerializer, MessageEncoderSettings) + return new ReadCommandOperation(CollectionNamespace.DatabaseNamespace, command, resultSerializer, MessageEncoderSettings, _serializationDomain) { RetryRequested = false }; diff --git a/src/MongoDB.Driver/Core/Operations/MapReduceOutputToCollectionOperation.cs b/src/MongoDB.Driver/Core/Operations/MapReduceOutputToCollectionOperation.cs index 475b628a8e2..e698bcbef82 100644 --- a/src/MongoDB.Driver/Core/Operations/MapReduceOutputToCollectionOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/MapReduceOutputToCollectionOperation.cs @@ -16,6 +16,7 @@ using System; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Connections; @@ -35,6 +36,7 @@ internal sealed class MapReduceOutputToCollectionOperation : MapReduceOperationB private bool? _nonAtomicOutput; private readonly CollectionNamespace _outputCollectionNamespace; private MapReduceOutputMode _outputMode; + private IBsonSerializationDomain _serializationDomain; private bool? _shardedOutput; private WriteConcern _writeConcern; @@ -47,12 +49,14 @@ internal sealed class MapReduceOutputToCollectionOperation : MapReduceOperationB /// The map function. /// The reduce function. /// The message encoder settings. + /// The serialization domain public MapReduceOutputToCollectionOperation( CollectionNamespace collectionNamespace, CollectionNamespace outputCollectionNamespace, BsonJavaScript mapFunction, BsonJavaScript reduceFunction, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) : base( collectionNamespace, mapFunction, @@ -60,9 +64,27 @@ public MapReduceOutputToCollectionOperation( messageEncoderSettings) { _outputCollectionNamespace = Ensure.IsNotNull(outputCollectionNamespace, nameof(outputCollectionNamespace)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); _outputMode = MapReduceOutputMode.Replace; } + //EXIT + public MapReduceOutputToCollectionOperation( + CollectionNamespace collectionNamespace, + CollectionNamespace outputCollectionNamespace, + BsonJavaScript mapFunction, + BsonJavaScript reduceFunction, + MessageEncoderSettings messageEncoderSettings) + : this( + collectionNamespace, + outputCollectionNamespace, + mapFunction, + reduceFunction, + messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain) + { + } + // properties /// /// Gets or sets a value indicating whether to bypass document validation. @@ -199,7 +221,7 @@ public async Task ExecuteAsync(OperationContext operationContext, private WriteCommandOperation CreateOperation(OperationContext operationContext, ICoreSessionHandle session, ConnectionDescription connectionDescription) { var command = CreateCommand(operationContext, session, connectionDescription); - return new WriteCommandOperation(CollectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, MessageEncoderSettings); + return new WriteCommandOperation(CollectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, MessageEncoderSettings, _serializationDomain); } } } diff --git a/src/MongoDB.Driver/Core/Operations/ReadCommandOperation.cs b/src/MongoDB.Driver/Core/Operations/ReadCommandOperation.cs index 711d31c37df..88ce4c20a2b 100644 --- a/src/MongoDB.Driver/Core/Operations/ReadCommandOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/ReadCommandOperation.cs @@ -27,12 +27,24 @@ internal sealed class ReadCommandOperation : CommandOperationBas { private bool _retryRequested; + public ReadCommandOperation( + DatabaseNamespace databaseNamespace, + BsonDocument command, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : base(databaseNamespace, command, resultSerializer, messageEncoderSettings, serializationDomain) + { + } + + //EXIT public ReadCommandOperation( DatabaseNamespace databaseNamespace, BsonDocument command, IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings) - : base(databaseNamespace, command, resultSerializer, messageEncoderSettings) + : this(databaseNamespace, command, resultSerializer, messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain) { } diff --git a/src/MongoDB.Driver/Core/Operations/RenameCollectionOperation.cs b/src/MongoDB.Driver/Core/Operations/RenameCollectionOperation.cs index c9b37f6cc02..6e17bd5360b 100644 --- a/src/MongoDB.Driver/Core/Operations/RenameCollectionOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/RenameCollectionOperation.cs @@ -1,4 +1,4 @@ -/* Copyright 2010-present MongoDB Inc. +/* Copyright 2013-present MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ using System; using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Connections; @@ -31,16 +32,29 @@ internal sealed class RenameCollectionOperation : IWriteOperation private bool? _dropTarget; private readonly MessageEncoderSettings _messageEncoderSettings; private readonly CollectionNamespace _newCollectionNamespace; + private readonly IBsonSerializationDomain _serializationDomain; private WriteConcern _writeConcern; public RenameCollectionOperation( CollectionNamespace collectionNamespace, CollectionNamespace newCollectionNamespace, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _newCollectionNamespace = Ensure.IsNotNull(newCollectionNamespace, nameof(newCollectionNamespace)); _messageEncoderSettings = messageEncoderSettings; + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + public RenameCollectionOperation( + CollectionNamespace collectionNamespace, + CollectionNamespace newCollectionNamespace, + MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, newCollectionNamespace, messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain) + { } public CollectionNamespace CollectionNamespace @@ -115,7 +129,7 @@ public async Task ExecuteAsync(OperationContext operationContext, private WriteCommandOperation CreateOperation(OperationContext operationContext, ICoreSessionHandle session, ConnectionDescription connectionDescription) { var command = CreateCommand(operationContext, session, connectionDescription); - return new WriteCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, _messageEncoderSettings); + return new WriteCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain); } } } diff --git a/src/MongoDB.Driver/Core/Operations/RetryableDeleteCommandOperation.cs b/src/MongoDB.Driver/Core/Operations/RetryableDeleteCommandOperation.cs index 53596ce2af4..8b307a07639 100644 --- a/src/MongoDB.Driver/Core/Operations/RetryableDeleteCommandOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/RetryableDeleteCommandOperation.cs @@ -37,13 +37,23 @@ internal sealed class RetryableDeleteCommandOperation : RetryableWriteCommandOpe public RetryableDeleteCommandOperation( CollectionNamespace collectionNamespace, BatchableSource deletes, - MessageEncoderSettings messageEncoderSettings) - : base(Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)).DatabaseNamespace, messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : base(Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)).DatabaseNamespace, messageEncoderSettings, serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _deletes = Ensure.IsNotNull(deletes, nameof(deletes)); } + //EXIT + public RetryableDeleteCommandOperation( + CollectionNamespace collectionNamespace, + BatchableSource deletes, + MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, deletes, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { + } + public BsonDocument Let { get { return _let; } diff --git a/src/MongoDB.Driver/Core/Operations/RetryableInsertCommandOperation.cs b/src/MongoDB.Driver/Core/Operations/RetryableInsertCommandOperation.cs index cd4b5f696b6..c97157307b9 100644 --- a/src/MongoDB.Driver/Core/Operations/RetryableInsertCommandOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/RetryableInsertCommandOperation.cs @@ -37,14 +37,26 @@ public RetryableInsertCommandOperation( CollectionNamespace collectionNamespace, BatchableSource documents, IBsonSerializer documentSerializer, - MessageEncoderSettings messageEncoderSettings) - : base(Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)).DatabaseNamespace, messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : base(Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)).DatabaseNamespace, messageEncoderSettings, serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _documents = Ensure.IsNotNull(documents, nameof(documents)); _documentSerializer = Ensure.IsNotNull(documentSerializer, nameof(documentSerializer)); } + //EXIT + public RetryableInsertCommandOperation( + CollectionNamespace collectionNamespace, + BatchableSource documents, + IBsonSerializer documentSerializer, + MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, documents, documentSerializer, messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain) + { + } + public bool? BypassDocumentValidation { get { return _bypassDocumentValidation; } @@ -139,7 +151,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati { if (_cachedSerializer.ValueType != actualType) { - _cachedSerializer = BsonSerializer.LookupSerializer(actualType); + _cachedSerializer = context.SerializationDomain.LookupSerializer(actualType); } serializer = _cachedSerializer; } diff --git a/src/MongoDB.Driver/Core/Operations/RetryableUpdateCommandOperation.cs b/src/MongoDB.Driver/Core/Operations/RetryableUpdateCommandOperation.cs index d7c390e45be..ceb651e7843 100644 --- a/src/MongoDB.Driver/Core/Operations/RetryableUpdateCommandOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/RetryableUpdateCommandOperation.cs @@ -38,13 +38,23 @@ internal sealed class RetryableUpdateCommandOperation : RetryableWriteCommandOpe public RetryableUpdateCommandOperation( CollectionNamespace collectionNamespace, BatchableSource updates, - MessageEncoderSettings messageEncoderSettings) - : base(Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)).DatabaseNamespace, messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : base(Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)).DatabaseNamespace, messageEncoderSettings, serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _updates = Ensure.IsNotNull(updates, nameof(updates)); } + //EXIT + public RetryableUpdateCommandOperation( + CollectionNamespace collectionNamespace, + BatchableSource updates, + MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, updates, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { + } + public bool? BypassDocumentValidation { get { return _bypassDocumentValidation; } diff --git a/src/MongoDB.Driver/Core/Operations/RetryableWriteCommandOperationBase.cs b/src/MongoDB.Driver/Core/Operations/RetryableWriteCommandOperationBase.cs index fab21530060..270f51c74e2 100644 --- a/src/MongoDB.Driver/Core/Operations/RetryableWriteCommandOperationBase.cs +++ b/src/MongoDB.Driver/Core/Operations/RetryableWriteCommandOperationBase.cs @@ -19,6 +19,7 @@ using System.Threading.Tasks; using MongoDB.Bson; using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Misc; @@ -36,14 +37,17 @@ internal abstract class RetryableWriteCommandOperationBase : IWriteOperation _serializationDomain; + public WriteConcern WriteConcern { get { return _writeConcern; } @@ -127,12 +133,15 @@ public BsonDocument ExecuteAttempt(OperationContext operationContext, RetryableW args.PostWriteAction, args.ResponseHandling, BsonDocumentSerializer.Instance, - args.MessageEncoderSettings); + args.MessageEncoderSettings, + _serializationDomain); } public Task ExecuteAttemptAsync(OperationContext operationContext, RetryableWriteContext context, int attempt, long? transactionNumber) { var args = GetCommandArgs(operationContext, context, attempt, transactionNumber); + var serializationDomain = args.MessageEncoderSettings.GetOrDefault( + MessageEncoderSettingsName.SerializationDomain, BsonSerializer.DefaultSerializationDomain); return context.Channel.CommandAsync( operationContext, context.ChannelSource.Session, @@ -145,7 +154,8 @@ public Task ExecuteAttemptAsync(OperationContext operationContext, args.PostWriteAction, args.ResponseHandling, BsonDocumentSerializer.Instance, - args.MessageEncoderSettings); + args.MessageEncoderSettings, + serializationDomain); } protected abstract BsonDocument CreateCommand(OperationContext operationContext, ICoreSessionHandle session, int attempt, long? transactionNumber); diff --git a/src/MongoDB.Driver/Core/Operations/UpdateSearchIndexOperation.cs b/src/MongoDB.Driver/Core/Operations/UpdateSearchIndexOperation.cs index 09496dd9d3b..9df572313c6 100644 --- a/src/MongoDB.Driver/Core/Operations/UpdateSearchIndexOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/UpdateSearchIndexOperation.cs @@ -15,6 +15,7 @@ using System.Threading.Tasks; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Events; @@ -30,17 +31,20 @@ internal sealed class UpdateSearchIndexOperation : IWriteOperation private readonly MessageEncoderSettings _messageEncoderSettings; private readonly string _indexName; private readonly BsonDocument _definition; + private readonly IBsonSerializationDomain _serializationDomain; public UpdateSearchIndexOperation( CollectionNamespace collectionNamespace, string indexName, BsonDocument definition, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { _collectionNamespace = Ensure.IsNotNull(collectionNamespace, nameof(collectionNamespace)); _indexName = Ensure.IsNotNullOrEmpty(indexName , nameof(indexName)); _definition = Ensure.IsNotNull(definition, nameof(definition)); _messageEncoderSettings = Ensure.IsNotNull(messageEncoderSettings, nameof(messageEncoderSettings)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); } public BsonDocument Execute(OperationContext operationContext, IWriteBinding binding) @@ -76,7 +80,7 @@ private WriteCommandOperation CreateOperation() { "definition", _definition } }; - return new (_collectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings); + return new (_collectionNamespace.DatabaseNamespace, command, BsonDocumentSerializer.Instance, _messageEncoderSettings, _serializationDomain); } } } diff --git a/src/MongoDB.Driver/Core/Operations/WriteCommandOperation.cs b/src/MongoDB.Driver/Core/Operations/WriteCommandOperation.cs index 033db2d0eae..87ed016d0c0 100644 --- a/src/MongoDB.Driver/Core/Operations/WriteCommandOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/WriteCommandOperation.cs @@ -27,8 +27,21 @@ internal sealed class WriteCommandOperation : CommandOperationBa { private ReadPreference _readPreference = ReadPreference.Primary; - public WriteCommandOperation(DatabaseNamespace databaseNamespace, BsonDocument command, IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings) - : base(databaseNamespace, command, resultSerializer, messageEncoderSettings) + public WriteCommandOperation(DatabaseNamespace databaseNamespace, + BsonDocument command, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) + : base(databaseNamespace, command, resultSerializer, messageEncoderSettings, serializationDomain) + { + } + + //EXIT + public WriteCommandOperation(DatabaseNamespace databaseNamespace, + BsonDocument command, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings) + : this(databaseNamespace, command, resultSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) { } diff --git a/src/MongoDB.Driver/Core/Servers/ServerChannel.cs b/src/MongoDB.Driver/Core/Servers/ServerChannel.cs index bf0ce569e87..5e767db5d7d 100644 --- a/src/MongoDB.Driver/Core/Servers/ServerChannel.cs +++ b/src/MongoDB.Driver/Core/Servers/ServerChannel.cs @@ -63,7 +63,8 @@ public TResult Command( Action postWriteAction, CommandResponseHandling responseHandling, IBsonSerializer resultSerializer, - MessageEncoderSettings messageEncoderSettings) + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { var roundTripTime = TimeSpan.Zero; if (_server is ISelectedServer selectedServer) @@ -84,12 +85,14 @@ public TResult Command( resultSerializer, messageEncoderSettings, _server.ServerApi, - roundTripTime); + roundTripTime, + serializationDomain); return ExecuteProtocol(operationContext, protocol, session); } - public Task CommandAsync( + //EXIT + public TResult Command( OperationContext operationContext, ICoreSession session, ReadPreference readPreference, @@ -102,6 +105,35 @@ public Task CommandAsync( CommandResponseHandling responseHandling, IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings) + => Command( + operationContext, + session, + readPreference, + databaseNamespace, + command, + commandPayloads, + commandValidator, + additionalOptions, + postWriteAction, + responseHandling, + resultSerializer, + messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain); + + public Task CommandAsync( + OperationContext operationContext, + ICoreSession session, + ReadPreference readPreference, + DatabaseNamespace databaseNamespace, + BsonDocument command, + IEnumerable commandPayloads, + IElementNameValidator commandValidator, + BsonDocument additionalOptions, + Action postWriteAction, + CommandResponseHandling responseHandling, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + IBsonSerializationDomain serializationDomain) { var roundTripTime = TimeSpan.Zero; if (_server is ISelectedServer selectedServer) @@ -122,11 +154,40 @@ public Task CommandAsync( resultSerializer, messageEncoderSettings, _server.ServerApi, - roundTripTime); + roundTripTime, + serializationDomain); return ExecuteProtocolAsync(operationContext, protocol, session); } + public Task CommandAsync( + OperationContext operationContext, + ICoreSession session, + ReadPreference readPreference, + DatabaseNamespace databaseNamespace, + BsonDocument command, + IEnumerable commandPayloads, + IElementNameValidator commandValidator, + BsonDocument additionalOptions, + Action postWriteAction, + CommandResponseHandling responseHandling, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings) + => CommandAsync( + operationContext, + session, + readPreference, + databaseNamespace, + command, + commandPayloads, + commandValidator, + additionalOptions, + postWriteAction, + responseHandling, + resultSerializer, + messageEncoderSettings, + BsonSerializer.DefaultSerializationDomain); + public void Dispose() { if (_state.TryChange(ChannelState.Initial, ChannelState.Disposed)) diff --git a/src/MongoDB.Driver/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs b/src/MongoDB.Driver/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs index 4b7af6b7209..eb709fbe3fd 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/CommandUsingCommandMessageWireProtocol.cs @@ -51,6 +51,7 @@ internal sealed class CommandUsingCommandMessageWireProtocol : I private readonly ServerApi _serverApi; private readonly TimeSpan _roundTripTime; private readonly ICoreSession _session; + private readonly IBsonSerializationDomain _serializationDomain; // streamable fields private bool _moreToCome = false; // MoreToCome from the previous response private int _previousRequestId; // RequestId from the previous response @@ -69,7 +70,8 @@ public CommandUsingCommandMessageWireProtocol( MessageEncoderSettings messageEncoderSettings, Action postWriteAction, ServerApi serverApi, - TimeSpan roundTripTime) + TimeSpan roundTripTime, + IBsonSerializationDomain serializationDomain) { if (responseHandling != CommandResponseHandling.Return && responseHandling != CommandResponseHandling.NoResponseExpected && @@ -91,6 +93,7 @@ public CommandUsingCommandMessageWireProtocol( _postWriteAction = postWriteAction; // can be null _serverApi = serverApi; // can be null _roundTripTime = roundTripTime; + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); if (messageEncoderSettings != null) { @@ -536,7 +539,7 @@ private TCommandResult ProcessResponse(ConnectionId connectionId, CommandMessage { using (var reader = new BsonBinaryReader(stream, binaryReaderSettings)) { - var context = BsonDeserializationContext.CreateRoot(reader); + var context = BsonDeserializationContext.CreateRoot(reader, _serializationDomain); return _resultSerializer.Deserialize(context); } } diff --git a/src/MongoDB.Driver/Core/WireProtocol/CommandUsingQueryMessageWireProtocol.cs b/src/MongoDB.Driver/Core/WireProtocol/CommandUsingQueryMessageWireProtocol.cs index ecfb53f0f70..feaa20cee41 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/CommandUsingQueryMessageWireProtocol.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/CommandUsingQueryMessageWireProtocol.cs @@ -49,6 +49,7 @@ internal sealed class CommandUsingQueryMessageWireProtocol : IWi private readonly IBsonSerializer _resultSerializer; private readonly ServerApi _serverApi; private readonly ICoreSession _session; + private readonly IBsonSerializationDomain _serializationDomain; // constructors public CommandUsingQueryMessageWireProtocol( @@ -63,7 +64,8 @@ public CommandUsingQueryMessageWireProtocol( IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings, Action postWriteAction, - ServerApi serverApi) + ServerApi serverApi, + IBsonSerializationDomain serializationDomain) { if (responseHandling != CommandResponseHandling.Return && responseHandling != CommandResponseHandling.Ignore) { @@ -82,6 +84,7 @@ public CommandUsingQueryMessageWireProtocol( _messageEncoderSettings = messageEncoderSettings; _postWriteAction = postWriteAction; // can be null _serverApi = serverApi; // can be null + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); } // public properties @@ -326,7 +329,7 @@ private TCommandResult ProcessReply(ConnectionId connectionId, ReplyMessage)encoderFactory.GetReplyMessageEncoder(_resultSerializer); using (var reader = encoder.CreateBinaryReader()) { - var context = BsonDeserializationContext.CreateRoot(reader); + var context = BsonDeserializationContext.CreateRoot(reader, _serializationDomain); return _resultSerializer.Deserialize(context); } } diff --git a/src/MongoDB.Driver/Core/WireProtocol/CommandWireProtocol.cs b/src/MongoDB.Driver/Core/WireProtocol/CommandWireProtocol.cs index 3871fdddca8..ec849835326 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/CommandWireProtocol.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/CommandWireProtocol.cs @@ -46,6 +46,7 @@ internal sealed class CommandWireProtocol : IWireProtocol resultSerializer, MessageEncoderSettings messageEncoderSettings, - ServerApi serverApi) + ServerApi serverApi, + IBsonSerializationDomain serializationDomain) : this( databaseNamespace, command, @@ -62,18 +64,39 @@ public CommandWireProtocol( CommandResponseHandling.Return, resultSerializer, messageEncoderSettings, - serverApi) + serverApi, + serializationDomain) { } + //EXIT public CommandWireProtocol( DatabaseNamespace databaseNamespace, BsonDocument command, bool secondaryOk, - CommandResponseHandling commandResponseHandling, IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings, ServerApi serverApi) + : this( + databaseNamespace, + command, + secondaryOk, + resultSerializer, + messageEncoderSettings, + serverApi, + BsonSerializer.DefaultSerializationDomain) + { + } + + public CommandWireProtocol( + DatabaseNamespace databaseNamespace, + BsonDocument command, + bool secondaryOk, + CommandResponseHandling commandResponseHandling, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + ServerApi serverApi, + IBsonSerializationDomain serializationDomain) : this( NoCoreSession.Instance, secondaryOk ? ReadPreference.PrimaryPreferred : ReadPreference.Primary, @@ -87,7 +110,29 @@ public CommandWireProtocol( resultSerializer, messageEncoderSettings, serverApi, - roundTripTime: TimeSpan.Zero) + roundTripTime: TimeSpan.Zero, + serializationDomain) + { + } + + //EXIT + public CommandWireProtocol( + DatabaseNamespace databaseNamespace, + BsonDocument command, + bool secondaryOk, + CommandResponseHandling commandResponseHandling, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + ServerApi serverApi) + : this( + databaseNamespace, + command, + secondaryOk, + commandResponseHandling, + resultSerializer, + messageEncoderSettings, + serverApi, + BsonSerializer.DefaultSerializationDomain) { } @@ -104,7 +149,8 @@ public CommandWireProtocol( IBsonSerializer resultSerializer, MessageEncoderSettings messageEncoderSettings, ServerApi serverApi, - TimeSpan roundTripTime) + TimeSpan roundTripTime, + IBsonSerializationDomain serializationDomain) { if (responseHandling != CommandResponseHandling.Return && responseHandling != CommandResponseHandling.NoResponseExpected && @@ -126,6 +172,40 @@ public CommandWireProtocol( _postWriteAction = postWriteAction; // can be null _serverApi = serverApi; // can be null _roundTripTime = roundTripTime; + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); + } + + //EXIT + public CommandWireProtocol( + ICoreSession session, + ReadPreference readPreference, + DatabaseNamespace databaseNamespace, + BsonDocument command, + IEnumerable commandPayloads, + IElementNameValidator commandValidator, + BsonDocument additionalOptions, + Action postWriteAction, + CommandResponseHandling responseHandling, + IBsonSerializer resultSerializer, + MessageEncoderSettings messageEncoderSettings, + ServerApi serverApi, + TimeSpan roundTripTime) + : this( + session, + readPreference, + databaseNamespace, + command, + commandPayloads, + commandValidator, + additionalOptions, + postWriteAction, + responseHandling, + resultSerializer, + messageEncoderSettings, + serverApi, + roundTripTime, + BsonSerializer.DefaultSerializationDomain) + { } // public properties @@ -160,7 +240,8 @@ private IWireProtocol CreateCommandUsingCommandMessageWireProtoc _messageEncoderSettings, _postWriteAction, _serverApi, - _roundTripTime); + _roundTripTime, + _serializationDomain); } private IWireProtocol CreateCommandUsingQueryMessageWireProtocol() @@ -179,7 +260,8 @@ private IWireProtocol CreateCommandUsingQueryMessageWireProtocol _resultSerializer, _messageEncoderSettings, _postWriteAction, - _serverApi); + _serverApi, + _serializationDomain); } private IWireProtocol CreateSupportedWireProtocol(IConnection connection) diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ClientBulkWriteOpsSectionFormatter.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ClientBulkWriteOpsSectionFormatter.cs index 353f45dab5e..b1478d40e7b 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ClientBulkWriteOpsSectionFormatter.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ClientBulkWriteOpsSectionFormatter.cs @@ -31,11 +31,11 @@ internal sealed class ClientBulkWriteOpsSectionFormatter : ICommandMessageSectio private readonly Dictionary _nsInfos; private MemoryStream _nsInfoMemoryStream; private BsonBinaryWriter _nsInfoWriter; - private IBsonSerializerRegistry _serializerRegistry; + private IBsonSerializationDomain _serializationDomain; private Dictionary _idsMap; private int _currentIndex; - public ClientBulkWriteOpsSectionFormatter(long? maxSize) + public ClientBulkWriteOpsSectionFormatter(long? maxSize, IBsonSerializationDomain serializationDomain) { _maxSize = (maxSize ?? long.MaxValue) - 1000; // according to spec we should leave some extra space for further overhead if (_maxSize <= 0) @@ -46,6 +46,7 @@ public ClientBulkWriteOpsSectionFormatter(long? maxSize) _nsInfos = new Dictionary(); _nsInfoMemoryStream = new MemoryStream(); _nsInfoWriter = new BsonBinaryWriter(_nsInfoMemoryStream); + _serializationDomain = serializationDomain; } public void Dispose() @@ -63,8 +64,7 @@ public void FormatSection(ClientBulkWriteOpsCommandMessageSection section, IBson throw new ArgumentException("Writer must be an instance of BsonBinaryWriter."); } - _serializerRegistry = BsonSerializer.SerializerRegistry; - var serializationContext = BsonSerializationContext.CreateRoot(binaryWriter); + var serializationContext = BsonSerializationContext.CreateRoot(binaryWriter, _serializationDomain); _idsMap = section.IdsMap; var stream = binaryWriter.BsonStream; var startPosition = stream.Position; @@ -126,7 +126,7 @@ public void FormatSection(ClientBulkWriteOpsCommandMessageSection section, IBson public void RenderDeleteMany(RenderArgs renderArgs, BsonSerializationContext serializationContext, BulkWriteDeleteManyModel model) { WriteStartModel(serializationContext, "delete", model); - var documentSerializer = _serializerRegistry.GetSerializer(); + var documentSerializer = _serializationDomain.SerializerRegistry.GetSerializer(); WriteFilter(serializationContext, renderArgs, model.Filter, documentSerializer); WriteBoolean(serializationContext, "multi", true); WriteHint(serializationContext, model.Hint); @@ -137,7 +137,7 @@ public void RenderDeleteMany(RenderArgs renderArgs, Bso public void RenderDeleteOne(RenderArgs renderArgs, BsonSerializationContext serializationContext, BulkWriteDeleteOneModel model) { WriteStartModel(serializationContext, "delete", model); - var documentSerializer = _serializerRegistry.GetSerializer(); + var documentSerializer = _serializationDomain.SerializerRegistry.GetSerializer(); WriteFilter(serializationContext, renderArgs, model.Filter, documentSerializer); WriteBoolean(serializationContext, "multi", false); WriteHint(serializationContext, model.Hint); @@ -148,9 +148,9 @@ public void RenderDeleteOne(RenderArgs renderArgs, Bson public void RenderInsertOne(RenderArgs renderArgs, BsonSerializationContext serializationContext, BulkWriteInsertOneModel model) { WriteStartModel(serializationContext, "insert", model); - var documentSerializer = _serializerRegistry.GetSerializer(); - var documentId = documentSerializer.SetDocumentIdIfMissing(null, model.Document); - _idsMap[_currentIndex] = documentId; + var documentSerializer = _serializationDomain.SerializerRegistry.GetSerializer(); + var documentId = documentSerializer.SetDocumentIdIfMissing(null, model.Document, serializationContext.SerializationDomain); + _idsMap[_currentIndex] = BsonValue.Create(documentId); serializationContext.Writer.WriteName("document"); documentSerializer.Serialize(serializationContext, model.Document); WriteEndModel(serializationContext); @@ -159,7 +159,7 @@ public void RenderInsertOne(RenderArgs renderArgs, Bson public void RenderReplaceOne(RenderArgs renderArgs, BsonSerializationContext serializationContext, BulkWriteReplaceOneModel model) { WriteStartModel(serializationContext, "update", model); - var documentSerializer = _serializerRegistry.GetSerializer(); + var documentSerializer = _serializationDomain.SerializerRegistry.GetSerializer(); WriteFilter(serializationContext, renderArgs, model.Filter, documentSerializer); WriteUpdate(serializationContext, model.Replacement, documentSerializer, UpdateType.Replacement); if (model.IsUpsert) @@ -177,7 +177,7 @@ public void RenderReplaceOne(RenderArgs renderArgs, Bso public void RenderUpdateMany(RenderArgs renderArgs, BsonSerializationContext serializationContext, BulkWriteUpdateManyModel model) { WriteStartModel(serializationContext, "update", model); - var documentSerializer = _serializerRegistry.GetSerializer(); + var documentSerializer = _serializationDomain.SerializerRegistry.GetSerializer(); WriteFilter(serializationContext, renderArgs, model.Filter, documentSerializer); WriteUpdate(serializationContext, renderArgs, model.Update, documentSerializer); if (model.IsUpsert) @@ -195,7 +195,7 @@ public void RenderUpdateMany(RenderArgs renderArgs, Bso public void RenderUpdateOne(RenderArgs renderArgs, BsonSerializationContext serializationContext, BulkWriteUpdateOneModel model) { WriteStartModel(serializationContext, "update", model); - var documentSerializer = _serializerRegistry.GetSerializer(); + var documentSerializer = _serializationDomain.SerializerRegistry.GetSerializer(); WriteFilter(serializationContext, renderArgs, model.Filter, documentSerializer); WriteUpdate(serializationContext, renderArgs, model.Update, documentSerializer); if (model.IsUpsert) @@ -238,7 +238,7 @@ private void WriteArrayFilters(BsonSerializationContext serializationContext, IE serializationContext.Writer.WriteStartArray(); foreach (var arrayFilter in arrayFilters) { - var renderedArrayFilter = arrayFilter.Render(null, _serializerRegistry); + var renderedArrayFilter = arrayFilter.Render(null, _serializationDomain.SerializerRegistry); BsonDocumentSerializer.Instance.Serialize(serializationContext, renderedArrayFilter); } serializationContext.Writer.WriteEndArray(); diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs index 85b4feb8a67..8ae86a8c837 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs @@ -28,7 +28,8 @@ namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders internal sealed class CommandMessageBinaryEncoder : MessageBinaryEncoderBase, IMessageEncoder { private const int EncryptedMaxBatchSize = 2 * 1024 * 1024; // 2 MiB - private static readonly ICommandMessageSectionFormatter __type0SectionFormatter = new Type0SectionFormatter(); + private static readonly ICommandMessageSectionFormatter __type0SectionFormatter = new Type0SectionFormatter(BsonSerializer.DefaultSerializationDomain); + //QUESTION Looking at the spec and our implementation, it seems that type 0 sections always serialize/deserialize RawBsonDocument, so they should use the default domain. Am I missing something? // constructors public CommandMessageBinaryEncoder(Stream stream, MessageEncoderSettings encoderSettings) @@ -214,7 +215,7 @@ private List ReadSections(BsonBinaryReader reader, long m private Type0CommandMessageSection ReadType0Section(IBsonReader reader) { var serializer = RawBsonDocumentSerializer.Instance; - var context = BsonDeserializationContext.CreateRoot(reader); + var context = BsonDeserializationContext.CreateRoot(reader, SerializationDomain); var document = serializer.Deserialize(context); return new Type0CommandMessageSection(document, serializer); } @@ -229,7 +230,7 @@ private Type1CommandMessageSection ReadType1Section(BsonBinaryR var payloadEndPosition = payloadStartPosition + payloadLength; var identifier = stream.ReadCString(Utf8Encodings.Strict); var serializer = RawBsonDocumentSerializer.Instance; - var context = BsonDeserializationContext.CreateRoot(reader); + var context = BsonDeserializationContext.CreateRoot(reader, SerializationDomain); var documents = new List(); while (stream.Position < payloadEndPosition) { @@ -252,11 +253,11 @@ private void WriteSection(BsonBinaryWriter writer, CommandMessageSection section __type0SectionFormatter.FormatSection(type0Section, writer); break; case Type1CommandMessageSection type1Section: - var type1SectionFormatter = new Type1SectionFormatter(GetSectionMaxSize()); + var type1SectionFormatter = new Type1SectionFormatter(GetSectionMaxSize(), SerializationDomain); type1SectionFormatter.FormatSection(type1Section, writer); break; case ClientBulkWriteOpsCommandMessageSection bulkWriteOpsSection: - using (var bulkWriteOpsSectionFormatter = new ClientBulkWriteOpsSectionFormatter(GetSectionMaxSize())) + using (var bulkWriteOpsSectionFormatter = new ClientBulkWriteOpsSectionFormatter(GetSectionMaxSize(), SerializationDomain)) { bulkWriteOpsSectionFormatter.FormatSection(bulkWriteOpsSection, writer); } diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs index e8e6e58b61d..71c07ee442b 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs @@ -15,8 +15,8 @@ using System.IO; using System.Text; -using MongoDB.Bson; using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; using MongoDB.Driver.Core.Misc; namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders @@ -82,6 +82,10 @@ protected int? MaxWireDocumentSize } } + protected IBsonSerializationDomain SerializationDomain + => _encoderSettings?.GetOrDefault(MessageEncoderSettingsName.SerializationDomain, null) ?? BsonSerializer.DefaultSerializationDomain; + //QUESTION Is this correct? If we don't have a domain in the encoder settings, just use the default one? + // methods public BsonBinaryReader CreateBinaryReader() { diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs index 45588a3e0b6..7146d4eec7b 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs @@ -85,7 +85,7 @@ internal QueryMessage ReadMessage(IBsonSerializer serializ var fullCollectionName = stream.ReadCString(Encoding); var skip = stream.ReadInt32(); var batchSize = stream.ReadInt32(); - var context = BsonDeserializationContext.CreateRoot(binaryReader); + var context = BsonDeserializationContext.CreateRoot(binaryReader, SerializationDomain); var query = serializer.Deserialize(context); BsonDocument fields = null; if (stream.Position < startPosition + messageSize) @@ -156,7 +156,8 @@ private void WriteOptionalFields(BsonBinaryWriter binaryWriter, BsonDocument fie { if (fields != null) { - var context = BsonSerializationContext.CreateRoot(binaryWriter); + //QUESTION Is it correct we only need a default domain here? + var context = BsonSerializationContext.CreateRoot(binaryWriter, BsonSerializer.DefaultSerializationDomain); BsonDocumentSerializer.Instance.Serialize(context, fields); } } @@ -169,7 +170,8 @@ private void WriteQuery(BsonBinaryWriter binaryWriter, BsonDocument query, IElem binaryWriter.PushElementNameValidator(queryValidator); try { - var context = BsonSerializationContext.CreateRoot(binaryWriter); + //QUESTION Is it correct we only need a default domain here? + var context = BsonSerializationContext.CreateRoot(binaryWriter, BsonSerializer.DefaultSerializationDomain); BsonDocumentSerializer.Instance.Serialize(context, query ?? new BsonDocument()); } finally diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ReplyMessageBinaryEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ReplyMessageBinaryEncoder.cs index d785716b2df..51594e6f2ff 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ReplyMessageBinaryEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ReplyMessageBinaryEncoder.cs @@ -60,7 +60,7 @@ public ReplyMessage ReadMessage() if (queryFailure) { - var context = BsonDeserializationContext.CreateRoot(binaryReader); + var context = BsonDeserializationContext.CreateRoot(binaryReader, SerializationDomain); queryFailureDocument = BsonDocumentSerializer.Instance.Deserialize(context); } else @@ -69,7 +69,7 @@ public ReplyMessage ReadMessage() for (var i = 0; i < numberReturned; i++) { var allowDuplicateElementNames = typeof(TDocument) == typeof(BsonDocument); - var context = BsonDeserializationContext.CreateRoot(binaryReader, builder => + var context = BsonDeserializationContext.CreateRoot(binaryReader, SerializationDomain, builder => { builder.AllowDuplicateElementNames = allowDuplicateElementNames; }); @@ -124,14 +124,16 @@ public void WriteMessage(ReplyMessage message) stream.WriteInt32(message.NumberReturned); if (message.QueryFailure) { - var context = BsonSerializationContext.CreateRoot(binaryWriter); + //QUESTION Is it correct we only need a default domain here? + var context = BsonSerializationContext.CreateRoot(binaryWriter, BsonSerializer.DefaultSerializationDomain); _serializer.Serialize(context, message.QueryFailureDocument); } else { foreach (var doc in message.Documents) { - var context = BsonSerializationContext.CreateRoot(binaryWriter); + //QUESTION Is it correct we only need a default domain here? + var context = BsonSerializationContext.CreateRoot(binaryWriter, BsonSerializer.DefaultSerializationDomain); _serializer.Serialize(context, doc); } } diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/Type0SectionFormatter.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/Type0SectionFormatter.cs index eccb8a7d01b..5444cc2150a 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/Type0SectionFormatter.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/Type0SectionFormatter.cs @@ -20,10 +20,17 @@ namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders { internal sealed class Type0SectionFormatter : ICommandMessageSectionFormatter { + private readonly IBsonSerializationDomain _serializationDomain; + + public Type0SectionFormatter(IBsonSerializationDomain serializationDomain) + { + _serializationDomain = serializationDomain; + } + public void FormatSection(Type0CommandMessageSection section, IBsonWriter writer) { var serializer = section.DocumentSerializer; - var context = BsonSerializationContext.CreateRoot(writer); + var context = BsonSerializationContext.CreateRoot(writer, _serializationDomain); serializer.Serialize(context, section.Document); } } diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/Type1SectionFormatter.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/Type1SectionFormatter.cs index f56b9e1bb46..49784613043 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/Type1SectionFormatter.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/Type1SectionFormatter.cs @@ -22,10 +22,12 @@ namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders internal sealed class Type1SectionFormatter : ICommandMessageSectionFormatter { private readonly long? _maxSize; + private readonly IBsonSerializationDomain _serializationDomain; - public Type1SectionFormatter(long? maxSize) + public Type1SectionFormatter(long? maxSize, IBsonSerializationDomain serializationDomain) { _maxSize = maxSize; + _serializationDomain = serializationDomain; } public void FormatSection(Type1CommandMessageSection section, IBsonWriter writer) @@ -37,7 +39,7 @@ public void FormatSection(Type1CommandMessageSection section, IBsonWriter writer var stream = binaryWriter.BsonStream; var serializer = section.DocumentSerializer; - var context = BsonSerializationContext.CreateRoot(binaryWriter); + var context = BsonSerializationContext.CreateRoot(binaryWriter, _serializationDomain); var startPosition = stream.Position; stream.WriteInt32(0); // size diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/ICommandMessageSectionFormatter.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/ICommandMessageSectionFormatter.cs index 3a80661a634..e79dab13765 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/ICommandMessageSectionFormatter.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/ICommandMessageSectionFormatter.cs @@ -14,6 +14,7 @@ */ using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders { diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandMessageJsonEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandMessageJsonEncoder.cs index 8bbce7ac8d2..ae5b1bdef97 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandMessageJsonEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandMessageJsonEncoder.cs @@ -27,19 +27,22 @@ namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.JsonEncoders { internal sealed class CommandMessageJsonEncoder : MessageJsonEncoderBase, IMessageEncoder { - private static readonly ICommandMessageSectionFormatter __type0SectionFormatter = new Type0SectionFormatter(); - private static readonly ICommandMessageSectionFormatter __type1SectionFormatter = new Type1SectionFormatter(); + private readonly ICommandMessageSectionFormatter _type0SectionFormatter; + private readonly ICommandMessageSectionFormatter _type1SectionFormatter; public CommandMessageJsonEncoder(TextReader textReader, TextWriter textWriter, MessageEncoderSettings encoderSettings) : base(textReader, textWriter, encoderSettings) { + //QUESTION Looking at the spec and our implementation, it seems that type 0 sections always serialize/deserialize RawBsonDocument, so they should use the default domain. Am I missing something? + _type0SectionFormatter = new Type0SectionFormatter(BsonSerializer.DefaultSerializationDomain); + _type1SectionFormatter = new Type1SectionFormatter(SerializationDomain); } // public methods public CommandMessage ReadMessage() { var reader = CreateJsonReader(); - var context = BsonDeserializationContext.CreateRoot(reader); + var context = BsonDeserializationContext.CreateRoot(reader, SerializationDomain); var messageDocument = BsonDocumentSerializer.Instance.Deserialize(context); var opcode = messageDocument["opcode"].AsString; @@ -143,11 +146,11 @@ private void WriteSection(IBsonWriter writer, CommandMessageSection section) switch (section) { case Type0CommandMessageSection type0Section: - __type0SectionFormatter.FormatSection(type0Section, writer); + _type0SectionFormatter.FormatSection(type0Section, writer); break; case Type1CommandMessageSection type1Section: - __type1SectionFormatter.FormatSection(type1Section, writer); + _type1SectionFormatter.FormatSection(type1Section, writer); break; default: diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/CompressedMessageJsonEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/CompressedMessageJsonEncoder.cs index a7093627b1c..d6af06a2e97 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/CompressedMessageJsonEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/CompressedMessageJsonEncoder.cs @@ -41,7 +41,7 @@ public CompressedMessageJsonEncoder(TextReader textReader, TextWriter textWriter public CompressedMessage ReadMessage() { var reader = CreateJsonReader(); - var context = BsonDeserializationContext.CreateRoot(reader); + var context = BsonDeserializationContext.CreateRoot(reader, SerializationDomain); var messageDocument = BsonDocumentSerializer.Instance.Deserialize(context); var opcode = (Opcode)messageDocument["opcode"].ToInt32(); diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/MessageJsonEncoderBase.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/MessageJsonEncoderBase.cs index 0a54dc96a30..0e2a5b67982 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/MessageJsonEncoderBase.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/MessageJsonEncoderBase.cs @@ -17,6 +17,7 @@ using System.IO; using MongoDB.Bson; using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; using MongoDB.Driver.Core.Misc; namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.JsonEncoders @@ -37,6 +38,8 @@ protected MessageJsonEncoderBase(TextReader textReader, TextWriter textWriter, M _encoderSettings = encoderSettings; } + protected IBsonSerializationDomain SerializationDomain => _encoderSettings?.GetOrDefault(MessageEncoderSettingsName.SerializationDomain, null) ?? BsonSerializer.DefaultSerializationDomain; + // methods public JsonReader CreateJsonReader() { diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/QueryMessageJsonEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/QueryMessageJsonEncoder.cs index 83259686e1b..80fc3eaba56 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/QueryMessageJsonEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/QueryMessageJsonEncoder.cs @@ -25,17 +25,21 @@ namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.JsonEncoders { internal sealed class QueryMessageJsonEncoder : MessageJsonEncoderBase, IMessageEncoder { + private IBsonSerializationDomain _serializationDomain; + // constructors public QueryMessageJsonEncoder(TextReader textReader, TextWriter textWriter, MessageEncoderSettings encoderSettings) : base(textReader, textWriter, encoderSettings) { + _serializationDomain = encoderSettings?.GetOrDefault(MessageEncoderSettingsName.SerializationDomain, null) ?? BsonSerializer.DefaultSerializationDomain; + //QUESTION: Should we use the default serialization domain here? I think it's appropriate. } // methods public QueryMessage ReadMessage() { var jsonReader = CreateJsonReader(); - var messageContext = BsonDeserializationContext.CreateRoot(jsonReader); + var messageContext = BsonDeserializationContext.CreateRoot(jsonReader, _serializationDomain); var messageDocument = BsonDocumentSerializer.Instance.Deserialize(messageContext); var opcode = messageDocument["opcode"].AsString; @@ -101,7 +105,7 @@ public void WriteMessage(QueryMessage message) }; var jsonWriter = CreateJsonWriter(); - var messageContext = BsonSerializationContext.CreateRoot(jsonWriter); + var messageContext = BsonSerializationContext.CreateRoot(jsonWriter, _serializationDomain); BsonDocumentSerializer.Instance.Serialize(messageContext, messageDocument); } diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/ReplyMessageJsonEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/ReplyMessageJsonEncoder.cs index 3051819f2b6..87bed75b0bb 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/ReplyMessageJsonEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/ReplyMessageJsonEncoder.cs @@ -29,19 +29,21 @@ internal sealed class ReplyMessageJsonEncoder : MessageJsonEncoderBas { // fields private readonly IBsonSerializer _serializer; + private readonly IBsonSerializationDomain _serializationDomain; // constructors public ReplyMessageJsonEncoder(TextReader textReader, TextWriter textWriter, MessageEncoderSettings encoderSettings, IBsonSerializer serializer) : base(textReader, textWriter, encoderSettings) { _serializer = Ensure.IsNotNull(serializer, nameof(serializer)); + _serializationDomain = encoderSettings?.GetOrDefault(MessageEncoderSettingsName.SerializationDomain, null) ?? BsonSerializer.DefaultSerializationDomain; } // methods public ReplyMessage ReadMessage() { var jsonReader = CreateJsonReader(); - var messageContext = BsonDeserializationContext.CreateRoot(jsonReader); + var messageContext = BsonDeserializationContext.CreateRoot(jsonReader, _serializationDomain); var messageDocument = BsonDocumentSerializer.Instance.Deserialize(messageContext); var opcode = messageDocument["opcode"].AsString; @@ -67,7 +69,7 @@ public ReplyMessage ReadMessage() { using (var documentReader = new BsonDocumentReader(serializedDocument)) { - var documentContext = BsonDeserializationContext.CreateRoot(documentReader); + var documentContext = BsonDeserializationContext.CreateRoot(documentReader, _serializationDomain); var document = _serializer.Deserialize(documentContext); documents.Add(document); } @@ -121,7 +123,7 @@ public void WriteMessage(ReplyMessage message) }; var jsonWriter = CreateJsonWriter(); - var messageContext = BsonSerializationContext.CreateRoot(jsonWriter); + var messageContext = BsonSerializationContext.CreateRoot(jsonWriter, _serializationDomain); BsonDocumentSerializer.Instance.Serialize(messageContext, messageDocument); } diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/Type0SectionFormatter.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/Type0SectionFormatter.cs index 389184f63bc..c0a213a94f6 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/Type0SectionFormatter.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/Type0SectionFormatter.cs @@ -20,11 +20,17 @@ namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.JsonEncoders { internal sealed class Type0SectionFormatter : ICommandMessageSectionFormatter { + private readonly IBsonSerializationDomain _serializationDomain; + + public Type0SectionFormatter(IBsonSerializationDomain serializationDomain) + { + _serializationDomain = serializationDomain; + } public void FormatSection(Type0CommandMessageSection section, IBsonWriter writer) { writer.WriteName("document"); var serializer = section.DocumentSerializer; - var context = BsonSerializationContext.CreateRoot(writer); + var context = BsonSerializationContext.CreateRoot(writer, _serializationDomain); serializer.Serialize(context, section.Document); } } diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/Type1SectionFormatter.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/Type1SectionFormatter.cs index 906d17e8029..ea621b65dcd 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/Type1SectionFormatter.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/Type1SectionFormatter.cs @@ -20,6 +20,13 @@ namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.JsonEncoders { internal sealed class Type1SectionFormatter : ICommandMessageSectionFormatter { + private readonly IBsonSerializationDomain _serializationDomain; + + public Type1SectionFormatter(IBsonSerializationDomain serializationDomain) + { + _serializationDomain = serializationDomain; + } + public void FormatSection(Type1CommandMessageSection section, IBsonWriter writer) { writer.WriteString("identifier", section.Identifier); @@ -27,7 +34,7 @@ public void FormatSection(Type1CommandMessageSection section, IBsonWriter writer writer.WriteStartArray(); var batch = section.Documents; var serializer = section.DocumentSerializer; - var context = BsonSerializationContext.CreateRoot(writer); + var context = BsonSerializationContext.CreateRoot(writer, _serializationDomain); for (var i = 0; i < batch.Count; i++) { var document = batch.Items[batch.Offset + i]; diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs index 30c2e33e2fd..112d77816ca 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs @@ -41,6 +41,7 @@ internal static class MessageEncoderSettingsName public const string ShellVersion = nameof(ShellVersion); // other encoders (if any) might use additional settings + public const string SerializationDomain = nameof(SerializationDomain); //FP I think I should try to remove it from here.. } internal sealed class MessageEncoderSettings : IEnumerable> diff --git a/src/MongoDB.Driver/CreateCollectionOptions.cs b/src/MongoDB.Driver/CreateCollectionOptions.cs index a91a13cf1fa..7b1d170578c 100644 --- a/src/MongoDB.Driver/CreateCollectionOptions.cs +++ b/src/MongoDB.Driver/CreateCollectionOptions.cs @@ -40,6 +40,7 @@ public class CreateCollectionOptions private TimeSeriesOptions _timeSeriesOptions; private bool? _usePowerOf2Sizes; private IBsonSerializerRegistry _serializerRegistry; + private IBsonSerializationDomain _serializationDomain; private DocumentValidationAction? _validationAction; private DocumentValidationLevel? _validationLevel; @@ -129,6 +130,8 @@ public bool? NoPadding set { _noPadding = value; } } + //DOMAIN-API We need to remove this, and have only the SerializationDomain property. When we have builder, we will add Obsolete + //We should also decide if we even need any of those two properties. /// /// Gets or sets the serializer registry. /// @@ -138,6 +141,12 @@ public IBsonSerializerRegistry SerializerRegistry set { _serializerRegistry = value; } } + internal IBsonSerializationDomain SerializationDomain + { + get => _serializationDomain; + set => _serializationDomain = value; + } + /// /// Gets or sets the storage engine options. /// @@ -216,6 +225,7 @@ public virtual CreateCollectionOptions Clone() => _maxDocuments = _maxDocuments, _maxSize = _maxSize, _serializerRegistry = _serializerRegistry, + _serializationDomain = _serializationDomain, _storageEngine = _storageEngine, _timeSeriesOptions = _timeSeriesOptions, _validationAction = _validationAction, @@ -256,6 +266,7 @@ internal static CreateCollectionOptions CoercedFrom(CreateCollectionO MaxDocuments = options.MaxDocuments, MaxSize = options.MaxSize, SerializerRegistry = options.SerializerRegistry, + SerializationDomain = options.SerializationDomain, StorageEngine = options.StorageEngine, TimeSeriesOptions = options.TimeSeriesOptions, ValidationAction = options.ValidationAction, diff --git a/src/MongoDB.Driver/CreateViewOptions.cs b/src/MongoDB.Driver/CreateViewOptions.cs index 5120f2efd72..7c1836d42a9 100644 --- a/src/MongoDB.Driver/CreateViewOptions.cs +++ b/src/MongoDB.Driver/CreateViewOptions.cs @@ -30,6 +30,7 @@ public class CreateViewOptions private IBsonSerializer _documentSerializer; private IBsonSerializerRegistry _serializerRegistry; private TimeSpan? _timeout; + private IBsonSerializationDomain _serializationDomain; // properties /// @@ -56,6 +57,8 @@ public IBsonSerializer DocumentSerializer set { _documentSerializer = value; } } + //DOMAIN-API We need to remove this, and have only the SerializationDomain property. + //We should also decide if we even need any of those two properties. /// /// Gets or sets the serializer registry. /// @@ -77,5 +80,11 @@ internal TimeSpan? Timeout get => _timeout; set => _timeout = Ensure.IsNullOrValidTimeout(value, nameof(Timeout)); } + + internal IBsonSerializationDomain SerializationDomain + { + get => _serializationDomain; + set => _serializationDomain = value; + } } } diff --git a/src/MongoDB.Driver/FieldDefinition.cs b/src/MongoDB.Driver/FieldDefinition.cs index 6a3f1319da6..9b850457aff 100644 --- a/src/MongoDB.Driver/FieldDefinition.cs +++ b/src/MongoDB.Driver/FieldDefinition.cs @@ -242,7 +242,7 @@ public LambdaExpression Expression /// public override RenderedFieldDefinition Render(RenderArgs args) { - return LinqProviderAdapter.TranslateExpressionToField(_expression, args.DocumentSerializer, args.SerializerRegistry, args.TranslationOptions); + return LinqProviderAdapter.TranslateExpressionToField(_expression, args.DocumentSerializer, args.SerializationDomain, args.TranslationOptions); } } @@ -275,7 +275,7 @@ public Expression> Expression /// public override RenderedFieldDefinition Render(RenderArgs args) { - return LinqProviderAdapter.TranslateExpressionToField(_expression, args.DocumentSerializer, args.SerializerRegistry, args.TranslationOptions, args.PathRenderArgs.AllowScalarValueForArray); + return LinqProviderAdapter.TranslateExpressionToField(_expression, args.DocumentSerializer, args.SerializationDomain, args.TranslationOptions, args.PathRenderArgs.AllowScalarValueForArray); } } diff --git a/src/MongoDB.Driver/FieldValueSerializerHelper.cs b/src/MongoDB.Driver/FieldValueSerializerHelper.cs index 68880f7fe18..26110109b03 100644 --- a/src/MongoDB.Driver/FieldValueSerializerHelper.cs +++ b/src/MongoDB.Driver/FieldValueSerializerHelper.cs @@ -20,6 +20,7 @@ using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; +using MongoDB.Driver.Linq.Linq3Implementation.Serializers; using MongoDB.Driver.Support; namespace MongoDB.Driver @@ -51,7 +52,7 @@ public static IBsonSerializer GetSerializerForValueType(IBsonSerializer fieldSer // serialize numeric values without converting them if (fieldType.IsNumeric() && valueType.IsNumeric()) { - var valueSerializer = BsonSerializer.SerializerRegistry.GetSerializer(valueType); + var valueSerializer = StandardSerializers.GetSerializer(valueType); if (HasStringRepresentation(fieldSerializer)) { valueSerializer = WithStringRepresentation(valueSerializer); diff --git a/src/MongoDB.Driver/FilterDefinition.cs b/src/MongoDB.Driver/FilterDefinition.cs index a7e727110af..12e03969c72 100644 --- a/src/MongoDB.Driver/FilterDefinition.cs +++ b/src/MongoDB.Driver/FilterDefinition.cs @@ -205,11 +205,11 @@ public override BsonDocument Render(RenderArgs args) { if (args.RenderForElemMatch) { - return LinqProviderAdapter.TranslateExpressionToElemMatchFilter(_expression, elementSerializer: args.DocumentSerializer, args.SerializerRegistry, args.TranslationOptions); + return LinqProviderAdapter.TranslateExpressionToElemMatchFilter(_expression, elementSerializer: args.DocumentSerializer, args.SerializationDomain, args.TranslationOptions); } else { - return LinqProviderAdapter.TranslateExpressionToFilter(_expression, args.DocumentSerializer, args.SerializerRegistry, args.TranslationOptions); + return LinqProviderAdapter.TranslateExpressionToFilter(_expression, args.DocumentSerializer, args.SerializationDomain, args.TranslationOptions); } } } diff --git a/src/MongoDB.Driver/FilterDefinitionBuilder.cs b/src/MongoDB.Driver/FilterDefinitionBuilder.cs index e07d9ac957c..8a1a2416ab0 100644 --- a/src/MongoDB.Driver/FilterDefinitionBuilder.cs +++ b/src/MongoDB.Driver/FilterDefinitionBuilder.cs @@ -1853,7 +1853,7 @@ public override BsonDocument Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(renderedField.FieldName); bsonWriter.WriteStartDocument(); @@ -2013,7 +2013,7 @@ public override BsonDocument Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(renderedField.FieldName); bsonWriter.WriteStartDocument(); @@ -2055,7 +2055,7 @@ public override BsonDocument Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(renderedField.FieldName); bsonWriter.WriteStartDocument(); @@ -2205,14 +2205,14 @@ public override BsonDocument Render(RenderArgs args) } else { - var discriminatorConvention = args.DocumentSerializer.GetDiscriminatorConvention(); + var discriminatorConvention = args.DocumentSerializer.GetDiscriminatorConvention(args.SerializationDomain); if (discriminatorConvention == null) { var message = string.Format("OfType requires a discriminator convention for type: {0}.", BsonUtils.GetFriendlyTypeName(typeof(TDocument))); throw new NotSupportedException(message); } - var discriminator = discriminatorConvention.GetDiscriminator(typeof(TDocument), typeof(TDerived)); + var discriminator = discriminatorConvention.GetDiscriminatorInternal(typeof(TDocument), typeof(TDerived), args.SerializationDomain); if (discriminator == null) { throw new NotSupportedException($"OfType requires that documents of type {BsonUtils.GetFriendlyTypeName(typeof(TDerived))} have a discriminator value."); @@ -2221,8 +2221,8 @@ public override BsonDocument Render(RenderArgs args) var discriminatorField = new AstFilterField(discriminatorConvention.ElementName); ofTypeFilter= discriminatorConvention switch { - IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType), - IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType), + IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType, args.SerializationDomain), + IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType, args.SerializationDomain), _ => throw new NotSupportedException("OfType is not supported with the configured discriminator convention.") }; } @@ -2268,7 +2268,7 @@ public override BsonDocument Render(RenderArgs args) } else { - var discriminatorConvention = renderedField.FieldSerializer.GetDiscriminatorConvention(); + var discriminatorConvention = renderedField.FieldSerializer.GetDiscriminatorConvention(args.SerializationDomain); if (discriminatorConvention == null) { var message = string.Format("OfType requires a discriminator convention for type: {0}.", BsonUtils.GetFriendlyTypeName(typeof(TField))); @@ -2280,8 +2280,8 @@ public override BsonDocument Render(RenderArgs args) ofTypeFilter = discriminatorConvention switch { - IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType), - IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType), + IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType, args.SerializationDomain), + IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType, args.SerializationDomain), _ => throw new NotSupportedException("OfType is not supported with the configured discriminator convention.") }; } @@ -2351,7 +2351,7 @@ public override BsonDocument Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(renderedField.FieldName); bsonWriter.WriteStartDocument(); @@ -2445,7 +2445,7 @@ public override BsonDocument Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(renderedField.FieldName); @@ -2495,7 +2495,7 @@ public override BsonDocument Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(renderedField.FieldName); bsonWriter.WriteStartDocument(); @@ -2551,7 +2551,7 @@ public override BsonDocument Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(renderedField.FieldName); bsonWriter.WriteStartDocument(); @@ -2600,7 +2600,7 @@ public override BsonDocument Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(renderedField.FieldName); itemSerializer.Serialize(context, _value); @@ -2660,7 +2660,7 @@ public override BsonDocument Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); var stringSerializer = BsonStringSerializer.Instance; var regularExpressionSerializer = BsonRegularExpressionSerializer.Instance; diff --git a/src/MongoDB.Driver/FindFluent.cs b/src/MongoDB.Driver/FindFluent.cs index 939aec7da71..a1830d4ec23 100644 --- a/src/MongoDB.Driver/FindFluent.cs +++ b/src/MongoDB.Driver/FindFluent.cs @@ -284,7 +284,7 @@ private TRendered Render(Func, TRendered> rende { var args = new RenderArgs( _collection.DocumentSerializer, - _collection.Settings.SerializerRegistry, + _collection.Settings.SerializationDomain, renderForFind: renderForFind, translationOptions: translationOptions); diff --git a/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonBoundingBoxSerializer.cs b/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonBoundingBoxSerializer.cs index 1c35c0eadec..248e816a052 100644 --- a/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonBoundingBoxSerializer.cs +++ b/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonBoundingBoxSerializer.cs @@ -73,7 +73,7 @@ protected override GeoJsonBoundingBox DeserializeValue(BsonDeseria using (var documentReader = new BsonDocumentReader(document)) { - var documentContext = BsonDeserializationContext.CreateRoot(documentReader); + var documentContext = BsonDeserializationContext.CreateRoot(documentReader, context.SerializationDomain); documentReader.ReadStartDocument(); documentReader.ReadName("min"); var min = _coordinatesSerializer.Deserialize(documentContext); @@ -99,7 +99,8 @@ protected override void SerializeValue(BsonSerializationContext context, BsonSer var document = new BsonDocument(); using (var documentWriter = new BsonDocumentWriter(document)) { - var documentContext = BsonSerializationContext.CreateRoot(documentWriter); + var documentContext = + BsonSerializationContext.CreateRoot(documentWriter, BsonSerializer.DefaultSerializationDomain); //FP Is this correct?; documentWriter.WriteStartDocument(); documentWriter.WriteName("min"); _coordinatesSerializer.Serialize(documentContext, value.Min); diff --git a/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonPointSerializer.cs b/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonPointSerializer.cs index cf28467eff8..821789af86c 100644 --- a/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonPointSerializer.cs +++ b/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonPointSerializer.cs @@ -31,7 +31,7 @@ private static class Flags } // private fields - private readonly IBsonSerializer _coordinatesSerializer = BsonSerializer.LookupSerializer(); + private readonly IBsonSerializer _coordinatesSerializer = BsonSerializer.LookupSerializer(); //QUESTION What do we do? We could lazily initialize it when we get the serialization/deserialization context. private readonly GeoJsonObjectSerializerHelper _helper; // constructors diff --git a/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonPolygonSerializer.cs b/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonPolygonSerializer.cs index 7a204283f47..a973324c7ea 100644 --- a/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonPolygonSerializer.cs +++ b/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonPolygonSerializer.cs @@ -32,6 +32,7 @@ private static class Flags // private fields private readonly IBsonSerializer> _coordinatesSerializer = BsonSerializer.LookupSerializer>(); + //QUESTION This happens in all GeoJsonOBjectModel serializers, what do we do here? Do we just lookup the serialzer in each Serialize/Deserialize or do we cache it? private readonly GeoJsonObjectSerializerHelper _helper; // constructors diff --git a/src/MongoDB.Driver/GridFS/GridFSBucket.cs b/src/MongoDB.Driver/GridFS/GridFSBucket.cs index 7e65af290a3..3950ed1f802 100644 --- a/src/MongoDB.Driver/GridFS/GridFSBucket.cs +++ b/src/MongoDB.Driver/GridFS/GridFSBucket.cs @@ -599,7 +599,7 @@ internal CreateIndexesOperation CreateCreateChunksCollectionIndexesOperation() var collectionNamespace = this.GetChunksCollectionNamespace(); var requests = new[] { new CreateIndexRequest(new BsonDocument { { "files_id", 1 }, { "n", 1 } }) { Unique = true } }; var messageEncoderSettings = this.GetMessageEncoderSettings(); - return new CreateIndexesOperation(collectionNamespace, requests, messageEncoderSettings) + return new CreateIndexesOperation(collectionNamespace, requests, messageEncoderSettings, _database.Settings.SerializationDomain) { WriteConcern = _options.WriteConcern ?? _database.Settings.WriteConcern }; @@ -610,7 +610,7 @@ internal CreateIndexesOperation CreateCreateFilesCollectionIndexesOperation() var collectionNamespace = this.GetFilesCollectionNamespace(); var requests = new[] { new CreateIndexRequest(new BsonDocument { { "filename", 1 }, { "uploadDate", 1 } }) }; var messageEncoderSettings = this.GetMessageEncoderSettings(); - return new CreateIndexesOperation(collectionNamespace, requests, messageEncoderSettings) + return new CreateIndexesOperation(collectionNamespace, requests, messageEncoderSettings, _database.Settings.SerializationDomain) { WriteConcern = _options.WriteConcern ?? _database.Settings.WriteConcern }; @@ -631,17 +631,17 @@ private BulkMixedWriteOperation CreateDeleteChunksOperation(TFileId id) if (seekable) { - return new GridFSSeekableDownloadStream(this, binding, fileInfo); + return new GridFSSeekableDownloadStream(this, binding, fileInfo, _database.Settings.SerializationDomain); } else { - return new GridFSForwardOnlyDownloadStream(this, binding, fileInfo); + return new GridFSForwardOnlyDownloadStream(this, binding, fileInfo, _database.Settings.SerializationDomain); } } internal DropCollectionOperation CreateDropCollectionOperation(CollectionNamespace collectionNamespace, MessageEncoderSettings messageEncoderSettings) { - return new DropCollectionOperation(collectionNamespace, messageEncoderSettings) + return new DropCollectionOperation(collectionNamespace, messageEncoderSettings, _database.Settings.SerializationDomain) { WriteConcern = _options.WriteConcern ?? _database.Settings.WriteConcern }; @@ -675,14 +675,15 @@ private FindOperation> CreateFindOperation( { var filesCollectionNamespace = this.GetFilesCollectionNamespace(); var messageEncoderSettings = this.GetMessageEncoderSettings(); - var args = new RenderArgs>(_fileInfoSerializer, _options.SerializerRegistry, translationOptions: translationOptions); + var args = new RenderArgs>(_fileInfoSerializer, _database.Settings.SerializationDomain, translationOptions: translationOptions); var renderedFilter = filter.Render(args); var renderedSort = options.Sort == null ? null : options.Sort.Render(args); return new FindOperation>( filesCollectionNamespace, _fileInfoSerializer, - messageEncoderSettings) + messageEncoderSettings, + _database.Settings.SerializationDomain) { AllowDiskUse = options.AllowDiskUse, BatchSize = options.BatchSize, @@ -709,7 +710,8 @@ private FindOperation> CreateGetFileInfoByNameOperation( return new FindOperation>( collectionNamespace, _fileInfoSerializer, - messageEncoderSettings) + messageEncoderSettings, + _database.Settings.SerializationDomain) { Filter = filter, Limit = limit, @@ -729,7 +731,8 @@ private FindOperation> CreateGetFileInfoOperation(TFileI return new FindOperation>( filesCollectionNamespace, _fileInfoSerializer, - messageEncoderSettings) + messageEncoderSettings, + _database.Settings.SerializationDomain) { Filter = filter, Limit = 1, @@ -743,7 +746,7 @@ private FindOperation CreateIsFilesCollectionEmptyOperation() { var filesCollectionNamespace = this.GetFilesCollectionNamespace(); var messageEncoderSettings = this.GetMessageEncoderSettings(); - return new FindOperation(filesCollectionNamespace, BsonDocumentSerializer.Instance, messageEncoderSettings) + return new FindOperation(filesCollectionNamespace, BsonDocumentSerializer.Instance, messageEncoderSettings, _database.Settings.SerializationDomain) { Limit = 1, ReadConcern = GetReadConcern(), @@ -756,7 +759,7 @@ private FindOperation CreateIsFilesCollectionEmptyOperation() private ListIndexesOperation CreateListIndexesOperation(CollectionNamespace collectionNamespace) { var messageEncoderSettings = this.GetMessageEncoderSettings(); - return new ListIndexesOperation(collectionNamespace, messageEncoderSettings) + return new ListIndexesOperation(collectionNamespace, messageEncoderSettings, _database.Settings.SerializationDomain) { RetryRequested = _database.Client.Settings.RetryReads }; @@ -822,7 +825,7 @@ private GridFSUploadStream CreateUploadStream(IReadWriteBindingHandle b private void DownloadToStreamHelper(IReadBindingHandle binding, GridFSFileInfo fileInfo, Stream destination, GridFSDownloadOptions options, CancellationToken cancellationToken = default(CancellationToken)) { var retryReads = _database.Client.Settings.RetryReads; - using (var source = new GridFSForwardOnlyDownloadStream(this, binding.Fork(), fileInfo) { RetryReads = retryReads }) + using (var source = new GridFSForwardOnlyDownloadStream(this, binding.Fork(), fileInfo, _database.Settings.SerializationDomain) { RetryReads = retryReads }) { var count = source.Length; var buffer = new byte[fileInfo.ChunkSizeBytes]; @@ -841,7 +844,7 @@ private GridFSUploadStream CreateUploadStream(IReadWriteBindingHandle b private async Task DownloadToStreamHelperAsync(IReadBindingHandle binding, GridFSFileInfo fileInfo, Stream destination, GridFSDownloadOptions options, CancellationToken cancellationToken = default(CancellationToken)) { var retryReads = _database.Client.Settings.RetryReads; - using (var source = new GridFSForwardOnlyDownloadStream(this, binding.Fork(), fileInfo) { RetryReads = retryReads }) + using (var source = new GridFSForwardOnlyDownloadStream(this, binding.Fork(), fileInfo, _database.Settings.SerializationDomain) { RetryReads = retryReads }) { var count = source.Length; var buffer = new byte[fileInfo.ChunkSizeBytes]; diff --git a/src/MongoDB.Driver/GridFS/GridFSBucketCompat.cs b/src/MongoDB.Driver/GridFS/GridFSBucketCompat.cs index cf4d994e11c..f5b6e83973e 100644 --- a/src/MongoDB.Driver/GridFS/GridFSBucketCompat.cs +++ b/src/MongoDB.Driver/GridFS/GridFSBucketCompat.cs @@ -120,8 +120,8 @@ public GridFSBucket(IMongoDatabase database, GridFSBucketOptions options = null) { Ensure.IsNotNull(filter, nameof(filter)); var translationOptions = Database.Client.Settings.TranslationOptions; - var wrappedFilter = WrapFilter(filter, translationOptions); - var wrappedOptions = WrapFindOptions(options, translationOptions); + var wrappedFilter = WrapFilter(filter, Database.Settings.SerializationDomain, translationOptions); + var wrappedOptions = WrapFindOptions(options, Database.Settings.SerializationDomain, translationOptions); var cursor = base.Find(wrappedFilter, wrappedOptions, cancellationToken); return new BatchTransformingAsyncCursor, GridFSFileInfo>(cursor, TransformFileInfos); } @@ -131,8 +131,8 @@ public GridFSBucket(IMongoDatabase database, GridFSBucketOptions options = null) { Ensure.IsNotNull(filter, nameof(filter)); var translationOptions = Database.Client.Settings.TranslationOptions; - var wrappedFilter = WrapFilter(filter, translationOptions); - var wrappedOptions = WrapFindOptions(options, translationOptions); + var wrappedFilter = WrapFilter(filter, Database.Settings.SerializationDomain, translationOptions); + var wrappedOptions = WrapFindOptions(options, Database.Settings.SerializationDomain, translationOptions); var cursor = await base.FindAsync(wrappedFilter, wrappedOptions, cancellationToken).ConfigureAwait(false); return new BatchTransformingAsyncCursor, GridFSFileInfo>(cursor, TransformFileInfos); } @@ -240,17 +240,17 @@ private IEnumerable TransformFileInfos(IEnumerable new GridFSFileInfo(fi.BackingDocument)); } - private FilterDefinition> WrapFilter(FilterDefinition filter, ExpressionTranslationOptions translationOptions) + private FilterDefinition> WrapFilter(FilterDefinition filter, IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) { - var renderedFilter = filter.Render(new(GridFSFileInfoSerializer.Instance, BsonSerializer.SerializerRegistry, translationOptions: translationOptions)); + var renderedFilter = filter.Render(new(GridFSFileInfoSerializer.Instance, serializationDomain, translationOptions: translationOptions)); return new BsonDocumentFilterDefinition>(renderedFilter); } - private GridFSFindOptions WrapFindOptions(GridFSFindOptions options, ExpressionTranslationOptions translationOptions) + private GridFSFindOptions WrapFindOptions(GridFSFindOptions options, IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) { if (options != null) { - var renderedSort = options.Sort == null ? null : options.Sort.Render(new(GridFSFileInfoSerializer.Instance, BsonSerializer.SerializerRegistry, translationOptions: translationOptions)); + var renderedSort = options.Sort == null ? null : options.Sort.Render(new(GridFSFileInfoSerializer.Instance, serializationDomain, translationOptions: translationOptions)); var wrappedSort = renderedSort == null ? null : new BsonDocumentSortDefinition>(renderedSort); return new GridFSFindOptions { diff --git a/src/MongoDB.Driver/GridFS/GridFSBucketOptions.cs b/src/MongoDB.Driver/GridFS/GridFSBucketOptions.cs index 1ef76936f0f..24c16e3d262 100644 --- a/src/MongoDB.Driver/GridFS/GridFSBucketOptions.cs +++ b/src/MongoDB.Driver/GridFS/GridFSBucketOptions.cs @@ -243,7 +243,8 @@ public ReadPreference ReadPreference /// public IBsonSerializerRegistry SerializerRegistry { - get { return BsonSerializer.SerializerRegistry; } + get { return BsonSerializer.SerializerRegistry; } //QUESTION What do we do in this case...? Given it's read only, we could ignore it? Given this is used for default serialization, it should be ok. + //Also, why the immutable options have a serializer registry and the non-immutable options do not? } /// diff --git a/src/MongoDB.Driver/GridFS/GridFSDownloadStreamBase.cs b/src/MongoDB.Driver/GridFS/GridFSDownloadStreamBase.cs index 4e2089eb4eb..f12ff4ee795 100644 --- a/src/MongoDB.Driver/GridFS/GridFSDownloadStreamBase.cs +++ b/src/MongoDB.Driver/GridFS/GridFSDownloadStreamBase.cs @@ -17,7 +17,9 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using MongoDB.Bson.Serialization; using MongoDB.Driver.Core.Bindings; +using MongoDB.Driver.Core.Misc; namespace MongoDB.Driver.GridFS { @@ -30,15 +32,29 @@ internal abstract class GridFSDownloadStreamBase : GridFSDownloadStream private bool _disposed; private readonly GridFSFileInfo _fileInfo; + // protected fields + protected readonly IBsonSerializationDomain SerializationDomain; + // constructors protected GridFSDownloadStreamBase( IGridFSBucket bucket, IReadBinding binding, - GridFSFileInfo fileInfo) + GridFSFileInfo fileInfo, + IBsonSerializationDomain serializationDomain) { _bucket = bucket; _binding = binding; _fileInfo = fileInfo; + SerializationDomain = serializationDomain; + } + + //EXIT + protected GridFSDownloadStreamBase( + IGridFSBucket bucket, + IReadBinding binding, + GridFSFileInfo fileInfo) + : this(bucket, binding, fileInfo, BsonSerializer.DefaultSerializationDomain) + { } // public properties diff --git a/src/MongoDB.Driver/GridFS/GridFSFileInfoSerializer.cs b/src/MongoDB.Driver/GridFS/GridFSFileInfoSerializer.cs index 4c91bb90283..38e6631c116 100644 --- a/src/MongoDB.Driver/GridFS/GridFSFileInfoSerializer.cs +++ b/src/MongoDB.Driver/GridFS/GridFSFileInfoSerializer.cs @@ -31,7 +31,7 @@ public class GridFSFileInfoSerializer : BsonDocumentBackedClassSerializ /// Initializes a new instance of the class. /// public GridFSFileInfoSerializer() - : this(BsonSerializer.LookupSerializer()) + : this(BsonSerializer.LookupSerializer()) //FP I think this should be fine. { } diff --git a/src/MongoDB.Driver/GridFS/GridFSForwardOnlyDownloadStream.cs b/src/MongoDB.Driver/GridFS/GridFSForwardOnlyDownloadStream.cs index d3c400afd76..da2e7f18f80 100644 --- a/src/MongoDB.Driver/GridFS/GridFSForwardOnlyDownloadStream.cs +++ b/src/MongoDB.Driver/GridFS/GridFSForwardOnlyDownloadStream.cs @@ -48,8 +48,9 @@ internal class GridFSForwardOnlyDownloadStream : GridFSDownloadStreamBa public GridFSForwardOnlyDownloadStream( GridFSBucket bucket, IReadBinding binding, - GridFSFileInfo fileInfo) - : base(bucket, binding, fileInfo) + GridFSFileInfo fileInfo, + IBsonSerializationDomain serializationDomain) + : base(bucket, binding, fileInfo, serializationDomain) { _lastChunkNumber = (int)((fileInfo.Length - 1) / fileInfo.ChunkSizeBytes); _lastChunkSize = (int)(fileInfo.Length % fileInfo.ChunkSizeBytes); @@ -185,7 +186,8 @@ private FindOperation CreateFirstBatchOperation() return new FindOperation( chunksCollectionNamespace, BsonDocumentSerializer.Instance, - messageEncoderSettings) + messageEncoderSettings, + SerializationDomain) { Filter = filter, Sort = sort, diff --git a/src/MongoDB.Driver/GridFS/GridFSSeekableDownloadStream.cs b/src/MongoDB.Driver/GridFS/GridFSSeekableDownloadStream.cs index 921bbac4232..c10d441f7f2 100644 --- a/src/MongoDB.Driver/GridFS/GridFSSeekableDownloadStream.cs +++ b/src/MongoDB.Driver/GridFS/GridFSSeekableDownloadStream.cs @@ -40,14 +40,24 @@ internal class GridFSSeekableDownloadStream : GridFSDownloadStreamBase< public GridFSSeekableDownloadStream( GridFSBucket bucket, IReadBinding binding, - GridFSFileInfo fileInfo) - : base(bucket, binding, fileInfo) + GridFSFileInfo fileInfo, + IBsonSerializationDomain serializationDomain) + : base(bucket, binding, fileInfo, serializationDomain) { var idSerializer = bucket.Options.SerializerRegistry.GetSerializer(); var idSerializationInfo = new BsonSerializationInfo("_id", idSerializer, typeof(TFileId)); _idAsBsonValue = idSerializationInfo.SerializeValue(fileInfo.Id); } + //EXIT + public GridFSSeekableDownloadStream( + GridFSBucket bucket, + IReadBinding binding, + GridFSFileInfo fileInfo) + : this(bucket, binding, fileInfo, BsonSerializer.DefaultSerializationDomain) + { + } + // public properties public override bool CanSeek { @@ -160,7 +170,8 @@ private FindOperation CreateGetChunkOperation(long n) return new FindOperation( chunksCollectionNamespace, BsonDocumentSerializer.Instance, - messageEncoderSettings) + messageEncoderSettings, + SerializationDomain) { Filter = filter, Limit = -1, diff --git a/src/MongoDB.Driver/IInheritableMongoClientSettings.cs b/src/MongoDB.Driver/IInheritableMongoClientSettings.cs index 2e54fda9d4c..cd516623616 100644 --- a/src/MongoDB.Driver/IInheritableMongoClientSettings.cs +++ b/src/MongoDB.Driver/IInheritableMongoClientSettings.cs @@ -15,6 +15,8 @@ using System; using System.Text; +using MongoDB.Bson; +using MongoDB.Bson.Serialization; namespace MongoDB.Driver { @@ -24,6 +26,7 @@ internal interface IInheritableMongoClientSettings UTF8Encoding ReadEncoding { get; } ReadPreference ReadPreference { get; } TimeSpan? Timeout { get; } + IBsonSerializationDomain SerializationDomain { get; set; } WriteConcern WriteConcern { get; } UTF8Encoding WriteEncoding { get; } } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/GroupingWithOutputExpressionStageDefinitions.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/GroupingWithOutputExpressionStageDefinitions.cs index 4d62eaea95c..565cf37e6c9 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/GroupingWithOutputExpressionStageDefinitions.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/GroupingWithOutputExpressionStageDefinitions.cs @@ -42,9 +42,8 @@ public GroupingWithOutputExpressionStageDefinition(Expression Render(RenderArgs args) { var inputSerializer = args.DocumentSerializer; - var serializerRegistry = args.SerializerRegistry; - var groupingStage = RenderGroupingStage(inputSerializer, serializerRegistry, args.TranslationOptions, out var groupingSerializer); - var projectStage = RenderProjectStage(groupingSerializer, serializerRegistry, args.TranslationOptions, out var outputSerializer); + var groupingStage = RenderGroupingStage(inputSerializer, args.SerializationDomain, args.TranslationOptions, out var groupingSerializer); + var projectStage = RenderProjectStage(groupingSerializer, args.SerializationDomain, args.TranslationOptions, out var outputSerializer); var optimizedStages = OptimizeGroupingStages(groupingStage, projectStage, inputSerializer, outputSerializer); var renderedStages = optimizedStages.Select(x => x.Render().AsBsonDocument); @@ -53,18 +52,18 @@ public override RenderedPipelineStageDefinition Render(RenderArgs inputSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions, out IBsonSerializer groupingOutputSerializer); private AstStage RenderProjectStage( IBsonSerializer inputSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions, out IBsonSerializer outputSerializer) { var partiallyEvaluatedOutput = (Expression>)PartialEvaluator.EvaluatePartially(_output); - var context = TranslationContext.Create(translationOptions); + var context = TranslationContext.Create(translationOptions, serializationDomain); var outputTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, partiallyEvaluatedOutput, inputSerializer, asRoot: true); var (projectStage, projectSerializer) = ProjectionHelper.CreateProjectStage(outputTranslation); outputSerializer = (IBsonSerializer)projectSerializer; @@ -101,12 +100,12 @@ public BucketWithOutputExpressionStageDefinition( protected override AstStage RenderGroupingStage( IBsonSerializer inputSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions, out IBsonSerializer> groupingOutputSerializer) { var partiallyEvaluatedGroupBy = (Expression>)PartialEvaluator.EvaluatePartially(_groupBy); - var context = TranslationContext.Create(translationOptions); + var context = TranslationContext.Create(translationOptions, serializationDomain); var groupByTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, partiallyEvaluatedGroupBy, inputSerializer, asRoot: true); var valueSerializer = (IBsonSerializer)groupByTranslation.Serializer; @@ -145,12 +144,12 @@ public BucketAutoWithOutputExpressionStageDefinition( protected override AstStage RenderGroupingStage( IBsonSerializer inputSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions, out IBsonSerializer, TInput>> groupingOutputSerializer) { var partiallyEvaluatedGroupBy = (Expression>)PartialEvaluator.EvaluatePartially(_groupBy); - var context = TranslationContext.Create(translationOptions); + var context = TranslationContext.Create(translationOptions, serializationDomain); var groupByTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, partiallyEvaluatedGroupBy, inputSerializer, asRoot: true); var valueSerializer = (IBsonSerializer)groupByTranslation.Serializer; @@ -183,12 +182,12 @@ public GroupWithOutputExpressionStageDefinition( protected override AstStage RenderGroupingStage( IBsonSerializer inputSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions, out IBsonSerializer> groupingOutputSerializer) { var partiallyEvaluatedGroupBy = (Expression>)PartialEvaluator.EvaluatePartially(_groupBy); - var context = TranslationContext.Create(translationOptions); + var context = TranslationContext.Create(translationOptions, serializationDomain); var groupByTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, partiallyEvaluatedGroupBy, inputSerializer, asRoot: true); var pushElements = AstExpression.AccumulatorField("_elements", AstUnaryAccumulatorOperator.Push, AstExpression.RootVar); var groupBySerializer = (IBsonSerializer)groupByTranslation.Serializer; diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/SerializationHelper.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/SerializationHelper.cs index 0b34b0bd7cf..ae6b638f51e 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/SerializationHelper.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/SerializationHelper.cs @@ -222,7 +222,7 @@ public static BsonValue SerializeValue(IBsonSerializer serializer, object value) { writer.WriteStartDocument(); writer.WriteName("_v"); - var context = BsonSerializationContext.CreateRoot(writer); + var context = BsonSerializationContext.CreateRoot(writer, BsonSerializer.DefaultSerializationDomain); //QUESTION Is it ok here to use the default domain? serializer.Serialize(context, value); writer.WriteEndDocument(); } @@ -237,7 +237,7 @@ public static BsonArray SerializeValues(IBsonSerializer itemSerializer, IEnumera writer.WriteStartDocument(); writer.WriteName("_v"); writer.WriteStartArray(); - var context = BsonSerializationContext.CreateRoot(writer); + var context = BsonSerializationContext.CreateRoot(writer, BsonSerializer.DefaultSerializationDomain); //QUESTION Is it ok here to use the default domain? foreach(var value in values) { itemSerializer.Serialize(context, value); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/TypeExtensions.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/TypeExtensions.cs index ccb8f699740..8879dbcc20f 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/TypeExtensions.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/TypeExtensions.cs @@ -212,10 +212,11 @@ public static bool IsEnumOrNullableEnum(this Type type, out Type enumType, out T type.IsNullableEnum(out enumType, out underlyingType); } - public static bool IsNullable(this Type type) - { - return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); - } + // Commented out because there is an identical method in Bson assembly (and also in this assembly...). + // public static bool IsNullable(this Type type) + // { + // return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); + // } public static bool IsNullable(this Type type, out Type valueType) { @@ -231,10 +232,11 @@ public static bool IsNullable(this Type type, out Type valueType) } } - public static bool IsNullableEnum(this Type type) - { - return type.IsNullable(out var valueType) && valueType.IsEnum; - } + // Commented out because there is an identical method in Bson assembly. + // public static bool IsNullableEnum(this Type type) + // { + // return type.IsNullable(out var valueType) && valueType.IsEnum; + // } public static bool IsNullableEnum(this Type type, out Type enumType, out Type underlyingType) { diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs index 2717a7e71d7..9156ead8290 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/MongoQueryProvider.cs @@ -64,6 +64,7 @@ internal sealed class MongoQueryProvider : MongoQueryProvider private readonly IMongoDatabase _database; private ExecutableQuery _executedQuery; private readonly IBsonSerializer _pipelineInputSerializer; + private readonly IBsonSerializationDomain _serializationDomain; // constructors public MongoQueryProvider( @@ -74,6 +75,7 @@ public MongoQueryProvider( { _collection = Ensure.IsNotNull(collection, nameof(collection)); _pipelineInputSerializer = collection.DocumentSerializer; + _serializationDomain = collection.Settings?.SerializationDomain ?? BsonSerializer.DefaultSerializationDomain; } public MongoQueryProvider( @@ -84,15 +86,18 @@ public MongoQueryProvider( { _database = Ensure.IsNotNull(database, nameof(database)); _pipelineInputSerializer = NoPipelineInputSerializer.Instance; + _serializationDomain = _database.Settings.SerializationDomain; } internal MongoQueryProvider( IBsonSerializer pipelineInputSerializer, IClientSessionHandle session, - AggregateOptions options) + AggregateOptions options, + IBsonSerializationDomain serializationDomain) : base(session, options) { _pipelineInputSerializer = Ensure.IsNotNull(pipelineInputSerializer, nameof(pipelineInputSerializer)); + _serializationDomain = Ensure.IsNotNull(serializationDomain, nameof(serializationDomain)); } // public properties @@ -101,6 +106,7 @@ internal MongoQueryProvider( public IMongoDatabase Database => _database; public override BsonDocument[] LoggedStages => _executedQuery?.LoggedStages; public override IBsonSerializer PipelineInputSerializer => _pipelineInputSerializer; + public IBsonSerializationDomain SerializationDomain => _serializationDomain; // public methods public override IQueryable CreateQuery(Expression expression) diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Serializers/ISetWindowFieldsPartitionSerializer.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Serializers/ISetWindowFieldsPartitionSerializer.cs index 2be9f49a1b3..69ccc07e370 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Serializers/ISetWindowFieldsPartitionSerializer.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Serializers/ISetWindowFieldsPartitionSerializer.cs @@ -61,13 +61,11 @@ public void Serialize(BsonSerializationContext context, BsonSerializationArgs ar throw new InvalidOperationException("This serializer is not intended to be used."); } - public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) { throw new InvalidOperationException("This serializer is not intended to be used."); } - object IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { throw new InvalidOperationException("This serializer is not intended to be used."); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/DiscriminatorAstExpression.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/DiscriminatorAstExpression.cs index 8baf59592fc..9c3b573f1f8 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/DiscriminatorAstExpression.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/DiscriminatorAstExpression.cs @@ -16,6 +16,7 @@ using System; using System.Linq; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Conventions; using MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions; @@ -23,17 +24,17 @@ namespace MongoDB.Driver.Linq.Linq3Implementation.Translators; internal static class DiscriminatorAstExpression { - public static AstExpression TypeEquals(AstGetFieldExpression discriminatorField, IDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType) + public static AstExpression TypeEquals(AstGetFieldExpression discriminatorField, IDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType, IBsonSerializationDomain serializationDomain) { - var discriminator = discriminatorConvention.GetDiscriminator(nominalType, actualType); + var discriminator = discriminatorConvention.GetDiscriminatorInternal(nominalType, actualType, serializationDomain); return discriminator == null ? AstExpression.IsMissing(discriminatorField) : AstExpression.Eq(discriminatorField, discriminator); } - public static AstExpression TypeIs(AstGetFieldExpression discriminatorField, IHierarchicalDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType) + public static AstExpression TypeIs(AstGetFieldExpression discriminatorField, IHierarchicalDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType, IBsonSerializationDomain serializationDomain) { - var discriminator = discriminatorConvention.GetDiscriminator(nominalType, actualType); + var discriminator = discriminatorConvention.GetDiscriminatorInternal(nominalType, actualType, serializationDomain); var lastItem = discriminator is BsonArray array ? array.Last() : discriminator; return AstExpression.Cond( AstExpression.Eq(AstExpression.Type(discriminatorField), "array"), @@ -41,9 +42,9 @@ public static AstExpression TypeIs(AstGetFieldExpression discriminatorField, IHi AstExpression.Eq(discriminatorField, lastItem)); } - public static AstExpression TypeIs(AstGetFieldExpression discriminatorField, IScalarDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType) + public static AstExpression TypeIs(AstGetFieldExpression discriminatorField, IScalarDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType, IBsonSerializationDomain serializationDomain) { - var discriminators = discriminatorConvention.GetDiscriminatorsForTypeAndSubTypes(actualType); + var discriminators = discriminatorConvention.GetDiscriminatorsForTypeAndSubTypesInternal(actualType, serializationDomain); return discriminators.Length == 1 ? AstExpression.Eq(discriminatorField, discriminators.Single()) : AstExpression.In(discriminatorField, new BsonArray(discriminators)); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/DiscriminatorAstFilter.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/DiscriminatorAstFilter.cs index 76149481b73..8e59861785f 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/DiscriminatorAstFilter.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/DiscriminatorAstFilter.cs @@ -16,6 +16,7 @@ using System; using System.Linq; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Conventions; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Linq.Linq3Implementation.Ast.Filters; @@ -24,9 +25,9 @@ namespace MongoDB.Driver.Linq.Linq3Implementation.Translators; internal static class DiscriminatorAstFilter { - public static AstFilter TypeEquals(AstFilterField discriminatorField, IHierarchicalDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType) + public static AstFilter TypeEquals(AstFilterField discriminatorField, IHierarchicalDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType, IBsonSerializationDomain serializationDomain) { - var discriminator = discriminatorConvention.GetDiscriminator(nominalType, actualType); + var discriminator = discriminatorConvention.GetDiscriminatorInternal(nominalType, actualType, serializationDomain); if (discriminator == null) { return AstFilter.NotExists(discriminatorField); @@ -44,24 +45,24 @@ public static AstFilter TypeEquals(AstFilterField discriminatorField, IHierarchi } } - public static AstFilter TypeEquals(AstFilterField discriminatorField, IDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType) + public static AstFilter TypeEquals(AstFilterField discriminatorField, IDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType, IBsonSerializationDomain serializationDomain) { - var discriminator = discriminatorConvention.GetDiscriminator(nominalType, actualType); + var discriminator = discriminatorConvention.GetDiscriminatorInternal(nominalType, actualType, serializationDomain); return discriminator == null ? AstFilter.NotExists(discriminatorField) : AstFilter.Eq(discriminatorField, discriminator); } - public static AstFieldOperationFilter TypeIs(AstFilterField discriminatorField, IHierarchicalDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType) + public static AstFieldOperationFilter TypeIs(AstFilterField discriminatorField, IHierarchicalDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType, IBsonSerializationDomain serializationDomain) { - var discriminator = discriminatorConvention.GetDiscriminator(nominalType, actualType); + var discriminator = discriminatorConvention.GetDiscriminatorInternal(nominalType, actualType, serializationDomain); var lastItem = discriminator is BsonArray array ? array.Last() : discriminator; return AstFilter.Eq(discriminatorField, lastItem); // will match subclasses also } - public static AstFieldOperationFilter TypeIs(AstFilterField discriminatorField, IScalarDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType) + public static AstFieldOperationFilter TypeIs(AstFilterField discriminatorField, IScalarDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType, IBsonSerializationDomain serializationDomain) { - var discriminators = discriminatorConvention.GetDiscriminatorsForTypeAndSubTypes(actualType); + var discriminators = discriminatorConvention.GetDiscriminatorsForTypeAndSubTypesInternal(actualType, serializationDomain); return discriminators.Length == 1 ? AstFilter.Eq(discriminatorField, discriminators.Single()) : AstFilter.In(discriminatorField, discriminators); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ArrayLengthExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ArrayLengthExpressionToAggregationExpressionTranslator.cs index 4ee3f896769..b7506dd615f 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ArrayLengthExpressionToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ArrayLengthExpressionToAggregationExpressionTranslator.cs @@ -28,7 +28,7 @@ public static TranslatedExpression Translate(TranslationContext context, UnaryEx var arrayExpression = expression.Operand; var arrayTranslation = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, arrayExpression); var ast = AstExpression.Size(arrayTranslation.Ast); - var serializer = BsonSerializer.LookupSerializer(expression.Type); + var serializer = context.SerializationDomain.LookupSerializer(expression.Type); return new TranslatedExpression(expression, ast, serializer); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ConstantExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ConstantExpressionToAggregationExpressionTranslator.cs index 7487627213d..2fbeab82308 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ConstantExpressionToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ConstantExpressionToAggregationExpressionTranslator.cs @@ -23,10 +23,10 @@ namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggreg { internal static class ConstantExpressionToAggregationExpressionTranslator { - public static TranslatedExpression Translate(ConstantExpression constantExpression) + public static TranslatedExpression Translate(TranslationContext context, ConstantExpression constantExpression) { var constantType = constantExpression.Type; - var constantSerializer = StandardSerializers.TryGetSerializer(constantType, out var serializer) ? serializer : BsonSerializer.LookupSerializer(constantType); + var constantSerializer = StandardSerializers.TryGetSerializer(constantType, out var serializer) ? serializer : context.SerializationDomain.LookupSerializer(constantType); return Translate(constantExpression, constantSerializer); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ConvertExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ConvertExpressionToAggregationExpressionTranslator.cs index 532e10c1609..2843eb21327 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ConvertExpressionToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ConvertExpressionToAggregationExpressionTranslator.cs @@ -44,13 +44,13 @@ sourceExpression is UnaryExpression unarySourceExpression && } var sourceTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, sourceExpression); - return Translate(expression, sourceType, targetType, sourceTranslation); + return Translate(expression, sourceType, targetType, sourceTranslation, context.SerializationDomain); } throw new ExpressionNotSupportedException(expression); } - private static TranslatedExpression Translate(UnaryExpression expression, Type sourceType, Type targetType, TranslatedExpression sourceTranslation) + private static TranslatedExpression Translate(UnaryExpression expression, Type sourceType, Type targetType, TranslatedExpression sourceTranslation, IBsonSerializationDomain serializationDomain) { if (targetType == sourceType) { @@ -60,12 +60,12 @@ private static TranslatedExpression Translate(UnaryExpression expression, Type s // from Nullable must be handled before to Nullable if (IsConvertFromNullableType(sourceType)) { - return TranslateConvertFromNullableType(expression, sourceType, targetType, sourceTranslation); + return TranslateConvertFromNullableType(expression, sourceType, targetType, sourceTranslation, serializationDomain); } if (IsConvertToNullableType(targetType)) { - return TranslateConvertToNullableType(expression, sourceType, targetType, sourceTranslation); + return TranslateConvertToNullableType(expression, sourceType, targetType, sourceTranslation, serializationDomain); } // from here on we know there are no longer any Nullable types involved @@ -97,7 +97,7 @@ private static TranslatedExpression Translate(UnaryExpression expression, Type s if (IsConvertToDerivedType(sourceType, targetType)) { - return TranslateConvertToDerivedType(expression, targetType, sourceTranslation); + return TranslateConvertToDerivedType(expression, targetType, sourceTranslation, serializationDomain); } var ast = sourceTranslation.Ast; @@ -177,10 +177,9 @@ private static TranslatedExpression TranslateConvertToBaseType(UnaryExpression e return new TranslatedExpression(expression, sourceTranslation.Ast, downcastingSerializer); } - private static TranslatedExpression TranslateConvertToDerivedType(UnaryExpression expression, Type targetType, TranslatedExpression sourceTranslation) + private static TranslatedExpression TranslateConvertToDerivedType(UnaryExpression expression, Type targetType, TranslatedExpression sourceTranslation, IBsonSerializationDomain serializationDomain) { - var serializer = BsonSerializer.LookupSerializer(targetType); - + var serializer = serializationDomain.LookupSerializer(targetType); return new TranslatedExpression(expression, sourceTranslation.Ast, serializer); } @@ -218,7 +217,7 @@ private static TranslatedExpression TranslateConvertEnumToUnderlyingType(UnaryEx return new TranslatedExpression(expression, sourceTranslation.Ast, targetSerializer); } - private static TranslatedExpression TranslateConvertFromNullableType(UnaryExpression expression, Type sourceType, Type targetType, TranslatedExpression sourceTranslation) + private static TranslatedExpression TranslateConvertFromNullableType(UnaryExpression expression, Type sourceType, Type targetType, TranslatedExpression sourceTranslation, IBsonSerializationDomain serializationDomain) { if (sourceType.IsNullable(out var sourceValueType)) { @@ -226,7 +225,7 @@ private static TranslatedExpression TranslateConvertFromNullableType(UnaryExpres var sourceNullableSerializer = (INullableSerializer)sourceTranslation.Serializer; var sourceValueSerializer = sourceNullableSerializer.ValueSerializer; var sourceValueTranslation = new TranslatedExpression(expression.Operand, sourceAst, sourceValueSerializer); - var convertTranslation = Translate(expression, sourceValueType, targetType, sourceValueTranslation); + var convertTranslation = Translate(expression, sourceValueType, targetType, sourceValueTranslation, serializationDomain); // note: we would have liked to throw a query execution error here if the value is null and the target type is not nullable but there is no way to do that in MQL // so we just return null instead and the user must check for null themselves if they want to define what happens when the value is null @@ -242,7 +241,7 @@ private static TranslatedExpression TranslateConvertFromNullableType(UnaryExpres throw new ExpressionNotSupportedException(expression, because: "sourceType is not nullable"); } - private static TranslatedExpression TranslateConvertToNullableType(UnaryExpression expression, Type sourceType, Type targetType, TranslatedExpression sourceTranslation) + private static TranslatedExpression TranslateConvertToNullableType(UnaryExpression expression, Type sourceType, Type targetType, TranslatedExpression sourceTranslation, IBsonSerializationDomain serializationDomain) { if (sourceType.IsNullable()) { @@ -252,7 +251,7 @@ private static TranslatedExpression TranslateConvertToNullableType(UnaryExpressi if (targetType.IsNullable(out var targetValueType)) { - var convertTranslation = Translate(expression, sourceType, targetValueType, sourceTranslation); + var convertTranslation = Translate(expression, sourceType, targetValueType, sourceTranslation, serializationDomain); var nullableSerializer = NullableSerializer.Create(convertTranslation.Serializer); return new TranslatedExpression(expression, convertTranslation.Ast, nullableSerializer); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ExpressionToAggregationExpressionTranslator.cs index c2d8e0010e9..5eeb2857f9a 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ExpressionToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ExpressionToAggregationExpressionTranslator.cs @@ -67,7 +67,7 @@ public static TranslatedExpression Translate(TranslationContext context, Express case ExpressionType.Conditional: return ConditionalExpressionToAggregationExpressionTranslator.Translate(context, (ConditionalExpression)expression); case ExpressionType.Constant: - return ConstantExpressionToAggregationExpressionTranslator.Translate((ConstantExpression)expression); + return ConstantExpressionToAggregationExpressionTranslator.Translate(context, (ConstantExpression)expression); case ExpressionType.Index: return IndexExpressionToAggregationExpressionTranslator.Translate(context, (IndexExpression)expression); case ExpressionType.ListInit: diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/GetTypeComparisonExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/GetTypeComparisonExpressionToAggregationExpressionTranslator.cs index ba26f5e4279..fdb75dc393d 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/GetTypeComparisonExpressionToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/GetTypeComparisonExpressionToAggregationExpressionTranslator.cs @@ -40,9 +40,9 @@ public static TranslatedExpression Translate(TranslationContext context, BinaryE var nominalType = objectExpression.Type; var actualType = comparandType; - var discriminatorConvention = objectTranslation.Serializer.GetDiscriminatorConvention(); + var discriminatorConvention = objectTranslation.Serializer.GetDiscriminatorConvention(context.SerializationDomain); var discriminatorField = AstExpression.GetField(objectTranslation.Ast, discriminatorConvention.ElementName); - var ast = DiscriminatorAstExpression.TypeEquals(discriminatorField, discriminatorConvention, nominalType, actualType); + var ast = DiscriminatorAstExpression.TypeEquals(discriminatorField, discriminatorConvention, nominalType, actualType, context.SerializationDomain); return new TranslatedExpression(expression, ast, BooleanSerializer.Instance); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MemberInitExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MemberInitExpressionToAggregationExpressionTranslator.cs index 20f7e81312c..de959f5dc37 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MemberInitExpressionToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MemberInitExpressionToAggregationExpressionTranslator.cs @@ -70,7 +70,7 @@ public static TranslatedExpression Translate( var constructorArgumentExpression = constructorArguments[i]; var constructorArgumentTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, constructorArgumentExpression); var constructorArgumentType = constructorArgumentExpression.Type; - var constructorArgumentSerializer = constructorArgumentTranslation.Serializer ?? BsonSerializer.LookupSerializer(constructorArgumentType); + var constructorArgumentSerializer = constructorArgumentTranslation.Serializer ?? context.SerializationDomain.LookupSerializer(constructorArgumentType); var memberMap = EnsureMemberMap(expression, classMap, creatorMapParameter); EnsureDefaultValue(memberMap); var memberSerializer = CoerceSourceSerializerToMemberSerializer(memberMap, constructorArgumentSerializer); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CeilingMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CeilingMethodToAggregationExpressionTranslator.cs index fa0aca10c72..7be49cff330 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CeilingMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CeilingMethodToAggregationExpressionTranslator.cs @@ -36,7 +36,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC var argumentAst = ConvertHelper.RemoveWideningConvert(argumentTranslation); var ast = AstExpression.Ceil(argumentAst); - var serializer = BsonSerializer.LookupSerializer(expression.Type); + var serializer = context.SerializationDomain.LookupSerializer(expression.Type); return new TranslatedExpression(expression, ast, serializer); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ConstantMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ConstantMethodToAggregationExpressionTranslator.cs index 0d977502d8a..47b39ab3e75 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ConstantMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ConstantMethodToAggregationExpressionTranslator.cs @@ -40,7 +40,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC { var representationExpression = arguments[1]; var representation = representationExpression.GetConstantValue(expression); - var registeredSerializer = BsonSerializer.LookupSerializer(valueExpression.Type); + var registeredSerializer = context.SerializationDomain.LookupSerializer(valueExpression.Type); if (registeredSerializer is IRepresentationConfigurable representationConfigurableSerializer) { serializer = representationConfigurableSerializer.WithRepresentation(representation); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/FloorMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/FloorMethodToAggregationExpressionTranslator.cs index 7af7b22ae97..ac811564c54 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/FloorMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/FloorMethodToAggregationExpressionTranslator.cs @@ -36,7 +36,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC var argumentAst = ConvertHelper.RemoveWideningConvert(argumentTranslation); var ast = AstExpression.Floor(argumentAst); - var serializer = BsonSerializer.LookupSerializer(expression.Type); + var serializer = context.SerializationDomain.LookupSerializer(expression.Type); return new TranslatedExpression(expression, ast, serializer); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/OfTypeMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/OfTypeMethodToAggregationExpressionTranslator.cs index 5ce6bbe01f1..bad75106f3b 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/OfTypeMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/OfTypeMethodToAggregationExpressionTranslator.cs @@ -56,7 +56,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC var nominalType = itemSerializer.ValueType; var nominalTypeSerializer = itemSerializer; var actualType = method.GetGenericArguments().Single(); - var actualTypeSerializer = BsonSerializer.LookupSerializer(actualType); + var actualTypeSerializer = context.SerializationDomain.LookupSerializer(actualType); AstExpression ast; if (nominalType == actualType) @@ -65,14 +65,14 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC } else { - var discriminatorConvention = nominalTypeSerializer.GetDiscriminatorConvention(); + var discriminatorConvention = nominalTypeSerializer.GetDiscriminatorConvention(context.SerializationDomain); var itemVar = AstExpression.Var("item"); var discriminatorField = AstExpression.GetField(itemVar, discriminatorConvention.ElementName); var ofTypeExpression = discriminatorConvention switch { - IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstExpression.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType), - IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstExpression.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType), + IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstExpression.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType, context.SerializationDomain), + IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstExpression.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType, context.SerializationDomain), _ => throw new ExpressionNotSupportedException(expression, because: "OfType is not supported with the configured discriminator convention") }; diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/PickMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/PickMethodToAggregationExpressionTranslator.cs index ae21565dc68..59e6d27737e 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/PickMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/PickMethodToAggregationExpressionTranslator.cs @@ -115,7 +115,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC { var sortByExpression = arguments[1]; var sortByDefinition = GetSortByDefinition(sortByExpression, expression); - sortBy = TranslateSortByDefinition(expression, sortByExpression, sortByDefinition, itemSerializer, context.TranslationOptions); + sortBy = TranslateSortByDefinition(context, expression, sortByExpression, sortByDefinition, itemSerializer); } var selectorLambda = (LambdaExpression)GetSelectorArgument(method, arguments); @@ -274,27 +274,26 @@ keyTranslation.Ast is AstGetFieldExpression getFieldExpression && } private static AstSortFields TranslateSortByDefinition( + TranslationContext context, Expression expression, Expression sortByExpression, object sortByDefinition, - IBsonSerializer documentSerializer, - ExpressionTranslationOptions translationOptions) + IBsonSerializer documentSerializer) { var methodInfoDefinition = typeof(PickMethodToAggregationExpressionTranslator).GetMethod(nameof(TranslateSortByDefinitionGeneric), BindingFlags.Static | BindingFlags.NonPublic); var documentType = documentSerializer.ValueType; var methodInfo = methodInfoDefinition.MakeGenericMethod(documentType); - return (AstSortFields)methodInfo.Invoke(null, new object[] { expression, sortByExpression, sortByDefinition, documentSerializer, translationOptions }); + return (AstSortFields)methodInfo.Invoke(null, new object[] { context, expression, sortByExpression, sortByDefinition, documentSerializer }); } private static AstSortFields TranslateSortByDefinitionGeneric( + TranslationContext context, Expression expression, Expression sortByExpression, SortDefinition sortByDefinition, - IBsonSerializer documentSerializer, - ExpressionTranslationOptions translationOptions) + IBsonSerializer documentSerializer) { - var serializerRegistry = BsonSerializer.SerializerRegistry; - var sortDocument = sortByDefinition.Render(new(documentSerializer, serializerRegistry, translationOptions: translationOptions)); + var sortDocument = sortByDefinition.Render(new(documentSerializer, context.SerializationDomain, translationOptions: context.TranslationOptions)); var fields = new List(); foreach (var element in sortDocument) { diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/StandardDeviationMethodsToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/StandardDeviationMethodsToAggregationExpressionTranslator.cs index d0f9079dcd9..99ab331d70f 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/StandardDeviationMethodsToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/StandardDeviationMethodsToAggregationExpressionTranslator.cs @@ -48,12 +48,12 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC input: sourceTranslation.Ast, @as: selectorParameterSymbol.Var, @in: selectorTranslation.Ast); - var selectorResultSerializer = BsonSerializer.LookupSerializer(selectorLambda.ReturnType); + var selectorResultSerializer = context.SerializationDomain.LookupSerializer(selectorLambda.ReturnType); sourceTranslation = new TranslatedExpression(selectorLambda, selectorAst, selectorResultSerializer); } var ast = AstExpression.StdDev(stddevOperator, sourceTranslation.Ast); - var serializer = BsonSerializer.LookupSerializer(expression.Type); + var serializer = context.SerializationDomain.LookupSerializer(expression.Type); return new TranslatedExpression(expression, ast, serializer); } } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WindowMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WindowMethodToAggregationExpressionTranslator.cs index f45cffc3e49..501b56dec22 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WindowMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WindowMethodToAggregationExpressionTranslator.cs @@ -325,7 +325,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC { var @operator = GetNullaryWindowOperator(method); var ast = AstExpression.NullaryWindowExpression(@operator, window); - var serializer = BsonSerializer.LookupSerializer(method.ReturnType); // TODO: use correct serializer + var serializer = context.SerializationDomain.LookupSerializer(method.ReturnType); // TODO: use correct serializer return new TranslatedExpression(expression, ast, serializer); } @@ -340,7 +340,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC ThrowIfSelectorTranslationIsNull(selectorTranslation); var @operator = GetUnaryWindowOperator(method); var ast = AstExpression.UnaryWindowExpression(@operator, selectorTranslation.Ast, window); - var serializer = BsonSerializer.LookupSerializer(method.ReturnType); // TODO: use correct serializer + var serializer = context.SerializationDomain.LookupSerializer(method.ReturnType); // TODO: use correct serializer return new TranslatedExpression(expression, ast, serializer); } @@ -353,7 +353,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC var @operator = GetBinaryWindowOperator(method); var ast = AstExpression.BinaryWindowExpression(@operator, selector1Translation.Ast, selector2Translation.Ast, window); - var serializer = BsonSerializer.LookupSerializer(method.ReturnType); // TODO: use correct serializer + var serializer = context.SerializationDomain.LookupSerializer(method.ReturnType); // TODO: use correct serializer return new TranslatedExpression(expression, ast, serializer); } @@ -368,7 +368,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC var @operator = GetDerivativeOrIntegralWindowOperator(method); var ast = AstExpression.DerivativeOrIntegralWindowExpression(@operator, selectorTranslation.Ast, unit, window); - var serializer = BsonSerializer.LookupSerializer(method.ReturnType); // TODO: use correct serializer + var serializer = context.SerializationDomain.LookupSerializer(method.ReturnType); // TODO: use correct serializer return new TranslatedExpression(expression, ast, serializer); } @@ -379,7 +379,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC var weighting = weightingExpression.GetConstantValue(expression); var ast = AstExpression.ExponentialMovingAverageWindowExpression(selectorTranslation.Ast, weighting, window); - var serializer = BsonSerializer.LookupSerializer(method.ReturnType); // TODO: use correct serializer + var serializer = context.SerializationDomain.LookupSerializer(method.ReturnType); // TODO: use correct serializer return new TranslatedExpression(expression, ast, serializer); } @@ -419,7 +419,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC } var ast = AstExpression.ShiftWindowExpression(selectorTranslation.Ast, by, defaultValue); - var serializer = BsonSerializer.LookupSerializer(method.ReturnType); // TODO: use correct serializer + var serializer = context.SerializationDomain.LookupSerializer(method.ReturnType); // TODO: use correct serializer return new TranslatedExpression(expression, ast, serializer); } } @@ -525,15 +525,14 @@ private static AstWindow TranslateWindow(TranslationContext context, Expression { var windowConstant = windowExpression.GetConstantValue(expression); var sortBy = context.Data?.GetValueOrDefault("SortBy", null); - var serializerRegistry = context.Data?.GetValueOrDefault("SerializerRegistry", null); - return ToAstWindow(windowConstant, sortBy, inputSerializer, serializerRegistry, context.TranslationOptions); + return ToAstWindow(windowConstant, sortBy, inputSerializer, context.SerializationDomain, context.TranslationOptions); } private static AstWindow ToAstWindow( SetWindowFieldsWindow window, object sortBy, IBsonSerializer inputSerializer, - BsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) { if (window == null) @@ -560,7 +559,7 @@ private static AstWindow ToAstWindow( IBsonSerializer upperBoundaryValueSerializer = null; if (lowerValueBoundary != null || upperValueBoundary != null) { - var sortBySerializer = GetSortBySerializer(sortBy, inputSerializer, serializerRegistry, translationOptions); + var sortBySerializer = GetSortBySerializer(sortBy, inputSerializer, serializationDomain, translationOptions); if (lowerValueBoundary != null) { lowerBoundaryValueSerializer = ValueRangeWindowBoundaryConvertingValueSerializerFactory.Create(lowerValueBoundary, sortBySerializer); @@ -587,7 +586,7 @@ private static AstWindow ToAstWindow( private static IBsonSerializer GetSortBySerializer( object sortBy, IBsonSerializer inputSerializer, - BsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) { Ensure.IsNotNull(sortBy, nameof(sortBy)); @@ -599,13 +598,13 @@ private static IBsonSerializer GetSortBySerializer( nameof(GetSortBySerializerGeneric), BindingFlags.NonPublic | BindingFlags.Static); var methodInfo = methodInfoDefinition.MakeGenericMethod(documentType); - return (IBsonSerializer)methodInfo.Invoke(null, new object[] { sortBy, inputSerializer, serializerRegistry, translationOptions }); + return (IBsonSerializer)methodInfo.Invoke(null, new object[] { sortBy, inputSerializer, serializationDomain, translationOptions }); } private static IBsonSerializer GetSortBySerializerGeneric( SortDefinition sortBy, IBsonSerializer documentSerializer, - BsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) { var directionalSortBy = sortBy as DirectionalSortDefinition; @@ -619,7 +618,7 @@ private static IBsonSerializer GetSortBySerializerGeneric( } var field = directionalSortBy.Field; - var renderedField = field.Render(new(documentSerializer, serializerRegistry, translationOptions: translationOptions)); + var renderedField = field.Render(new(documentSerializer, serializationDomain, translationOptions: translationOptions)); return renderedField.FieldSerializer; } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ZipMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ZipMethodToAggregationExpressionTranslator.cs index 259af4e59c6..b0ea6c8a2c6 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ZipMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ZipMethodToAggregationExpressionTranslator.cs @@ -47,8 +47,8 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC var resultSelectorParameters = resultSelectorLambda.Parameters; var resultSelectorParameter1 = resultSelectorParameters[0]; var resultSelectorParameter2 = resultSelectorParameters[1]; - var resultSelectorSymbol1 = context.CreateSymbol(resultSelectorParameter1, BsonSerializer.LookupSerializer(resultSelectorParameter1.Type)); - var resultSelectorSymbol2 = context.CreateSymbol(resultSelectorParameter2, BsonSerializer.LookupSerializer(resultSelectorParameter2.Type)); + var resultSelectorSymbol1 = context.CreateSymbol(resultSelectorParameter1, context.SerializationDomain.LookupSerializer(resultSelectorParameter1.Type)); + var resultSelectorSymbol2 = context.CreateSymbol(resultSelectorParameter2, context.SerializationDomain.LookupSerializer(resultSelectorParameter2.Type)); var resultSelectorContext = context.WithSymbols(resultSelectorSymbol1, resultSelectorSymbol2); var resultSelectorTranslation = ExpressionToAggregationExpressionTranslator.Translate(resultSelectorContext, resultSelectorLambda.Body); var @as = AstExpression.Var("pair"); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewArrayInitExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewArrayInitExpressionToAggregationExpressionTranslator.cs index c5eba340536..a2abd8b8e87 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewArrayInitExpressionToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewArrayInitExpressionToAggregationExpressionTranslator.cs @@ -45,7 +45,7 @@ public static TranslatedExpression Translate(TranslationContext context, NewArra var arrayType = expression.Type; var itemType = arrayType.GetElementType(); - itemSerializer ??= BsonSerializer.LookupSerializer(itemType); // if the array is empty itemSerializer will be null + itemSerializer ??= context.SerializationDomain.LookupSerializer(itemType); // if the array is empty itemSerializer will be null var arraySerializerType = typeof(ArraySerializer<>).MakeGenericType(itemType); var arraySerializer = (IBsonSerializer)Activator.CreateInstance(arraySerializerType, itemSerializer); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/TypeIsExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/TypeIsExpressionToAggregationExpressionTranslator.cs index defda7b972b..07badb1e8c4 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/TypeIsExpressionToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/TypeIsExpressionToAggregationExpressionTranslator.cs @@ -39,13 +39,13 @@ public static TranslatedExpression Translate(TranslationContext context, TypeBin } else { - var discriminatorConvention = objectTranslation.Serializer.GetDiscriminatorConvention(); + var discriminatorConvention = objectTranslation.Serializer.GetDiscriminatorConvention(context.SerializationDomain); var discriminatorField = AstExpression.GetField(objectTranslation.Ast, discriminatorConvention.ElementName); ast = discriminatorConvention switch { - IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstExpression.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType), - IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstExpression.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType), + IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstExpression.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType, context.SerializationDomain), + IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstExpression.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType, context.SerializationDomain), _ => throw new ExpressionNotSupportedException(expression, because: "is operator is not supported with the configured discriminator convention") }; } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/ExpressionToExecutableQueryTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/ExpressionToExecutableQueryTranslator.cs index b96a193e323..a838b8051f6 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/ExpressionToExecutableQueryTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/ExpressionToExecutableQueryTranslator.cs @@ -31,7 +31,7 @@ public static ExecutableQuery> Translate TranslateScalar Translate(MongoQuer valueAst = AstExpression.GetField(AstExpression.RootVar, "_v"); } var outputValueType = expression.GetResultType(); - var outputValueSerializer = BsonSerializer.LookupSerializer(outputValueType); + var outputValueSerializer = context.SerializationDomain.LookupSerializer(outputValueType); var outputWrappedValueSerializer = WrappedValueSerializer.Create("_v", outputValueSerializer); pipeline = pipeline.AddStages( diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/SumMethodToExecutableQueryTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/SumMethodToExecutableQueryTranslator.cs index 0e44e945fd7..3ee5b352757 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/SumMethodToExecutableQueryTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/SumMethodToExecutableQueryTranslator.cs @@ -135,7 +135,7 @@ public static ExecutableQuery Translate(MongoQuer } var outputValueType = expression.GetResultType(); - var outputValueSerializer = BsonSerializer.LookupSerializer(outputValueType); + var outputValueSerializer = context.SerializationDomain.LookupSerializer(outputValueType); var outputWrappedValueSerializer = WrappedValueSerializer.Create("_v", outputValueSerializer); pipeline = pipeline.AddStages( diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/GetTypeComparisonExpressionToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/GetTypeComparisonExpressionToFilterTranslator.cs index bbcddc7e29c..32bc3938907 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/GetTypeComparisonExpressionToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/GetTypeComparisonExpressionToFilterTranslator.cs @@ -55,13 +55,13 @@ public static AstFilter Translate( var nominalType = fieldTranslation.Serializer.ValueType; var actualType = typeConstantExpression.GetConstantValue(expression); - var discriminatorConvention = fieldTranslation.Serializer.GetDiscriminatorConvention(); + var discriminatorConvention = fieldTranslation.Serializer.GetDiscriminatorConvention(context.SerializationDomain); var discriminatorField = fieldTranslation.Ast.SubField(discriminatorConvention.ElementName); var filter = discriminatorConvention switch { - IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstFilter.TypeEquals(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType), - _ => DiscriminatorAstFilter.TypeEquals(discriminatorField, discriminatorConvention, nominalType, actualType), + IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstFilter.TypeEquals(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType, context.SerializationDomain), + _ => DiscriminatorAstFilter.TypeEquals(discriminatorField, discriminatorConvention, nominalType, actualType, context.SerializationDomain), }; return comparisonOperator switch diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/TypeIsExpressionToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/TypeIsExpressionToFilterTranslator.cs index 691e310febd..eed84283da1 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/TypeIsExpressionToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/TypeIsExpressionToFilterTranslator.cs @@ -41,13 +41,13 @@ public static AstFilter Translate(TranslationContext context, TypeBinaryExpressi } else { - var discriminatorConvention = fieldTranslation.Serializer.GetDiscriminatorConvention(); + var discriminatorConvention = fieldTranslation.Serializer.GetDiscriminatorConvention(context.SerializationDomain); var discriminatorField = fieldTranslation.Ast.SubField(discriminatorConvention.ElementName); return discriminatorConvention switch { - IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType), - IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType), + IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType, context.SerializationDomain), + IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType, context.SerializationDomain), _ => throw new ExpressionNotSupportedException(expression, because: "is operator is not supported with the configured discriminator convention") }; } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/AllOrAnyMethodToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/AllOrAnyMethodToFilterTranslator.cs index abb59233f3c..157bd2a87c6 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/AllOrAnyMethodToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/AllOrAnyMethodToFilterTranslator.cs @@ -120,17 +120,17 @@ public static (TranslatedFilterField, AstFilter) Translate(TranslationContext co var sourceSerializer = fieldTranslation.Serializer; var itemSerializer = ArraySerializerHelper.GetItemSerializer(sourceSerializer); - var discriminatorConvention = itemSerializer.GetDiscriminatorConvention(); + var discriminatorConvention = itemSerializer.GetDiscriminatorConvention(context.SerializationDomain); var discriminatorField = AstFilter.Field(discriminatorConvention.ElementName); var ofTypeFilter = discriminatorConvention switch { - IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType), - IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType), + IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType, context.SerializationDomain), + IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType, context.SerializationDomain), _ => throw new ExpressionNotSupportedException(sourceExpression, because: "OfType method is not supported with the configured discriminator convention") }; - var actualTypeSerializer = BsonSerializer.LookupSerializer(actualType); + var actualTypeSerializer = context.SerializationDomain.LookupSerializer(actualType); var enumerableActualTypeSerializer = IEnumerableSerializer.Create(actualTypeSerializer); var actualTypeSourceField = new TranslatedFilterField(fieldTranslation.Ast, enumerableActualTypeSerializer); var combinedFilter = AstFilter.Combine(sourceFilter, ofTypeFilter); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/InjectMethodToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/InjectMethodToFilterTranslator.cs index a21ed9d567e..67d09688419 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/InjectMethodToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/InjectMethodToFilterTranslator.cs @@ -58,10 +58,9 @@ public static AstFilter Translate(TranslationContext context, MethodCallExpressi { throw new ExpressionNotSupportedException(expression, because: $"FilterDefinition TDocument type: {filterDefinitionDocumentType} does not match document type {documentSerializer.ValueType} "); } - var serializerRegistry = BsonSerializer.SerializerRegistry; var renderFilterMethod = __renderFilterMethodInfo.MakeGenericMethod(filterDefinitionDocumentType); - var renderedFilter = (BsonDocument)renderFilterMethod.Invoke(null, new[] { filterDefinition, documentSerializer, serializerRegistry, context.TranslationOptions }); + var renderedFilter = (BsonDocument)renderFilterMethod.Invoke(null, new[] { filterDefinition, documentSerializer, context.SerializationDomain, context.TranslationOptions }); return AstFilter.Raw(renderedFilter); } @@ -73,8 +72,8 @@ public static AstFilter Translate(TranslationContext context, MethodCallExpressi private static BsonDocument RenderFilter( FilterDefinition filterDefinition, IBsonSerializer documentSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) => - filterDefinition.Render(new(documentSerializer, serializerRegistry, translationOptions: translationOptions)); + filterDefinition.Render(new(documentSerializer, serializationDomain, translationOptions: translationOptions)); } } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/ConvertExpressionToFilterFieldTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/ConvertExpressionToFilterFieldTranslator.cs index 7a734d7a075..40889bf9aef 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/ConvertExpressionToFilterFieldTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/ConvertExpressionToFilterFieldTranslator.cs @@ -66,7 +66,7 @@ public static TranslatedFilterField Translate(TranslationContext context, UnaryE if (IsConvertToDerivedType(fieldType, targetType)) { - return TranslateConvertToDerivedType(fieldTranslation, targetType); + return TranslateConvertToDerivedType(fieldTranslation, targetType, context.SerializationDomain); } } @@ -165,9 +165,9 @@ private static TranslatedFilterField TranslateConvertToBaseType(TranslatedFilter return new TranslatedFilterField(fieldTranslation.Ast, targetSerializer); } - private static TranslatedFilterField TranslateConvertToDerivedType(TranslatedFilterField fieldTranslation, Type targetType) + private static TranslatedFilterField TranslateConvertToDerivedType(TranslatedFilterField fieldTranslation, Type targetType, IBsonSerializationDomain serializationDomain) { - var targetSerializer = BsonSerializer.LookupSerializer(targetType); + var targetSerializer = serializationDomain.LookupSerializer(targetType); return new TranslatedFilterField(fieldTranslation.Ast, targetSerializer); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/AppendStageMethodToPipelineTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/AppendStageMethodToPipelineTranslator.cs index f226a6d504f..56e9acd51aa 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/AppendStageMethodToPipelineTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/AppendStageMethodToPipelineTranslator.cs @@ -39,7 +39,7 @@ public static TranslatedPipeline Translate(TranslationContext context, MethodCal var sourceSerializer = pipeline.OutputSerializer; var stageExpression = arguments[1]; - var renderedStage = TranslateStage(expression, stageExpression, sourceSerializer, BsonSerializer.SerializerRegistry, context.TranslationOptions); + var renderedStage = TranslateStage(expression, stageExpression, sourceSerializer, context.SerializationDomain, context.TranslationOptions); var stage = AstStage.Universal(renderedStage.Document); var resultSerializerExpression = arguments[2]; @@ -57,11 +57,11 @@ private static IRenderedPipelineStageDefinition TranslateStage( Expression expression, Expression stageExpression, IBsonSerializer inputSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) { - var stageDefinition = stageExpression.GetConstantValue(stageExpression); - return stageDefinition.Render(inputSerializer, serializerRegistry, translationOptions); + var stageDefinition = stageExpression.GetConstantValue(stageExpression); + return stageDefinition.Render(inputSerializer, serializationDomain, translationOptions); } } } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/AsMethodToPipelineTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/AsMethodToPipelineTranslator.cs index a7426d8e69c..60bd66c5a59 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/AsMethodToPipelineTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/AsMethodToPipelineTranslator.cs @@ -41,7 +41,7 @@ public static TranslatedPipeline Translate(TranslationContext context, MethodCal var resultSerializerExpression = arguments[1]; var resultSerializer = resultSerializerExpression.GetConstantValue(expression); var resultType = method.GetGenericArguments()[1]; - var outputSerializer = resultSerializer ?? BsonSerializer.LookupSerializer(resultType); + var outputSerializer = resultSerializer ?? context.SerializationDomain.LookupSerializer(resultType); pipeline = pipeline.WithNewOutputSerializer(outputSerializer); return pipeline; diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/ConcatMethodToPipelineTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/ConcatMethodToPipelineTranslator.cs index 03fb1ecb1b7..ccaec5bdc73 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/ConcatMethodToPipelineTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/ConcatMethodToPipelineTranslator.cs @@ -44,7 +44,7 @@ secondProvider.CollectionNamespace is var secondCollectionNamespace && secondCollectionNamespace != null) { var secondCollectionName = secondCollectionNamespace.CollectionName; - var secondContext = TranslationContext.Create(context.TranslationOptions); + var secondContext = TranslationContext.Create(context.TranslationOptions, context.SerializationDomain); var secondPipeline = ExpressionToPipelineTranslator.Translate(secondContext, secondQueryable.Expression); if (secondPipeline.Ast.Stages.Count == 0) { diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/DocumentsMethodToPipelineTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/DocumentsMethodToPipelineTranslator.cs index 6f7ae7a9a3f..c03f0a8725d 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/DocumentsMethodToPipelineTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/DocumentsMethodToPipelineTranslator.cs @@ -58,7 +58,7 @@ public static TranslatedPipeline Translate(TranslationContext context, MethodCal else { var documentType = method.GetGenericArguments()[0]; - documentSerializer = BsonSerializer.LookupSerializer(documentType); + documentSerializer = context.SerializationDomain.LookupSerializer(documentType); } var serializedDocuments = SerializationHelper.SerializeValues(documentSerializer, documents); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/LookupMethodToPipelineTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/LookupMethodToPipelineTranslator.cs index 93916b46c90..bcb31d605ff 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/LookupMethodToPipelineTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/LookupMethodToPipelineTranslator.cs @@ -281,12 +281,12 @@ private static TranslatedPipeline TranslateDocumentsPipelineGeneric(documentSerializer, session: null, options: null); + var provider = new MongoQueryProvider(documentSerializer, session: null, options: null, serializationDomain: context.SerializationDomain); var queryable = new MongoQuery(provider); body = ExpressionReplacer.Replace(body, queryableParameter, Expression.Constant(queryable)); @@ -332,7 +332,7 @@ private static TranslatedPipeline TranslateLookupPipelineAgainstQueryable DiscriminatorAstFilter.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType), - IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType), + IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType, context.SerializationDomain), + IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType, context.SerializationDomain), _ => throw new ExpressionNotSupportedException(expression, because: "OfType is not supported with the configured discriminator convention") }; - var resultSerializer = BsonSerializer.LookupSerializer(actualType); + var resultSerializer = context.SerializationDomain.LookupSerializer(actualType); if (wrappedValueOutputSerializer != null) { resultSerializer = WrappedValueSerializer.Create(wrappedValueOutputSerializer.FieldName, resultSerializer); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/UnionMethodToPipelineTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/UnionMethodToPipelineTranslator.cs index 6e2cd53e465..b7734723a6c 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/UnionMethodToPipelineTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/UnionMethodToPipelineTranslator.cs @@ -46,7 +46,7 @@ secondProvider.CollectionNamespace is var secondCollectionNamespace && secondCollectionNamespace != null) { var secondCollectionName = secondCollectionNamespace.CollectionName; - var secondContext = TranslationContext.Create(context.TranslationOptions); + var secondContext = TranslationContext.Create(context.TranslationOptions, context.SerializationDomain); var secondPipeline = ExpressionToPipelineTranslator.Translate(secondContext, secondQueryable.Expression); if (secondPipeline.Ast.Stages.Count == 0) { diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/TranslationContext.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/TranslationContext.cs index b14afedd614..41e037c2453 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/TranslationContext.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/TranslationContext.cs @@ -26,17 +26,19 @@ internal class TranslationContext #region static public static TranslationContext Create( ExpressionTranslationOptions translationOptions, + IBsonSerializationDomain serializationDomain, TranslationContextData data = null) { var symbolTable = new SymbolTable(); var nameGenerator = new NameGenerator(); - return new TranslationContext(translationOptions, data, symbolTable, nameGenerator); + return new TranslationContext(translationOptions, data, symbolTable, nameGenerator, serializationDomain); } #endregion // private fields private readonly TranslationContextData _data; private readonly NameGenerator _nameGenerator; + private readonly IBsonSerializationDomain _serializationDomain; private readonly SymbolTable _symbolTable; private readonly ExpressionTranslationOptions _translationOptions; @@ -44,17 +46,21 @@ private TranslationContext( ExpressionTranslationOptions translationOptions, TranslationContextData data, SymbolTable symbolTable, - NameGenerator nameGenerator) + NameGenerator nameGenerator, + IBsonSerializationDomain serializationDomain) { _translationOptions = translationOptions ?? new ExpressionTranslationOptions(); _data = data; // can be null _symbolTable = Ensure.IsNotNull(symbolTable, nameof(symbolTable)); + _serializationDomain = serializationDomain; _nameGenerator = Ensure.IsNotNull(nameGenerator, nameof(nameGenerator)); } // public properties public TranslationContextData Data => _data; public NameGenerator NameGenerator => _nameGenerator; + public IBsonSerializationDomain SerializationDomain => _serializationDomain; + public SymbolTable SymbolTable => _symbolTable; public ExpressionTranslationOptions TranslationOptions => _translationOptions; @@ -124,7 +130,7 @@ public TranslationContext WithSymbols(params Symbol[] newSymbols) public TranslationContext WithSymbolTable(SymbolTable symbolTable) { - return new TranslationContext(_translationOptions, _data, symbolTable, _nameGenerator); + return new TranslationContext(_translationOptions, _data, symbolTable, _nameGenerator, _serializationDomain); } } } diff --git a/src/MongoDB.Driver/Linq/LinqProviderAdapter.cs b/src/MongoDB.Driver/Linq/LinqProviderAdapter.cs index 67ca25b4261..19550d75afc 100644 --- a/src/MongoDB.Driver/Linq/LinqProviderAdapter.cs +++ b/src/MongoDB.Driver/Linq/LinqProviderAdapter.cs @@ -56,12 +56,12 @@ internal static IQueryable AsQueryable( internal static BsonValue TranslateExpressionToAggregateExpression( Expression> expression, IBsonSerializer sourceSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions, TranslationContextData contextData = null) { expression = (Expression>)PartialEvaluator.EvaluatePartially(expression); - var context = TranslationContext.Create(translationOptions, contextData); + var context = TranslationContext.Create(translationOptions, serializationDomain, contextData); var translation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, expression, sourceSerializer, asRoot: true); var simplifiedAst = AstSimplifier.Simplify(translation.Ast); @@ -71,12 +71,12 @@ internal static BsonValue TranslateExpressionToAggregateExpression( LambdaExpression expression, IBsonSerializer documentSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) { expression = (LambdaExpression)PartialEvaluator.EvaluatePartially(expression); var parameter = expression.Parameters.Single(); - var context = TranslationContext.Create(translationOptions); + var context = TranslationContext.Create(translationOptions, serializationDomain); var symbol = context.CreateSymbol(parameter, documentSerializer, isCurrent: true); context = context.WithSymbol(symbol); var body = RemovePossibleConvertToObject(expression.Body); @@ -100,20 +100,20 @@ static Expression RemovePossibleConvertToObject(Expression expression) internal static RenderedFieldDefinition TranslateExpressionToField( Expression> expression, IBsonSerializer documentSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions, bool allowScalarValueForArrayField) { expression = (Expression>)PartialEvaluator.EvaluatePartially(expression); var parameter = expression.Parameters.Single(); - var context = TranslationContext.Create(translationOptions); + var context = TranslationContext.Create(translationOptions, serializationDomain); var symbol = context.CreateSymbol(parameter, documentSerializer, isCurrent: true); context = context.WithSymbol(symbol); var fieldTranslation = ExpressionToFilterFieldTranslator.Translate(context, expression.Body); var underlyingSerializer = fieldTranslation.Serializer; var fieldSerializer = underlyingSerializer as IBsonSerializer; - var valueSerializer = (IBsonSerializer)FieldValueSerializerHelper.GetSerializerForValueType(underlyingSerializer, serializerRegistry, typeof(TField), allowScalarValueForArrayField); + var valueSerializer = (IBsonSerializer)FieldValueSerializerHelper.GetSerializerForValueType(underlyingSerializer, serializationDomain.SerializerRegistry, typeof(TField), allowScalarValueForArrayField); return new RenderedFieldDefinition(fieldTranslation.Ast.Path, fieldSerializer, valueSerializer, underlyingSerializer); } @@ -121,11 +121,11 @@ internal static RenderedFieldDefinition TranslateExpressionToField( Expression> expression, IBsonSerializer elementSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) { expression = (Expression>)PartialEvaluator.EvaluatePartially(expression); - var context = TranslationContext.Create(translationOptions); + var context = TranslationContext.Create(translationOptions, serializationDomain); var parameter = expression.Parameters.Single(); var symbol = context.CreateSymbol(parameter, "@", elementSerializer); // @ represents the implied element context = context.WithSingleSymbol(symbol); // @ is the only symbol visible inside an $elemMatch @@ -138,11 +138,11 @@ internal static BsonDocument TranslateExpressionToElemMatchFilter( internal static BsonDocument TranslateExpressionToFilter( Expression> expression, IBsonSerializer documentSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) { expression = (Expression>)PartialEvaluator.EvaluatePartially(expression); - var context = TranslationContext.Create(translationOptions); + var context = TranslationContext.Create(translationOptions, serializationDomain); var filter = ExpressionToFilterTranslator.TranslateLambda(context, expression, documentSerializer, asRoot: true); filter = AstSimplifier.SimplifyAndConvert(filter); @@ -152,22 +152,23 @@ internal static BsonDocument TranslateExpressionToFilter( internal static RenderedProjectionDefinition TranslateExpressionToFindProjection( Expression> expression, IBsonSerializer sourceSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) - => TranslateExpressionToProjection(expression, sourceSerializer, translationOptions, forFind: true); + => TranslateExpressionToProjection(expression, sourceSerializer, translationOptions, forFind: true, serializationDomain); internal static RenderedProjectionDefinition TranslateExpressionToProjection( Expression> expression, IBsonSerializer inputSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) - => TranslateExpressionToProjection(expression, inputSerializer, translationOptions, forFind: false); + => TranslateExpressionToProjection(expression, inputSerializer, translationOptions, forFind: false, serializationDomain); private static RenderedProjectionDefinition TranslateExpressionToProjection( Expression> expression, IBsonSerializer inputSerializer, ExpressionTranslationOptions translationOptions, - bool forFind) + bool forFind, + IBsonSerializationDomain serializationDomain) { if (expression.Parameters.Count == 1 && expression.Body == expression.Parameters[0]) { @@ -176,7 +177,7 @@ private static RenderedProjectionDefinition TranslateExpressionToProjec } expression = (Expression>)PartialEvaluator.EvaluatePartially(expression); - var context = TranslationContext.Create(translationOptions); + var context = TranslationContext.Create(translationOptions, serializationDomain); var simplifier = forFind ? new AstFindProjectionSimplifier() : new AstSimplifier(); try @@ -212,10 +213,10 @@ private static RenderedProjectionDefinition TranslateExpressionToProjec internal static BsonDocument TranslateExpressionToSetStage( Expression> expression, IBsonSerializer documentSerializer, - IBsonSerializerRegistry serializerRegistry, + IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions) { - var context = TranslationContext.Create(translationOptions); // do not partially evaluate expression + var context = TranslationContext.Create(translationOptions, serializationDomain); // do not partially evaluate expression var parameter = expression.Parameters.Single(); var symbol = context.CreateRootSymbol(parameter, documentSerializer); context = context.WithSymbol(symbol); diff --git a/src/MongoDB.Driver/MongoClient.cs b/src/MongoDB.Driver/MongoClient.cs index 4b70bfdfd16..c8465eedafa 100644 --- a/src/MongoDB.Driver/MongoClient.cs +++ b/src/MongoDB.Driver/MongoClient.cs @@ -499,7 +499,7 @@ private ClientBulkWriteOperation CreateClientBulkWriteOperation(IReadOnlyList CreateDatabaseNamesCursor(IAsyncCursor databases.Select(database => database["name"].AsString)); private DropDatabaseOperation CreateDropDatabaseOperation(string name) - => new(new DatabaseNamespace(name), GetMessageEncoderSettings()) + => new(new DatabaseNamespace(name), GetMessageEncoderSettings(), _settings.SerializationDomain) { WriteConcern = _settings.WriteConcern }; @@ -528,11 +528,11 @@ private ListDatabasesOperation CreateListDatabasesOperation(ListDatabasesOptions var messageEncoderSettings = GetMessageEncoderSettings(); var translationOptions = _settings.TranslationOptions; - return new ListDatabasesOperation(messageEncoderSettings) + return new ListDatabasesOperation(messageEncoderSettings, _settings.SerializationDomain) { AuthorizedDatabases = options.AuthorizedDatabases, Comment = options.Comment, - Filter = options.Filter?.Render(new(BsonDocumentSerializer.Instance, BsonSerializer.SerializerRegistry, translationOptions: translationOptions)), + Filter = options.Filter?.Render(new(BsonDocumentSerializer.Instance, (_settings as IInheritableMongoClientSettings).SerializationDomain, translationOptions: translationOptions)), NameOnly = options.NameOnly, RetryRequested = _settings.RetryReads }; @@ -561,7 +561,8 @@ private ChangeStreamOperation CreateChangeStreamOperation( _settings.ReadConcern, GetMessageEncoderSettings(), _settings.RetryReads, - _settings.TranslationOptions); + _settings.TranslationOptions, + _settings.SerializationDomain); private OperationContext CreateOperationContext(IClientSessionHandle session, TimeSpan? timeout, CancellationToken cancellationToken) { @@ -616,8 +617,7 @@ private MessageEncoderSettings GetMessageEncoderSettings() private RenderArgs GetRenderArgs() { var translationOptions = Settings.TranslationOptions; - var serializerRegistry = BsonSerializer.SerializerRegistry; - return new RenderArgs(BsonDocumentSerializer.Instance, serializerRegistry, translationOptions: translationOptions); + return new RenderArgs(BsonDocumentSerializer.Instance, (_settings as IInheritableMongoClientSettings).SerializationDomain, translationOptions: translationOptions); } private IClientSessionHandle StartSession(ClientSessionOptions options) diff --git a/src/MongoDB.Driver/MongoClientSettings.cs b/src/MongoDB.Driver/MongoClientSettings.cs index bd2ce52064e..de5429f7958 100644 --- a/src/MongoDB.Driver/MongoClientSettings.cs +++ b/src/MongoDB.Driver/MongoClientSettings.cs @@ -18,6 +18,7 @@ using System.Collections.ObjectModel; using System.Linq; using System.Text; +using MongoDB.Bson.Serialization; using MongoDB.Driver.Core.Compression; using MongoDB.Driver.Core.Configuration; using MongoDB.Driver.Core.Misc; @@ -65,6 +66,7 @@ public class MongoClientSettings : IEquatable, IInheritable private bool _retryReads; private bool _retryWrites; private ConnectionStringScheme _scheme; + private IBsonSerializationDomain _serializationDomain; private ServerApi _serverApi; private List _servers; private ServerMonitoringMode _serverMonitoringMode; @@ -117,6 +119,7 @@ public MongoClientSettings() _retryReads = true; _retryWrites = true; _scheme = ConnectionStringScheme.MongoDB; + _serializationDomain = BsonSerializer.DefaultSerializationDomain; _serverApi = null; _servers = new List { new MongoServerAddress("localhost") }; _serverMonitoringMode = ServerMonitoringMode.Auto; @@ -472,6 +475,21 @@ public ReadPreference ReadPreference } } + IBsonSerializationDomain IInheritableMongoClientSettings.SerializationDomain + { + //QUESTION Is this reasonable? + get => _serializationDomain ?? BsonSerializer.DefaultSerializationDomain; + set + { + if (_isFrozen) { throw new InvalidOperationException("MongoClientSettings is frozen."); } + _serializationDomain = value ?? throw new ArgumentNullException(nameof(value)); + } + } + + //FP This is a convenience property, it could be removed. + internal IBsonSerializationDomain SerializationDomain + => (this as IInheritableMongoClientSettings).SerializationDomain; + /// /// Gets or sets the name of the replica set. /// @@ -944,6 +962,7 @@ public MongoClientSettings Clone() clone._retryReads = _retryReads; clone._retryWrites = _retryWrites; clone._scheme = _scheme; + clone._serializationDomain = _serializationDomain; clone._serverApi = _serverApi; clone._servers = new List(_servers); clone._serverMonitoringMode = _serverMonitoringMode; diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index 20b11c8c942..700c8911297 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -677,7 +677,7 @@ private WriteRequest ConvertWriteModelToWriteRequest(WriteModel model var insertOneModel = (InsertOneModel)model; if (_settings.AssignIdOnInsert) { - _documentSerializer.SetDocumentIdIfMissing(this, insertOneModel.Document); + _documentSerializer.SetDocumentIdIfMissing(this, insertOneModel.Document, renderArgs.SerializationDomain); } return new InsertRequest(new BsonDocumentWrapper(insertOneModel.Document, _documentSerializer)) { @@ -755,7 +755,8 @@ private AggregateOperation CreateAggregateOperation(RenderedPi _collectionNamespace, renderedPipeline.Documents, renderedPipeline.OutputSerializer, - _messageEncoderSettings) + _messageEncoderSettings, + Settings.SerializationDomain) { AllowDiskUse = options.AllowDiskUse, BatchSize = options.BatchSize, @@ -777,7 +778,7 @@ private IAsyncCursor CreateAggregateToCollectionResultCursor(I { var outputCollectionNamespace = AggregateHelper.GetOutCollection(pipeline.Documents.Last(), _collectionNamespace.DatabaseNamespace); - var findOperation = new FindOperation(outputCollectionNamespace, pipeline.OutputSerializer, _messageEncoderSettings) + var findOperation = new FindOperation(outputCollectionNamespace, pipeline.OutputSerializer, _messageEncoderSettings, Settings.SerializationDomain) { BatchSize = options.BatchSize, Collation = options.Collation, @@ -801,7 +802,8 @@ private AggregateToCollectionOperation CreateAggregateToCollectionOperation CreateChangeStreamOperation( options, _settings.ReadConcern, messageEncoderSettings: _messageEncoderSettings, _database.Client.Settings.RetryReads, - translationOptions); + translationOptions, + _settings.SerializationDomain); } private CountDocumentsOperation CreateCountDocumentsOperation( @@ -868,7 +871,7 @@ private CountDocumentsOperation CreateCountDocumentsOperation( options ??= new CountOptions(); var renderArgs = GetRenderArgs(); - return new CountDocumentsOperation(_collectionNamespace, _messageEncoderSettings) + return new CountDocumentsOperation(_collectionNamespace, _messageEncoderSettings, Settings.SerializationDomain) { Collation = options.Collation, Comment = options.Comment, @@ -889,7 +892,7 @@ private CountOperation CreateCountOperation( options ??= new CountOptions(); var renderArgs = GetRenderArgs(); - return new CountOperation(_collectionNamespace, _messageEncoderSettings) + return new CountOperation(_collectionNamespace, _messageEncoderSettings, _settings.SerializationDomain) { Collation = options.Collation, Comment = options.Comment, @@ -917,7 +920,8 @@ private DistinctOperation CreateDistinctOperation( _collectionNamespace, valueSerializer, renderedField.FieldName, - _messageEncoderSettings) + _messageEncoderSettings, + _settings.SerializationDomain) { Collation = options.Collation, Comment = options.Comment, @@ -942,7 +946,8 @@ private DistinctOperation CreateDistinctManyOperation( _collectionNamespace, itemSerializer, renderedField.FieldName, - _messageEncoderSettings) + _messageEncoderSettings, + _settings.SerializationDomain) { Collation = options.Collation, Comment = options.Comment, @@ -955,7 +960,7 @@ private DistinctOperation CreateDistinctManyOperation( private EstimatedDocumentCountOperation CreateEstimatedDocumentCountOperation(EstimatedDocumentCountOptions options) { - return new EstimatedDocumentCountOperation(_collectionNamespace, _messageEncoderSettings) + return new EstimatedDocumentCountOperation(_collectionNamespace, _messageEncoderSettings, _settings.SerializationDomain) { Comment = options?.Comment, MaxTime = options?.MaxTime, @@ -976,7 +981,8 @@ private FindOneAndDeleteOperation CreateFindOneAndDeleteOperation(renderedProjection.ProjectionSerializer), - _messageEncoderSettings) + _messageEncoderSettings, + _settings.SerializationDomain) { Collation = options.Collation, Comment = options.Comment, @@ -1006,7 +1012,8 @@ private FindOneAndReplaceOperation CreateFindOneAndReplaceOperation filter.Render(renderArgs), new BsonDocumentWrapper(replacement, _documentSerializer), new FindAndModifyValueDeserializer(renderedProjection.ProjectionSerializer), - _messageEncoderSettings) + _messageEncoderSettings, + _settings.SerializationDomain) { BypassDocumentValidation = options.BypassDocumentValidation, Collation = options.Collation, @@ -1037,7 +1044,8 @@ private FindOneAndUpdateOperation CreateFindOneAndUpdateOperation(renderedProjection.ProjectionSerializer), - _messageEncoderSettings) + _messageEncoderSettings, + _settings.SerializationDomain) { ArrayFilters = RenderArrayFilters(options.ArrayFilters), BypassDocumentValidation = options.BypassDocumentValidation, @@ -1068,7 +1076,8 @@ private FindOperation CreateFindOperation( return new FindOperation( _collectionNamespace, renderedProjection.ProjectionSerializer, - _messageEncoderSettings) + _messageEncoderSettings, + Settings.SerializationDomain) { AllowDiskUse = options.AllowDiskUse, AllowPartialResults = options.AllowPartialResults, @@ -1112,7 +1121,8 @@ private MapReduceOperation CreateMapReduceOperation( map, reduce, resultSerializer, - _messageEncoderSettings) + _messageEncoderSettings, + Settings.SerializationDomain) { Collation = options.Collation, Filter = options.Filter?.Render(renderArgs), @@ -1149,7 +1159,8 @@ private MapReduceOutputToCollectionOperation CreateMapReduceOutputToCollectionOp outputCollectionNamespace, map, reduce, - _messageEncoderSettings) + _messageEncoderSettings, + _settings.SerializationDomain) { BypassDocumentValidation = options.BypassDocumentValidation, Collation = options.Collation, @@ -1181,7 +1192,8 @@ private IAsyncCursor CreateMapReduceOutputToCollectionResultCursor( outputCollectionNamespace, resultSerializer, - _messageEncoderSettings) + _messageEncoderSettings, + Settings.SerializationDomain) { Collation = options.Collation, MaxTime = options.MaxTime, @@ -1247,7 +1259,8 @@ private MessageEncoderSettings GetMessageEncoderSettings() var messageEncoderSettings = new MessageEncoderSettings { { MessageEncoderSettingsName.ReadEncoding, _settings.ReadEncoding ?? Utf8Encodings.Strict }, - { MessageEncoderSettingsName.WriteEncoding, _settings.WriteEncoding ?? Utf8Encodings.Strict } + { MessageEncoderSettingsName.WriteEncoding, _settings.WriteEncoding ?? Utf8Encodings.Strict }, + { MessageEncoderSettingsName.SerializationDomain, _settings.SerializationDomain } }; if (_database.Client is MongoClient mongoClient) @@ -1307,13 +1320,13 @@ private IBsonSerializer GetItemSerializerForDistinctMany(RenderedF private RenderArgs GetRenderArgs() { var translationOptions = _database.Client.Settings.TranslationOptions; - return new RenderArgs(_documentSerializer, _settings.SerializerRegistry, translationOptions: translationOptions); + return new RenderArgs(_documentSerializer, _settings.SerializationDomain, translationOptions: translationOptions); } private RenderArgs GetRenderArgs(ExpressionTranslationOptions translationOptions) { translationOptions = translationOptions.AddMissingOptionsFrom(_database.Client.Settings.TranslationOptions); - return new RenderArgs(_documentSerializer, _settings.SerializerRegistry, translationOptions: translationOptions); + return new RenderArgs(_documentSerializer, _settings.SerializationDomain, translationOptions: translationOptions); } private IEnumerable RenderArrayFilters(IEnumerable arrayFilters) @@ -1566,7 +1579,7 @@ private CreateIndexesOperation CreateCreateIndexesOperation(IEnumerable CreateCreateIndexRequests(IEnumerable CreateOneAsync(CreateSearchIndexModel model, Cancellat public void DropOne(string indexName, CancellationToken cancellationToken = default) { using var session = _collection._operationExecutor.StartImplicitSession(); - var operation = new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings); + var operation = new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings, _collection.Settings.SerializationDomain); // TODO: CSOT: find a way to add timeout parameter to the interface method _collection.ExecuteWriteOperation(session, operation, null, cancellationToken); } @@ -1702,7 +1715,7 @@ public void DropOne(string indexName, CancellationToken cancellationToken = defa public async Task DropOneAsync(string indexName, CancellationToken cancellationToken = default) { using var session = _collection._operationExecutor.StartImplicitSession(); - var operation = new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings); + var operation = new DropSearchIndexOperation(_collection.CollectionNamespace, indexName, _collection._messageEncoderSettings, _collection.Settings.SerializationDomain); // TODO: CSOT: find a way to add timeout parameter to the interface method await _collection.ExecuteWriteOperationAsync(session, operation, null, cancellationToken).ConfigureAwait(false); } @@ -1720,7 +1733,7 @@ public Task> ListAsync(string indexName, AggregateOpt public void Update(string indexName, BsonDocument definition, CancellationToken cancellationToken = default) { using var session = _collection._operationExecutor.StartImplicitSession(); - var operation = new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings); + var operation = new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings, _collection.Settings.SerializationDomain); // TODO: CSOT: find a way to add timeout parameter to the interface method _collection.ExecuteWriteOperation(session, operation, null, cancellationToken); } @@ -1728,7 +1741,7 @@ public void Update(string indexName, BsonDocument definition, CancellationToken public async Task UpdateAsync(string indexName, BsonDocument definition, CancellationToken cancellationToken = default) { using var session = _collection._operationExecutor.StartImplicitSession(); - var operation = new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings); + var operation = new UpdateSearchIndexOperation(_collection.CollectionNamespace, indexName, definition, _collection._messageEncoderSettings, _collection.Settings.SerializationDomain); // TODO: CSOT: find a way to add timeout parameter to the interface method await _collection.ExecuteWriteOperationAsync(session, operation, null, cancellationToken).ConfigureAwait(false); } @@ -1744,7 +1757,8 @@ private PipelineDefinition CreateListIndexesStage(strin private CreateSearchIndexesOperation CreateCreateIndexesOperation(IEnumerable models) => new(_collection._collectionNamespace, models.Select(m => new CreateSearchIndexRequest(m.Name, m.Type, m.Definition)), - _collection._messageEncoderSettings); + _collection._messageEncoderSettings, + _collection.Settings.SerializationDomain); private string[] GetIndexNames(BsonDocument createSearchIndexesResponse) => createSearchIndexesResponse["indexesCreated"] diff --git a/src/MongoDB.Driver/MongoCollectionSettings.cs b/src/MongoDB.Driver/MongoCollectionSettings.cs index 81691de6f09..1ed42c2ae9a 100644 --- a/src/MongoDB.Driver/MongoCollectionSettings.cs +++ b/src/MongoDB.Driver/MongoCollectionSettings.cs @@ -34,6 +34,7 @@ public class MongoCollectionSettings private TimeSpan? _timeout; private Setting _writeConcern; private Setting _writeEncoding; + private Setting _serializationDomain; // the following fields are set when Freeze is called private bool _isFrozen; @@ -116,9 +117,24 @@ public ReadPreference ReadPreference /// /// Gets the serializer registry. /// - public IBsonSerializerRegistry SerializerRegistry + public IBsonSerializerRegistry SerializerRegistry => SerializationDomain.SerializerRegistry; + + /// + /// //TODO + /// + internal IBsonSerializationDomain SerializationDomain { - get { return BsonSerializer.SerializerRegistry; } + //QUESTION Is this reasonable? In normal uses cases the domain would be setup by ApplyDefaultValues, but for testing it would not work. + get => _serializationDomain.Value ?? BsonSerializer.DefaultSerializationDomain; + set + { + if (_isFrozen) { throw new InvalidOperationException("MongoCollectionSettings is frozen."); } + if (value == null) + { + throw new ArgumentNullException("value"); + } + _serializationDomain.Value = value; + } } /// @@ -180,6 +196,7 @@ public virtual MongoCollectionSettings Clone() clone._timeout = _timeout; clone._writeConcern = _writeConcern.Clone(); clone._writeEncoding = _writeEncoding.Clone(); + clone._serializationDomain = _serializationDomain; //TODO .clone...? return clone; } @@ -319,6 +336,10 @@ internal void ApplyDefaultValues(MongoDatabaseSettings databaseSettings) { ReadPreference = databaseSettings.ReadPreference; } + if (!_serializationDomain.HasBeenSet) + { + SerializationDomain = databaseSettings.SerializationDomain; + } if (!_timeout.HasValue) { Timeout = databaseSettings.Timeout; diff --git a/src/MongoDB.Driver/MongoDB.Driver.csproj b/src/MongoDB.Driver/MongoDB.Driver.csproj index 34add76dfbe..734e55b8df9 100644 --- a/src/MongoDB.Driver/MongoDB.Driver.csproj +++ b/src/MongoDB.Driver/MongoDB.Driver.csproj @@ -13,11 +13,12 @@ true - - - - - + + + + + + diff --git a/src/MongoDB.Driver/MongoDatabase.cs b/src/MongoDB.Driver/MongoDatabase.cs index 31b872da989..39ad92d14f0 100644 --- a/src/MongoDB.Driver/MongoDatabase.cs +++ b/src/MongoDB.Driver/MongoDatabase.cs @@ -538,7 +538,8 @@ private AggregateOperation CreateAggregateOperation(RenderedPi _databaseNamespace, renderedPipeline.Documents, renderedPipeline.OutputSerializer, - messageEncoderSettings) + messageEncoderSettings, + Settings.SerializationDomain) { AllowDiskUse = options.AllowDiskUse, BatchSize = options.BatchSize, @@ -565,7 +566,7 @@ private IAsyncCursor CreateAggregateToCollectionResultCursor(I // However, since we've added encryption configuration for CreateAggregateToCollectionOperation operation, // it's not superfluous to also add it here var messageEncoderSettings = GetMessageEncoderSettings(); - var findOperation = new FindOperation(outputCollectionNamespace, pipeline.OutputSerializer, messageEncoderSettings) + var findOperation = new FindOperation(outputCollectionNamespace, pipeline.OutputSerializer, messageEncoderSettings, Settings.SerializationDomain) { BatchSize = options.BatchSize, Collation = options.Collation, @@ -590,7 +591,8 @@ private AggregateToCollectionOperation CreateAggregateToCollectionOperation CreateCreateCollectionOperation var serializerRegistry = options.SerializerRegistry ?? BsonSerializer.SerializerRegistry; var documentSerializer = options.DocumentSerializer ?? serializerRegistry.GetSerializer(); - var clusteredIndex = options.ClusteredIndex?.Render(documentSerializer, serializerRegistry, translationOptions); - var validator = options.Validator?.Render(new(documentSerializer, serializerRegistry, translationOptions: translationOptions)); + //DOMAIN-API This will need to go away + //This is only happening in a couple of places, it's not worth to find better solutions right now. + RenderArgs renderArgs = options.SerializationDomain is null ? + new(documentSerializer, serializerRegistry, translationOptions: translationOptions) : + new(documentSerializer, options.SerializationDomain, translationOptions: translationOptions); + + //DOMAIN-API This will need to go away + var clusteredIndex = options.SerializationDomain is null? + options.ClusteredIndex?.Render(documentSerializer, serializerRegistry, translationOptions): + options.ClusteredIndex?.Render(documentSerializer, options.SerializationDomain, translationOptions); + var validator = options.Validator?.Render(renderArgs); var collectionNamespace = new CollectionNamespace(_databaseNamespace, name); var effectiveEncryptedFields = EncryptedCollectionHelper.GetEffectiveEncryptedFields(collectionNamespace, options.EncryptedFields, _client.Settings?.AutoEncryptionOptions?.EncryptedFieldsMap); @@ -636,6 +647,7 @@ private IWriteOperation CreateCreateCollectionOperation collectionNamespace, effectiveEncryptedFields, messageEncoderSettings, + _settings.SerializationDomain, createCollectionOperationConfigurator: cco => { cco.Capped = options.Capped; @@ -666,8 +678,14 @@ private CreateViewOperation CreateCreateViewOperation( var translationOptions = _client.Settings.TranslationOptions; var serializerRegistry = options.SerializerRegistry ?? BsonSerializer.SerializerRegistry; var documentSerializer = options.DocumentSerializer ?? serializerRegistry.GetSerializer(); - var pipelineDocuments = pipeline.Render(new (documentSerializer, serializerRegistry, translationOptions: translationOptions)).Documents; - return new CreateViewOperation(_databaseNamespace, viewName, viewOn, pipelineDocuments, GetMessageEncoderSettings()) + + //DOMAIN-API This will need to go away + RenderArgs renderArgs = options.SerializationDomain is null ? + new(documentSerializer, serializerRegistry, translationOptions: translationOptions) : + new(documentSerializer, options.SerializationDomain, translationOptions: translationOptions); + + var pipelineDocuments = pipeline.Render(renderArgs).Documents; + return new CreateViewOperation(_databaseNamespace, viewName, viewOn, pipelineDocuments, GetMessageEncoderSettings(), _settings.SerializationDomain) { Collation = options.Collation, WriteConcern = _settings.WriteConcern @@ -681,6 +699,7 @@ private IWriteOperation CreateDropCollectionOperation(CollectionNa collectionNamespace, effectiveEncryptedFields, messageEncoderSettings, + _settings.SerializationDomain, (dco) => { dco.WriteConcern = _settings.WriteConcern; @@ -691,7 +710,7 @@ private ListCollectionsOperation CreateListCollectionNamesOperation(ListCollecti { var messageEncoderSettings = GetMessageEncoderSettings(); var renderArgs = GetRenderArgs(BsonDocumentSerializer.Instance); - return new ListCollectionsOperation(_databaseNamespace, messageEncoderSettings) + return new ListCollectionsOperation(_databaseNamespace, messageEncoderSettings, Settings.SerializationDomain) { AuthorizedCollections = options?.AuthorizedCollections, Comment = options?.Comment, @@ -705,7 +724,7 @@ private ListCollectionsOperation CreateListCollectionsOperation(ListCollectionsO { var renderArgs = GetRenderArgs(BsonDocumentSerializer.Instance); var messageEncoderSettings = GetMessageEncoderSettings(); - return new ListCollectionsOperation(_databaseNamespace, messageEncoderSettings) + return new ListCollectionsOperation(_databaseNamespace, messageEncoderSettings, Settings.SerializationDomain) { BatchSize = options?.BatchSize, Comment = options?.Comment, @@ -722,7 +741,8 @@ private RenameCollectionOperation CreateRenameCollectionOperation(string oldName return new RenameCollectionOperation( new CollectionNamespace(_databaseNamespace, oldName), new CollectionNamespace(_databaseNamespace, newName), - messageEncoderSettings) + messageEncoderSettings, + _settings.SerializationDomain) { DropTarget = options.DropTarget, WriteConcern = _settings.WriteConcern @@ -733,7 +753,7 @@ private ReadCommandOperation CreateRunCommandOperation(Command { var renderedCommand = command.Render(_settings.SerializerRegistry); var messageEncoderSettings = GetMessageEncoderSettings(); - return new ReadCommandOperation(_databaseNamespace, renderedCommand.Document, renderedCommand.ResultSerializer, messageEncoderSettings) + return new ReadCommandOperation(_databaseNamespace, renderedCommand.Document, renderedCommand.ResultSerializer, messageEncoderSettings, Settings.SerializationDomain) { RetryRequested = false }; @@ -752,7 +772,8 @@ private ChangeStreamOperation CreateChangeStreamOperation( _settings.ReadConcern, GetMessageEncoderSettings(), _client.Settings.RetryReads, - translationOptions); + translationOptions, + _client.Settings.SerializationDomain); } private OperationContext CreateOperationContext(IClientSessionHandle session, TimeSpan? timeout, CancellationToken cancellationToken) @@ -849,7 +870,8 @@ private MessageEncoderSettings GetMessageEncoderSettings() var messageEncoderSettings = new MessageEncoderSettings { { MessageEncoderSettingsName.ReadEncoding, _settings.ReadEncoding ?? Utf8Encodings.Strict }, - { MessageEncoderSettingsName.WriteEncoding, _settings.WriteEncoding ?? Utf8Encodings.Strict } + { MessageEncoderSettingsName.WriteEncoding, _settings.WriteEncoding ?? Utf8Encodings.Strict }, + { MessageEncoderSettingsName.SerializationDomain, _settings.SerializationDomain } }; if (_client is MongoClient mongoClient) @@ -863,13 +885,13 @@ private MessageEncoderSettings GetMessageEncoderSettings() private RenderArgs GetRenderArgs(IBsonSerializer documentSerializer) { var translationOptions = _client.Settings.TranslationOptions; - return new RenderArgs(documentSerializer, _settings.SerializerRegistry, translationOptions: translationOptions); + return new RenderArgs(documentSerializer, _settings.SerializationDomain, translationOptions: translationOptions); } private RenderArgs GetRenderArgs(IBsonSerializer documentSerializer, ExpressionTranslationOptions translationOptions) { translationOptions = translationOptions.AddMissingOptionsFrom(_client.Settings.TranslationOptions); - return new RenderArgs(documentSerializer, _settings.SerializerRegistry, translationOptions: translationOptions); + return new RenderArgs(documentSerializer, _settings.SerializationDomain, translationOptions: translationOptions); } } } diff --git a/src/MongoDB.Driver/MongoDatabaseSettings.cs b/src/MongoDB.Driver/MongoDatabaseSettings.cs index e88fe90ed6c..779b2ead274 100644 --- a/src/MongoDB.Driver/MongoDatabaseSettings.cs +++ b/src/MongoDB.Driver/MongoDatabaseSettings.cs @@ -33,6 +33,7 @@ public class MongoDatabaseSettings private TimeSpan? _timeout; private Setting _writeConcern; private Setting _writeEncoding; + private Setting _serializationDomain; // the following fields are set when Freeze is called private bool _isFrozen; @@ -101,9 +102,23 @@ public ReadPreference ReadPreference /// /// Gets the serializer registry. /// - public IBsonSerializerRegistry SerializerRegistry + public IBsonSerializerRegistry SerializerRegistry => SerializationDomain.SerializerRegistry; + + /// + /// //TODO + /// + internal IBsonSerializationDomain SerializationDomain { - get { return BsonSerializer.SerializerRegistry; } + get => _serializationDomain.Value ?? BsonSerializer.DefaultSerializationDomain; //QUESTION Is this reasonable? + set + { + if (_isFrozen) { throw new InvalidOperationException("MongoCollectionSettings is frozen."); } + if (value == null) + { + throw new ArgumentNullException("value"); + } + _serializationDomain.Value = value; + } } /// @@ -164,6 +179,7 @@ public MongoDatabaseSettings Clone() clone._timeout = _timeout; clone._writeConcern = _writeConcern.Clone(); clone._writeEncoding = _writeEncoding.Clone(); + clone._serializationDomain = _serializationDomain; return clone; } @@ -300,6 +316,10 @@ internal void ApplyDefaultValues(IInheritableMongoClientSettings clientSettings) { Timeout = clientSettings.Timeout; } + if (!_serializationDomain.HasBeenSet) + { + SerializationDomain = clientSettings.SerializationDomain; + } if (!_writeConcern.HasBeenSet) { WriteConcern = clientSettings.WriteConcern; diff --git a/src/MongoDB.Driver/OfTypeMongoCollection.cs b/src/MongoDB.Driver/OfTypeMongoCollection.cs index a1b1dd69220..43a7d27cad2 100644 --- a/src/MongoDB.Driver/OfTypeMongoCollection.cs +++ b/src/MongoDB.Driver/OfTypeMongoCollection.cs @@ -61,9 +61,9 @@ protected override UpdateDefinition AdjustUpdateDefinition(Upd if (isUpsert) { - var discriminatorConvention = _rootDocumentCollection.DocumentSerializer.GetDiscriminatorConvention(); + var discriminatorConvention = _rootDocumentCollection.DocumentSerializer.GetDiscriminatorConvention(Settings.SerializationDomain); var discriminatorConventionElementName = discriminatorConvention.ElementName; - var discriminator = discriminatorConvention.GetDiscriminator(typeof(TRootDocument), typeof(TDerivedDocument)); + var discriminator = discriminatorConvention.GetDiscriminatorInternal(typeof(TRootDocument), typeof(TDerivedDocument), Settings.SerializationDomain); if (result is PipelineUpdateDefinition pipeline) { diff --git a/src/MongoDB.Driver/OfTypeSerializer.cs b/src/MongoDB.Driver/OfTypeSerializer.cs index 1ff1b95e4c2..84b07c4813a 100644 --- a/src/MongoDB.Driver/OfTypeSerializer.cs +++ b/src/MongoDB.Driver/OfTypeSerializer.cs @@ -14,12 +14,13 @@ */ using System; +using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; namespace MongoDB.Driver { - internal sealed class OfTypeSerializer : SerializerBase, IBsonDocumentSerializer, IBsonIdProvider + internal sealed class OfTypeSerializer : SerializerBase, IBsonDocumentSerializer, IBsonIdProviderInternal where TDerivedDocument : TRootDocument { private readonly IBsonSerializer _derivedDocumentSerializer; @@ -46,10 +47,14 @@ obj is OfTypeSerializer other && } public bool GetDocumentId(object document, out object id, out Type idNominalType, out IIdGenerator idGenerator) + => GetDocumentId(document, BsonSerializer.DefaultSerializationDomain, out id, out idNominalType, out idGenerator); + + public bool GetDocumentId(object document, IBsonSerializationDomain serializationDomain, out object id, out Type idNominalType, + out IIdGenerator idGenerator) { if (_derivedDocumentSerializer is IBsonIdProvider idProvider) { - return idProvider.GetDocumentId(document, out id, out idNominalType, out idGenerator); + return idProvider.GetDocumentIdInternal(document, serializationDomain, out id, out idNominalType, out idGenerator); } else { diff --git a/src/MongoDB.Driver/PipelineDefinition.cs b/src/MongoDB.Driver/PipelineDefinition.cs index fbd9d69d5c0..5b346c395eb 100644 --- a/src/MongoDB.Driver/PipelineDefinition.cs +++ b/src/MongoDB.Driver/PipelineDefinition.cs @@ -21,6 +21,7 @@ using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Misc; using MongoDB.Driver.Linq; +using MongoDB.Driver.Support; namespace MongoDB.Driver { @@ -329,7 +330,7 @@ public override RenderedPipelineDefinition Render(RenderArgs ar IBsonSerializer currentSerializer = args.DocumentSerializer; foreach (var stage in _stages) { - var renderedStage = stage.Render(currentSerializer, args.SerializerRegistry, args.TranslationOptions); + var renderedStage = stage.RenderInternal(currentSerializer, args.SerializationDomain, args.SerializerRegistry, args.TranslationOptions); currentSerializer = renderedStage.OutputSerializer; foreach (var document in renderedStage.Documents) { diff --git a/src/MongoDB.Driver/PipelineDefinitionBuilder.cs b/src/MongoDB.Driver/PipelineDefinitionBuilder.cs index 3ad6eca971a..1b3de33a4ae 100644 --- a/src/MongoDB.Driver/PipelineDefinitionBuilder.cs +++ b/src/MongoDB.Driver/PipelineDefinitionBuilder.cs @@ -1644,7 +1644,7 @@ public AppendedStagePipelineDefinition( public override RenderedPipelineDefinition Render(RenderArgs args) { var renderedPipeline = _pipeline.Render(args); - var renderedStage = _stage.Render(new(renderedPipeline.OutputSerializer, args.SerializerRegistry, translationOptions: args.TranslationOptions)); + var renderedStage = _stage.Render(new(renderedPipeline.OutputSerializer, args.SerializationDomain, translationOptions: args.TranslationOptions)); var documents = renderedPipeline.Documents.Concat(renderedStage.Documents); var outputSerializer = _outputSerializer ?? renderedStage.OutputSerializer; return new RenderedPipelineDefinition(documents, outputSerializer); @@ -1720,7 +1720,7 @@ public PrependedStagePipelineDefinition( public override RenderedPipelineDefinition Render(RenderArgs args) { var renderedStage = _stage.Render(args); - var renderedPipeline = _pipeline.Render(new(renderedStage.OutputSerializer, args.SerializerRegistry, translationOptions: args.TranslationOptions)); + var renderedPipeline = _pipeline.Render(new(renderedStage.OutputSerializer, args.SerializationDomain, translationOptions: args.TranslationOptions)); var documents = renderedStage.Documents.Concat(renderedPipeline.Documents); var outputSerializer = _outputSerializer ?? renderedPipeline.OutputSerializer; return new RenderedPipelineDefinition(documents, outputSerializer); diff --git a/src/MongoDB.Driver/PipelineStageDefinition.cs b/src/MongoDB.Driver/PipelineStageDefinition.cs index 27f1dcaae52..900769862b6 100644 --- a/src/MongoDB.Driver/PipelineStageDefinition.cs +++ b/src/MongoDB.Driver/PipelineStageDefinition.cs @@ -16,7 +16,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Transactions; using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Driver.Core.Misc; @@ -139,6 +138,7 @@ public interface IPipelineStageDefinition /// Type OutputType { get; } + //DOMAIN-API We need to swap the serializer registry for the serialization domain. /// /// Renders the specified document serializer. /// @@ -167,12 +167,17 @@ public interface IPipelineStageDefinition string ToString(IBsonSerializer inputSerializer, IBsonSerializerRegistry serializerRegistry); } + internal interface IPipelineStageStageDefinitionInternal : IPipelineStageDefinition + { + IRenderedPipelineStageDefinition Render(IBsonSerializer inputSerializer, IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions); + } + /// /// Base class for pipeline stages. /// /// The type of the input. /// The type of the output. - public abstract class PipelineStageDefinition : IPipelineStageDefinition + public abstract class PipelineStageDefinition : IPipelineStageStageDefinitionInternal { /// /// Gets the type of the input. @@ -292,6 +297,12 @@ IRenderedPipelineStageDefinition IPipelineStageDefinition.Render(IBsonSerializer { return Render(new((IBsonSerializer)inputSerializer, serializerRegistry, translationOptions: translationOptions)); } + + IRenderedPipelineStageDefinition IPipelineStageStageDefinitionInternal.Render(IBsonSerializer inputSerializer, IBsonSerializationDomain serializationDomain, + ExpressionTranslationOptions translationOptions) + { + return Render(new((IBsonSerializer)inputSerializer, serializationDomain, translationOptions: translationOptions)); + } } /// diff --git a/src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs b/src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs index b8c7ee834fb..8cc047a228e 100644 --- a/src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs +++ b/src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs @@ -544,6 +544,7 @@ public static PipelineStageDefinition Facet( const string operatorName = "$facet"; var materializedFacets = facets.ToArray(); + var stage = new DelegatedPipelineStageDefinition( operatorName, args => @@ -556,7 +557,25 @@ public static PipelineStageDefinition Facet( facetsDocument.Add(facet.Name, renderedPipeline); } var document = new BsonDocument("$facet", facetsDocument); - var outputSerializer = options?.OutputSerializer ?? args.SerializerRegistry.GetSerializer(); + + IBsonSerializer outputSerializer; + + if (options?.OutputSerializer is not null) + { + outputSerializer = options.OutputSerializer; + } + else if (typeof(TOutput) == typeof(AggregateFacetResults)) + { + outputSerializer = (IBsonSerializer)new AggregateFacetResultsSerializer( + materializedFacets.Select(f => f.Name), + materializedFacets.Select(f => f.OutputSerializer ?? args.SerializerRegistry.GetSerializer(f.OutputType))); //QUESTION What do we do? Do we delay the setting of the serializer..? + } + else + { + outputSerializer = args.SerializerRegistry.GetSerializer(); + } + + //var outputSerializer = options?.OutputSerializer ?? args.SerializerRegistry.GetSerializer(); return new RenderedPipelineStageDefinition(operatorName, document, outputSerializer); }); @@ -572,12 +591,7 @@ public static PipelineStageDefinition Facet( public static PipelineStageDefinition Facet( IEnumerable> facets) { - Ensure.IsNotNull(facets, nameof(facets)); - var outputSerializer = new AggregateFacetResultsSerializer( - facets.Select(f => f.Name), - facets.Select(f => f.OutputSerializer ?? BsonSerializer.SerializerRegistry.GetSerializer(f.OutputType))); - var options = new AggregateFacetOptions { OutputSerializer = outputSerializer }; - return Facet(facets, options); + return Facet(facets, options: null); } /// @@ -1280,7 +1294,7 @@ public static PipelineStageDefinition OfType( else { var inputSerializer = args.DocumentSerializer; - var discriminatorConvention = inputSerializer.GetDiscriminatorConvention(); + var discriminatorConvention = inputSerializer.GetDiscriminatorConvention(args.SerializationDomain); if (discriminatorConvention == null) { var message = string.Format("OfType requires that a discriminator convention exist for type: {0}.", BsonUtils.GetFriendlyTypeName(typeof(TOutput))); @@ -1290,8 +1304,8 @@ public static PipelineStageDefinition OfType( var discriminatorField = new AstFilterField(discriminatorConvention.ElementName); ofTypeFilter = discriminatorConvention switch { - IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType), - IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType), + IHierarchicalDiscriminatorConvention hierarchicalDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, hierarchicalDiscriminatorConvention, nominalType, actualType, args.SerializationDomain), + IScalarDiscriminatorConvention scalarDiscriminatorConvention => DiscriminatorAstFilter.TypeIs(discriminatorField, scalarDiscriminatorConvention, nominalType, actualType, args.SerializationDomain), _ => throw new NotSupportedException( "OfType is not supported with the configured discriminator convention.") }; } @@ -2224,8 +2238,8 @@ public Expression> Expression } public override RenderedProjectionDefinition Render(RenderArgs args) => args.RenderForFind ? - LinqProviderAdapter.TranslateExpressionToFindProjection(_expression, args.DocumentSerializer, args.SerializerRegistry, args.TranslationOptions) : - LinqProviderAdapter.TranslateExpressionToProjection(_expression, args.DocumentSerializer, args.SerializerRegistry, args.TranslationOptions); + LinqProviderAdapter.TranslateExpressionToFindProjection(_expression, args.DocumentSerializer, args.SerializationDomain, args.TranslationOptions) : + LinqProviderAdapter.TranslateExpressionToProjection(_expression, args.DocumentSerializer, args.SerializationDomain, args.TranslationOptions); } internal class SortPipelineStageDefinition : PipelineStageDefinition diff --git a/src/MongoDB.Driver/ProjectionDefinition.cs b/src/MongoDB.Driver/ProjectionDefinition.cs index 6ae7985cf5b..99c58af8107 100644 --- a/src/MongoDB.Driver/ProjectionDefinition.cs +++ b/src/MongoDB.Driver/ProjectionDefinition.cs @@ -277,11 +277,11 @@ public override RenderedProjectionDefinition Render(RenderArgs private readonly bool _renderForFind = false; private readonly IBsonSerializerRegistry _serializerRegistry = default; private readonly ExpressionTranslationOptions _translationOptions = default; + private readonly IBsonSerializationDomain _serializationDomain = default; + //DOMAIN-API We need to stop using this constructor, and use the one with the serialization domain instead. /// /// Initializes a new instance of the record. /// @@ -65,6 +67,36 @@ public RenderArgs( _renderForFind = renderForFind; _renderForElemMatch = renderForElemMatch; _translationOptions = translationOptions; // can be null + _serializationDomain = BsonSerializer.DefaultSerializationDomain; + } + + /// + /// Initializes a new instance of the record. + /// + /// The document serializer. + /// The path render arguments. + /// Value that specifies whether full dollar for should be rendered. + /// Value that specifies whether rendering a find operation. + /// Value that specifies whether rendering an $elemMatch. + /// The translation options. + /// //TODO + internal RenderArgs( + IBsonSerializer documentSerializer, + IBsonSerializationDomain serializationDomain, + PathRenderArgs pathRenderArgs = default, + bool renderDollarForm = default, + bool renderForFind = false, + bool renderForElemMatch = false, + ExpressionTranslationOptions translationOptions = null) + { + DocumentSerializer = documentSerializer; + PathRenderArgs = pathRenderArgs; + RenderDollarForm = renderDollarForm; + _serializationDomain = serializationDomain ?? BsonSerializer.DefaultSerializationDomain; + _renderForFind = renderForFind; + _renderForElemMatch = renderForElemMatch; + _translationOptions = translationOptions; // can be null + SerializerRegistry = _serializationDomain.SerializerRegistry; } /// @@ -99,12 +131,18 @@ public readonly IBsonSerializer DocumentSerializer /// /// Gets the serializer registry. /// - public readonly IBsonSerializerRegistry SerializerRegistry + public readonly IBsonSerializerRegistry SerializerRegistry //TODO: we should probably remove this property { get => _serializerRegistry; init => _serializerRegistry = Ensure.IsNotNull(value, nameof(value)); } + internal readonly IBsonSerializationDomain SerializationDomain + { + get => _serializationDomain; + init => _serializationDomain = Ensure.IsNotNull(value, nameof(value)); + } + /// /// Gets the translation options used when translation Expressions to MQL. /// @@ -129,6 +167,6 @@ public readonly IBsonSerializer GetSerializer() => /// A new RenderArgs{TNewDocument} instance. /// public readonly RenderArgs WithNewDocumentType(IBsonSerializer serializer) => - new(serializer, _serializerRegistry, _pathRenderArgs, _renderDollarForm, _renderForFind, _renderForElemMatch, _translationOptions); + new(serializer, _serializationDomain, _pathRenderArgs, _renderDollarForm, _renderForFind, _renderForElemMatch, _translationOptions); } } diff --git a/src/MongoDB.Driver/SetFieldDefinitions.cs b/src/MongoDB.Driver/SetFieldDefinitions.cs index 76dcc1c1914..f660419bec3 100644 --- a/src/MongoDB.Driver/SetFieldDefinitions.cs +++ b/src/MongoDB.Driver/SetFieldDefinitions.cs @@ -93,7 +93,7 @@ public ExpressionSetFieldDefinitions(Expression> expres /// public override BsonDocument Render(RenderArgs args) { - var stage = LinqProviderAdapter.TranslateExpressionToSetStage(_expression, args.DocumentSerializer, args.SerializerRegistry, args.TranslationOptions); + var stage = LinqProviderAdapter.TranslateExpressionToSetStage(_expression, args.DocumentSerializer, args.SerializationDomain, args.TranslationOptions); return stage["$set"].AsBsonDocument; } } diff --git a/src/MongoDB.Driver/Support/InternalExtensions.cs b/src/MongoDB.Driver/Support/InternalExtensions.cs new file mode 100644 index 00000000000..8ffefef2d01 --- /dev/null +++ b/src/MongoDB.Driver/Support/InternalExtensions.cs @@ -0,0 +1,39 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using MongoDB.Bson.Serialization; + +namespace MongoDB.Driver.Support +{ + internal static class InternalExtensions + { + #region IPipelineStageDefinition + + public static IRenderedPipelineStageDefinition RenderInternal(this IPipelineStageDefinition pipelineStageDefinition, IBsonSerializer inputSerializer, + IBsonSerializationDomain serializationDomain, IBsonSerializerRegistry serializerRegistry, ExpressionTranslationOptions translationOptions) + { + if (pipelineStageDefinition is IPipelineStageStageDefinitionInternal pipelineStageStageDefinitionInternal) + { + return pipelineStageStageDefinitionInternal + .Render(inputSerializer, serializationDomain, translationOptions); + } + + return pipelineStageDefinition + .Render(inputSerializer, serializerRegistry, translationOptions); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/MongoDB.Driver/Support/ReflectionExtensions.cs b/src/MongoDB.Driver/Support/ReflectionExtensions.cs index 7bae4fa777e..b078332fa20 100644 --- a/src/MongoDB.Driver/Support/ReflectionExtensions.cs +++ b/src/MongoDB.Driver/Support/ReflectionExtensions.cs @@ -18,6 +18,7 @@ using System.Linq; using System.Reflection; using MongoDB.Bson; +using MongoDB.Bson.Serialization; namespace MongoDB.Driver.Support { @@ -62,20 +63,21 @@ public static bool IsBooleanOrNullableBoolean(this Type type) } } - public static bool IsNullable(this Type type) - { - return type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); - } - - public static bool IsNullableEnum(this Type type) - { - if (!IsNullable(type)) - { - return false; - } - - return GetNullableUnderlyingType(type).GetTypeInfo().IsEnum; - } + // Those have been commented out because there are identical methods in Bson assembly. + // public static bool IsNullable(this Type type) + // { + // return type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); + // } + // + // public static bool IsNullableEnum(this Type type) + // { + // if (!IsNullable(type)) + // { + // return false; + // } + // + // return GetNullableUnderlyingType(type).GetTypeInfo().IsEnum; + // } public static bool IsNumeric(this Type type) { @@ -120,7 +122,7 @@ public static bool IsConvertibleToEnum(this Type type) public static Type GetNullableUnderlyingType(this Type type) { - if (!IsNullable(type)) + if (!type.IsNullable()) { throw new ArgumentException("Type must be nullable.", "type"); } diff --git a/src/MongoDB.Driver/UpdateDefinition.cs b/src/MongoDB.Driver/UpdateDefinition.cs index e7434a14d0d..45fbe905edf 100644 --- a/src/MongoDB.Driver/UpdateDefinition.cs +++ b/src/MongoDB.Driver/UpdateDefinition.cs @@ -120,6 +120,7 @@ public override string ToString() return ToString(inputSerializer, serializerRegistry); } + //DOMAIN-API These versions will need to go away. /// /// Returns a that represents this instance. /// diff --git a/src/MongoDB.Driver/UpdateDefinitionBuilder.cs b/src/MongoDB.Driver/UpdateDefinitionBuilder.cs index 9f2bac9d8ff..a3d11c54f44 100644 --- a/src/MongoDB.Driver/UpdateDefinitionBuilder.cs +++ b/src/MongoDB.Driver/UpdateDefinitionBuilder.cs @@ -1366,7 +1366,7 @@ public override BsonValue Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("$addToSet"); bsonWriter.WriteStartDocument(); @@ -1460,7 +1460,7 @@ public override BsonValue Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("$bit"); bsonWriter.WriteStartDocument(); @@ -1517,7 +1517,7 @@ public override BsonValue Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(_operatorName); bsonWriter.WriteStartDocument(); @@ -1581,7 +1581,7 @@ public override BsonValue Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(_values.Count == 1 ? "$pull" : "$pullAll"); bsonWriter.WriteStartDocument(); @@ -1648,7 +1648,7 @@ public override BsonValue Render(RenderArgs args) var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, args.SerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("$push"); bsonWriter.WriteStartDocument(); diff --git a/tests/MongoDB.Bson.Tests/ObjectModel/BsonDocumentWrapperTests.cs b/tests/MongoDB.Bson.Tests/ObjectModel/BsonDocumentWrapperTests.cs index a1f94fb3b41..12dc65583ec 100644 --- a/tests/MongoDB.Bson.Tests/ObjectModel/BsonDocumentWrapperTests.cs +++ b/tests/MongoDB.Bson.Tests/ObjectModel/BsonDocumentWrapperTests.cs @@ -305,12 +305,12 @@ public void TestCreateWithNominalTypeAndObject() { var c = CreateC(); - var wrapper = BsonDocumentWrapper.Create(typeof(C), c); + var wrapper = BsonDocumentWrapper.Create(typeof(C), value: c); Assert.Same(BsonSerializer.LookupSerializer(typeof(C)), wrapper.Serializer); Assert.Same(c, wrapper.Wrapped); Assert.Equal(false, wrapper.IsMaterialized); - wrapper = BsonDocumentWrapper.Create(typeof(C), null); + wrapper = BsonDocumentWrapper.Create(typeof(C), value: null); Assert.Same(BsonSerializer.LookupSerializer(typeof(C)), wrapper.Serializer); Assert.Same(null, wrapper.Wrapped); Assert.Equal(false, wrapper.IsMaterialized); diff --git a/tests/MongoDB.Driver.TestHelpers/Core/CoreTestConfiguration.cs b/tests/MongoDB.Driver.TestHelpers/Core/CoreTestConfiguration.cs index fbc9c8b35b7..861f73d09c0 100644 --- a/tests/MongoDB.Driver.TestHelpers/Core/CoreTestConfiguration.cs +++ b/tests/MongoDB.Driver.TestHelpers/Core/CoreTestConfiguration.cs @@ -20,6 +20,7 @@ using System.Security.Cryptography.X509Certificates; using System.Threading; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Authentication; using MongoDB.Driver.Core.Bindings; @@ -303,7 +304,7 @@ private static int GetMaxWireVersion() using (var binding = CreateReadBinding(session)) { var command = new BsonDocument("hello", 1); - var operation = new ReadCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, __messageEncoderSettings); + var operation = new ReadCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, __messageEncoderSettings, BsonSerializer.DefaultSerializationDomain); var response = operation.Execute(OperationContext.NoTimeout, binding); return response["maxWireVersion"].AsInt32; } @@ -315,7 +316,7 @@ private static SemanticVersion GetServerVersion() using (var binding = CreateReadBinding(session)) { var command = new BsonDocument("buildinfo", 1); - var operation = new ReadCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, __messageEncoderSettings); + var operation = new ReadCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, __messageEncoderSettings, BsonSerializer.DefaultSerializationDomain); var response = operation.Execute(OperationContext.NoTimeout, binding); return SemanticVersion.Parse(response["version"].AsString); } @@ -327,7 +328,7 @@ public static BsonDocument GetServerParameters() using (var binding = CreateReadBinding(session)) { var command = new BsonDocument("getParameter", new BsonString("*")); - var operation = new ReadCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, __messageEncoderSettings); + var operation = new ReadCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, __messageEncoderSettings, BsonSerializer.DefaultSerializationDomain); var serverParameters = operation.Execute(OperationContext.NoTimeout, binding); return serverParameters; @@ -402,7 +403,7 @@ private static IReadWriteBindingHandle CreateReadWriteBinding(ICoreSessionHandle private static void DropDatabase() { - var operation = new DropDatabaseOperation(__databaseNamespace.Value, __messageEncoderSettings); + var operation = new DropDatabaseOperation(__databaseNamespace.Value, __messageEncoderSettings, BsonSerializer.DefaultSerializationDomain); using (var session = StartSession()) using (var binding = CreateReadWriteBinding(session)) @@ -416,7 +417,7 @@ private static IEnumerable FindDocuments(IClusterInternal cluster, using (var session = StartSession(cluster)) using (var binding = CreateReadBinding(cluster, ReadPreference.Primary, session)) { - var operation = new FindOperation(collectionNamespace, BsonDocumentSerializer.Instance, __messageEncoderSettings); + var operation = new FindOperation(collectionNamespace, BsonDocumentSerializer.Instance, __messageEncoderSettings, BsonSerializer.DefaultSerializationDomain); return operation.Execute(OperationContext.NoTimeout, binding).ToList(); } @@ -495,7 +496,7 @@ string GetStorageEngineForCluster(IClusterInternal cluster) using (var session = StartSession(cluster)) using (var binding = CreateReadBinding(cluster, ReadPreference.PrimaryPreferred, session)) { - var operation = new ReadCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, __messageEncoderSettings); + var operation = new ReadCommandOperation(DatabaseNamespace.Admin, command, BsonDocumentSerializer.Instance, __messageEncoderSettings, BsonSerializer.DefaultSerializationDomain); var response = operation.Execute(OperationContext.NoTimeout, binding); if (response.TryGetValue("storageEngine", out var storageEngine) && storageEngine.AsBsonDocument.TryGetValue("name", out var name)) diff --git a/tests/MongoDB.Driver.TestHelpers/Core/FailPoint.cs b/tests/MongoDB.Driver.TestHelpers/Core/FailPoint.cs index 0122eb8447b..bc575e475ea 100644 --- a/tests/MongoDB.Driver.TestHelpers/Core/FailPoint.cs +++ b/tests/MongoDB.Driver.TestHelpers/Core/FailPoint.cs @@ -16,6 +16,7 @@ using System; using System.Threading; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Clusters; @@ -184,7 +185,8 @@ private void ExecuteCommand(BsonDocument command, bool waitForConnected) adminDatabase, command, BsonDocumentSerializer.Instance, - new MessageEncoderSettings()); + new MessageEncoderSettings(), + BsonSerializer.DefaultSerializationDomain); operation.Execute(OperationContext.NoTimeout, _binding); } diff --git a/tests/MongoDB.Driver.Tests/ChangeStreamHelperTests.cs b/tests/MongoDB.Driver.Tests/ChangeStreamHelperTests.cs index 450c92f8ef4..dcd5ba60f9d 100644 --- a/tests/MongoDB.Driver.Tests/ChangeStreamHelperTests.cs +++ b/tests/MongoDB.Driver.Tests/ChangeStreamHelperTests.cs @@ -45,7 +45,7 @@ public void CreateChangeStreamOperation_for_client_returns_expected_result() var messageEncoderSettings = new MessageEncoderSettings(); var renderedPipeline = RenderPipeline(pipeline); - var result = ChangeStreamHelper.CreateChangeStreamOperation(pipeline, options, readConcern, messageEncoderSettings, retryRequested: true, translationOptions: null); + var result = ChangeStreamHelper.CreateChangeStreamOperation(pipeline, options, readConcern, messageEncoderSettings, retryRequested: true, translationOptions: null, BsonSerializer.DefaultSerializationDomain); result.BatchSize.Should().Be(options.BatchSize); result.Collation.Should().BeSameAs(options.Collation); @@ -86,7 +86,7 @@ public void CreateChangeStreamOperation_for_database_returns_expected_result() var messageEncoderSettings = new MessageEncoderSettings(); var renderedPipeline = RenderPipeline(pipeline); - var result = ChangeStreamHelper.CreateChangeStreamOperation(mockDatabase.Object, pipeline, options, readConcern, messageEncoderSettings, retryRequested: true, translationOptions: null); + var result = ChangeStreamHelper.CreateChangeStreamOperation(mockDatabase.Object, pipeline, options, readConcern, messageEncoderSettings, retryRequested: true, translationOptions: null, BsonSerializer.DefaultSerializationDomain); result.BatchSize.Should().Be(options.BatchSize); result.Collation.Should().BeSameAs(options.Collation); @@ -129,7 +129,7 @@ public void CreateChangeStreamOperation_for_collection_returns_expected_result() var messageEncoderSettings = new MessageEncoderSettings(); var renderedPipeline = RenderPipeline(pipeline); - var result = ChangeStreamHelper.CreateChangeStreamOperation(mockCollection.Object, pipeline, documentSerializer, options, readConcern, messageEncoderSettings, retryRequested: true, translationOptions: null); + var result = ChangeStreamHelper.CreateChangeStreamOperation(mockCollection.Object, pipeline, documentSerializer, options, readConcern, messageEncoderSettings, retryRequested: true, translationOptions: null, BsonSerializer.DefaultSerializationDomain); result.BatchSize.Should().Be(options.BatchSize); result.Collation.Should().BeSameAs(options.Collation); diff --git a/tests/MongoDB.Driver.Tests/Core/IAsyncCursorExtensionsTests.cs b/tests/MongoDB.Driver.Tests/Core/IAsyncCursorExtensionsTests.cs index 47b69d6da9a..33956c9400a 100644 --- a/tests/MongoDB.Driver.Tests/Core/IAsyncCursorExtensionsTests.cs +++ b/tests/MongoDB.Driver.Tests/Core/IAsyncCursorExtensionsTests.cs @@ -20,6 +20,7 @@ using System.Threading.Tasks; using FluentAssertions; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.TestHelpers.XunitExtensions; using MongoDB.Driver.Core.Bindings; @@ -342,6 +343,7 @@ private IAsyncCursor CreateCursor(int count) limit: null, serializer: BsonDocumentSerializer.Instance, messageEncoderSettings: new MessageEncoderSettings(), + serializationDomain: BsonSerializer.DefaultSerializationDomain, maxTime: null); } } diff --git a/tests/MongoDB.Driver.Tests/Core/IAsyncCursorSourceExtensionsTests.cs b/tests/MongoDB.Driver.Tests/Core/IAsyncCursorSourceExtensionsTests.cs index dedd7cd59ae..0d167f8dfdc 100644 --- a/tests/MongoDB.Driver.Tests/Core/IAsyncCursorSourceExtensionsTests.cs +++ b/tests/MongoDB.Driver.Tests/Core/IAsyncCursorSourceExtensionsTests.cs @@ -20,6 +20,7 @@ using System.Threading.Tasks; using FluentAssertions; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.TestHelpers.XunitExtensions; using MongoDB.Driver.Core.Bindings; @@ -317,6 +318,7 @@ private IAsyncCursor CreateCursor(int count) limit: null, serializer: BsonDocumentSerializer.Instance, messageEncoderSettings: new MessageEncoderSettings(), + serializationDomain: BsonSerializer.DefaultSerializationDomain, maxTime: null); } diff --git a/tests/MongoDB.Driver.Tests/Core/Operations/AggregateToCollectionOperationTests.cs b/tests/MongoDB.Driver.Tests/Core/Operations/AggregateToCollectionOperationTests.cs index 024fc2a5d1c..eaaee2c5c1d 100644 --- a/tests/MongoDB.Driver.Tests/Core/Operations/AggregateToCollectionOperationTests.cs +++ b/tests/MongoDB.Driver.Tests/Core/Operations/AggregateToCollectionOperationTests.cs @@ -21,6 +21,7 @@ using System.Threading.Tasks; using FluentAssertions; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Driver.Core.Clusters; using MongoDB.Driver.Core.Misc; using MongoDB.Driver.Core.Servers; @@ -121,7 +122,7 @@ public void Constructor_should_throw_when_pipeline_is_null() [Fact] public void Constructor_should_throw_when_pipeline_does_not_end_with_out() { - var exception = Record.Exception(() => new AggregateToCollectionOperation(_collectionNamespace, Enumerable.Empty(), _messageEncoderSettings)); + var exception = Record.Exception(() => new AggregateToCollectionOperation(_collectionNamespace, Enumerable.Empty(), _messageEncoderSettings, BsonSerializer.DefaultSerializationDomain)); var argumentException = exception.Should().BeOfType().Subject; argumentException.ParamName.Should().Be("pipeline"); @@ -130,7 +131,7 @@ public void Constructor_should_throw_when_pipeline_does_not_end_with_out() [Fact] public void Constructor_should_throw_when_messageEncoderSettings_is_null() { - var exception = Record.Exception(() => new AggregateToCollectionOperation(_collectionNamespace, __pipeline, null)); + var exception = Record.Exception(() => new AggregateToCollectionOperation(_collectionNamespace, __pipeline, null, BsonSerializer.DefaultSerializationDomain)); var argumentNullException = exception.Should().BeOfType().Subject; argumentNullException.ParamName.Should().Be("messageEncoderSettings"); diff --git a/tests/MongoDB.Driver.Tests/Core/Operations/AsyncCursorTests.cs b/tests/MongoDB.Driver.Tests/Core/Operations/AsyncCursorTests.cs index 804bf16939b..61445c81cfe 100644 --- a/tests/MongoDB.Driver.Tests/Core/Operations/AsyncCursorTests.cs +++ b/tests/MongoDB.Driver.Tests/Core/Operations/AsyncCursorTests.cs @@ -443,7 +443,8 @@ public void GetMore_should_use_same_session( null, CommandResponseHandling.Return, It.IsAny>(), - It.IsAny())) + It.IsAny(), + It.IsAny())) .Callback(() => sameSessionWasUsed = true) .Returns(Task.FromResult(secondBatch)); @@ -465,8 +466,9 @@ public void GetMore_should_use_same_session( null, CommandResponseHandling.Return, It.IsAny>(), - It.IsAny())) - .Callback(() => sameSessionWasUsed = true) + It.IsAny(), + It.IsAny())) + .Callback(() => sameSessionWasUsed = true) .Returns(secondBatch); subject.MoveNext(CancellationToken.None); @@ -607,7 +609,8 @@ private void VerifyHowManyTimesKillCursorsCommandWasCalled(Mock It.IsAny>(), It.IsAny(), It.IsAny>(), - It.IsAny()), + It.IsAny(), + It.IsAny()), times); } else @@ -625,7 +628,8 @@ private void VerifyHowManyTimesKillCursorsCommandWasCalled(Mock It.IsAny>(), It.IsAny(), It.IsAny>(), - It.IsAny()), + It.IsAny(), + It.IsAny()), times); } } diff --git a/tests/MongoDB.Driver.Tests/Core/Operations/ChangeStreamOperationTests.cs b/tests/MongoDB.Driver.Tests/Core/Operations/ChangeStreamOperationTests.cs index 394685a8807..d6bdd0363c4 100644 --- a/tests/MongoDB.Driver.Tests/Core/Operations/ChangeStreamOperationTests.cs +++ b/tests/MongoDB.Driver.Tests/Core/Operations/ChangeStreamOperationTests.cs @@ -86,7 +86,7 @@ public void constructor_with_database_should_throw_when_pipeline_is_null() var messageEncoderSettings = new MessageEncoderSettings(); - var exception = Record.Exception(() => new ChangeStreamOperation(databaseNamespace, pipeline, resultSerializer, messageEncoderSettings)); + var exception = Record.Exception(() => new ChangeStreamOperation(databaseNamespace, pipeline, resultSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain)); var argumentNullException = exception.Should().BeOfType().Subject; argumentNullException.ParamName.Should().Be("resultSerializer"); @@ -101,7 +101,7 @@ public void constructor_with_database_should_throw_when_messageEncoderSettings_i MessageEncoderSettings messageEncoderSettings = null; - var exception = Record.Exception(() => new ChangeStreamOperation(databaseNamespace, pipeline, resultSerializer, messageEncoderSettings)); + var exception = Record.Exception(() => new ChangeStreamOperation(databaseNamespace, pipeline, resultSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain)); var argumentNullException = exception.Should().BeOfType().Subject; argumentNullException.ParamName.Should().Be("messageEncoderSettings"); @@ -116,7 +116,7 @@ public void constructor_with_database_should_throw_when_resultSerializer_is_null var messageEncoderSettings = new MessageEncoderSettings(); - var exception = Record.Exception(() => new ChangeStreamOperation(databaseNamespace, pipeline, resultSerializer, messageEncoderSettings)); + var exception = Record.Exception(() => new ChangeStreamOperation(databaseNamespace, pipeline, resultSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain)); var argumentNullException = exception.Should().BeOfType().Subject; argumentNullException.ParamName.Should().Be("pipeline"); @@ -130,7 +130,7 @@ public void constructor_with_collection_should_initialize_instance() var resultSerializer = BsonDocumentSerializer.Instance; var messageEncoderSettings = new MessageEncoderSettings(); - var subject = new ChangeStreamOperation(collectionNamespace, pipeline, resultSerializer, messageEncoderSettings); + var subject = new ChangeStreamOperation(collectionNamespace, pipeline, resultSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain); subject.BatchSize.Should().NotHaveValue(); subject.Collation.Should().BeNull(); @@ -173,7 +173,7 @@ public void constructor_with_collection_should_throw_when_pipeline_is_null() var messageEncoderSettings = new MessageEncoderSettings(); - var exception = Record.Exception(() => new ChangeStreamOperation(collectionNamespace, pipeline, resultSerializer, messageEncoderSettings)); + var exception = Record.Exception(() => new ChangeStreamOperation(collectionNamespace, pipeline, resultSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain)); var argumentNullException = exception.Should().BeOfType().Subject; argumentNullException.ParamName.Should().Be("resultSerializer"); @@ -203,7 +203,7 @@ public void constructor_with_collection_should_throw_when_resultSerializer_is_nu var messageEncoderSettings = new MessageEncoderSettings(); - var exception = Record.Exception(() => new ChangeStreamOperation(collectionNamespace, pipeline, resultSerializer, messageEncoderSettings)); + var exception = Record.Exception(() => new ChangeStreamOperation(collectionNamespace, pipeline, resultSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain)); var argumentNullException = exception.Should().BeOfType().Subject; argumentNullException.ParamName.Should().Be("pipeline"); @@ -475,7 +475,7 @@ public void Execute_should_return_expected_results_for_inserts( var pipeline = new[] { BsonDocument.Parse("{ $match : { operationType : \"insert\" } }") }; var resultSerializer = new ChangeStreamDocumentSerializer(BsonDocumentSerializer.Instance); var messageEncoderSettings = new MessageEncoderSettings(); - var subject = new ChangeStreamOperation>(_collectionNamespace, pipeline, resultSerializer, messageEncoderSettings); + var subject = new ChangeStreamOperation>(_collectionNamespace, pipeline, resultSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain); EnsureDatabaseExists(); DropCollection(); Insert("{ _id : 1, x : 1 }"); diff --git a/tests/MongoDB.Driver.Tests/Core/Operations/CreateCollectionOperationTests.cs b/tests/MongoDB.Driver.Tests/Core/Operations/CreateCollectionOperationTests.cs index 8fdc19a7467..17a4d4edc31 100644 --- a/tests/MongoDB.Driver.Tests/Core/Operations/CreateCollectionOperationTests.cs +++ b/tests/MongoDB.Driver.Tests/Core/Operations/CreateCollectionOperationTests.cs @@ -19,6 +19,7 @@ using System.Threading.Tasks; using FluentAssertions; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Driver.Core.Bindings; using MongoDB.Driver.Core.Clusters; using MongoDB.Driver.Core.TestHelpers.XunitExtensions; @@ -394,7 +395,7 @@ public void CreateCommand_should_return_expected_result_when_WriteConcern_is_set [Fact] public void CreateEncryptedCreateCollectionOperationIfConfigured_should_return_expected_result_when_EncryptedFields_is_null() { - var subject = CreateCollectionOperation.CreateEncryptedCreateCollectionOperationIfConfigured(_collectionNamespace, encryptedFields: null, _messageEncoderSettings, null); + var subject = CreateCollectionOperation.CreateEncryptedCreateCollectionOperationIfConfigured(_collectionNamespace, encryptedFields: null, _messageEncoderSettings, BsonSerializer.DefaultSerializationDomain, null); var session = OperationTestHelper.CreateSession(); var s = subject.Should().BeOfType().Subject; @@ -431,7 +432,7 @@ public void CreateEncryptedCreateCollectionOperationIfConfigured_should_return_e }}] }}"); - var subject = CreateCollectionOperation.CreateEncryptedCreateCollectionOperationIfConfigured(_collectionNamespace, encryptedFields, _messageEncoderSettings, null); + var subject = CreateCollectionOperation.CreateEncryptedCreateCollectionOperationIfConfigured(_collectionNamespace, encryptedFields, _messageEncoderSettings, BsonSerializer.DefaultSerializationDomain, null); var session = OperationTestHelper.CreateSession(); var operations = ((CompositeWriteOperation)subject)._operations(); diff --git a/tests/MongoDB.Driver.Tests/Core/Operations/CursorBatchDeserializationHelperTests.cs b/tests/MongoDB.Driver.Tests/Core/Operations/CursorBatchDeserializationHelperTests.cs index c35abc52e0a..8fcced5cd2d 100644 --- a/tests/MongoDB.Driver.Tests/Core/Operations/CursorBatchDeserializationHelperTests.cs +++ b/tests/MongoDB.Driver.Tests/Core/Operations/CursorBatchDeserializationHelperTests.cs @@ -16,6 +16,7 @@ using FluentAssertions; using MongoDB.Bson; using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Core.WireProtocol.Messages.Encoders; using Xunit; @@ -34,7 +35,7 @@ public void DeserializeBatch_should_return_expected_result_when_batch_has_one_do var documentSerializer = BsonDocumentSerializer.Instance; var messageEncoderSettings = new MessageEncoderSettings(); - var result = CursorBatchDeserializationHelper.DeserializeBatch(batch, documentSerializer, messageEncoderSettings); + var result = CursorBatchDeserializationHelper.DeserializeBatch(batch, documentSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain); result.Count.Should().Be(1); result[0].Should().BeOfType(); @@ -51,7 +52,7 @@ public void DeserializeBatch_should_return_expected_result_when_batch_has_two_do var documentSerializer = BsonDocumentSerializer.Instance; var messageEncoderSettings = new MessageEncoderSettings(); - var result = CursorBatchDeserializationHelper.DeserializeBatch(batch, documentSerializer, messageEncoderSettings); + var result = CursorBatchDeserializationHelper.DeserializeBatch(batch, documentSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain); result.Count.Should().Be(2); result[0].Should().BeOfType(); @@ -70,7 +71,7 @@ public void DeserializeBatch_should_return_expected_result_when_batch_is_empty() var documentSerializer = BsonDocumentSerializer.Instance; var messageEncoderSettings = new MessageEncoderSettings(); - var result = CursorBatchDeserializationHelper.DeserializeBatch(batch, documentSerializer, messageEncoderSettings); + var result = CursorBatchDeserializationHelper.DeserializeBatch(batch, documentSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain); result.Count.Should().Be(0); } @@ -86,7 +87,7 @@ public void DeserializeBatch_should_return_expected_result_when_GuidRepresentati var documentSerializer = BsonDocumentSerializer.Instance; var messageEncoderSettings = new MessageEncoderSettings { { "GuidRepresentation", GuidRepresentation.Standard } }; - var result = CursorBatchDeserializationHelper.DeserializeBatch(batch, documentSerializer, messageEncoderSettings); + var result = CursorBatchDeserializationHelper.DeserializeBatch(batch, documentSerializer, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain); result.Count.Should().Be(1); result[0].Should().BeOfType(); diff --git a/tests/MongoDB.Driver.Tests/Core/Operations/ReadCommandOperationTests.cs b/tests/MongoDB.Driver.Tests/Core/Operations/ReadCommandOperationTests.cs index 48b4bed12bf..5b3e9fa7e60 100644 --- a/tests/MongoDB.Driver.Tests/Core/Operations/ReadCommandOperationTests.cs +++ b/tests/MongoDB.Driver.Tests/Core/Operations/ReadCommandOperationTests.cs @@ -107,7 +107,8 @@ public void Execute_should_call_channel_Command_with_unwrapped_command_when_wrap null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } else @@ -125,7 +126,8 @@ public void Execute_should_call_channel_Command_with_unwrapped_command_when_wrap null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } } @@ -161,7 +163,8 @@ public void Execute_should_call_channel_Command_with_wrapped_command_when_additi null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } else @@ -179,7 +182,8 @@ public void Execute_should_call_channel_Command_with_wrapped_command_when_additi null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } } @@ -214,7 +218,8 @@ public void Execute_should_call_channel_Command_with_wrapped_command_when_commen null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } else @@ -232,7 +237,8 @@ public void Execute_should_call_channel_Command_with_wrapped_command_when_commen null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } } @@ -268,7 +274,8 @@ public void Execute_should_call_channel_Command_with_wrapped_command_when_readPr null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } else @@ -286,7 +293,8 @@ public void Execute_should_call_channel_Command_with_wrapped_command_when_readPr null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } } diff --git a/tests/MongoDB.Driver.Tests/Core/Operations/WriteCommandOperationTests.cs b/tests/MongoDB.Driver.Tests/Core/Operations/WriteCommandOperationTests.cs index 71c26aebdba..4d9b44e1815 100644 --- a/tests/MongoDB.Driver.Tests/Core/Operations/WriteCommandOperationTests.cs +++ b/tests/MongoDB.Driver.Tests/Core/Operations/WriteCommandOperationTests.cs @@ -81,7 +81,8 @@ public void Execute_should_call_channel_Command_with_unwrapped_command_when_wrap null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } else @@ -99,7 +100,8 @@ public void Execute_should_call_channel_Command_with_unwrapped_command_when_wrap null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } } @@ -133,7 +135,8 @@ public void Execute_should_call_channel_Command_with_wrapped_command_when_additi null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } else @@ -151,7 +154,8 @@ public void Execute_should_call_channel_Command_with_wrapped_command_when_additi null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } } @@ -185,7 +189,8 @@ public void Execute_should_call_channel_Command_with_wrapped_command_when_commen null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } else @@ -203,7 +208,8 @@ public void Execute_should_call_channel_Command_with_wrapped_command_when_commen null, // postWriteAction CommandResponseHandling.Return, subject.ResultSerializer, - subject.MessageEncoderSettings), + subject.MessageEncoderSettings, + It.IsAny()), Times.Once); } } diff --git a/tests/MongoDB.Driver.Tests/IMongoCollectionExtensionsTests.cs b/tests/MongoDB.Driver.Tests/IMongoCollectionExtensionsTests.cs index a65cf915b5c..f7ba678557b 100644 --- a/tests/MongoDB.Driver.Tests/IMongoCollectionExtensionsTests.cs +++ b/tests/MongoDB.Driver.Tests/IMongoCollectionExtensionsTests.cs @@ -20,6 +20,7 @@ using System.Threading; using FluentAssertions; using MongoDB.Bson; +using MongoDB.Bson.Serialization; using MongoDB.Driver.Tests.Linq.Linq3Implementation; using MongoDB.TestHelpers.XunitExtensions; using Moq; diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Linq3IntegrationTest.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Linq3IntegrationTest.cs index b198cf4e9a1..e61bffdae66 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Linq3IntegrationTest.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Linq3IntegrationTest.cs @@ -55,7 +55,7 @@ protected void CreateCollection(IMongoCollection collectio protected void CreateCollection(IMongoCollection collection, params TDocument[] documents) { - CreateCollection(collection, (IEnumerable)documents); ; + CreateCollection(collection, (IEnumerable)documents); } protected IMongoCollection GetCollection(string collectionName = null) diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ModuloComparisonExpressionToFilterTranslatorTests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ModuloComparisonExpressionToFilterTranslatorTests.cs index 10f3f2a5d14..c7c7cb9b4a3 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ModuloComparisonExpressionToFilterTranslatorTests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ModuloComparisonExpressionToFilterTranslatorTests.cs @@ -182,8 +182,9 @@ private void Assert(AstFilter result, string path, BsonValue divisor, BsonValue private TranslationContext CreateContext(ParameterExpression parameter) { - var serializer = BsonSerializer.LookupSerializer(parameter.Type); - var context = TranslationContext.Create(translationOptions: null); + var domain = BsonSerializer.DefaultSerializationDomain; + var serializer = domain.LookupSerializer(parameter.Type); + var context = TranslationContext.Create(translationOptions: null, domain); var symbol = context.CreateSymbol(parameter, serializer, isCurrent: true); return context.WithSymbol(symbol); } diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationWithLinq2Tests/Translators/AggregateGroupTranslatorTests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationWithLinq2Tests/Translators/AggregateGroupTranslatorTests.cs index a8f7428079b..ecc5d33e339 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationWithLinq2Tests/Translators/AggregateGroupTranslatorTests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationWithLinq2Tests/Translators/AggregateGroupTranslatorTests.cs @@ -641,7 +641,8 @@ private ProjectedResult Group(Expression(Expression> expression, int { expression = (Expression>)PartialEvaluator.EvaluatePartially(expression); + var domain = BsonSerializer.DefaultSerializationDomain; var parameter = expression.Parameters.Single(); var serializer = BsonSerializer.LookupSerializer(); - var context = TranslationContext.Create(translationOptions: null); + var context = TranslationContext.Create(translationOptions: null, serializationDomain: domain); var symbol = context.CreateSymbol(parameter, serializer, isCurrent: true); context = context.WithSymbol(symbol); var filterAst = ExpressionToFilterTranslator.Translate(context, expression.Body); diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationWithLinq2Tests/Translators/PredicateTranslatorTests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationWithLinq2Tests/Translators/PredicateTranslatorTests.cs index 0869d70822e..1dbc964d7a8 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationWithLinq2Tests/Translators/PredicateTranslatorTests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3ImplementationWithLinq2Tests/Translators/PredicateTranslatorTests.cs @@ -1152,9 +1152,10 @@ public List Assert(IMongoCollection collection, { filter = (Expression>)PartialEvaluator.EvaluatePartially(filter); - var serializer = BsonSerializer.SerializerRegistry.GetSerializer(); + var domain = BsonSerializer.DefaultSerializationDomain; + var serializer = domain.SerializerRegistry.GetSerializer(); var parameter = filter.Parameters.Single(); - var context = TranslationContext.Create(translationOptions: null); + var context = TranslationContext.Create(translationOptions: null, serializationDomain: domain); var symbol = context.CreateSymbol(parameter, serializer, isCurrent: true); context = context.WithSymbol(symbol); var filterAst = ExpressionToFilterTranslator.Translate(context, filter.Body); diff --git a/tests/MongoDB.Driver.Tests/Linq/LinqProviderAdapterTests.cs b/tests/MongoDB.Driver.Tests/Linq/LinqProviderAdapterTests.cs index f6f0d15f647..789caacae8a 100644 --- a/tests/MongoDB.Driver.Tests/Linq/LinqProviderAdapterTests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/LinqProviderAdapterTests.cs @@ -20,7 +20,6 @@ using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Linq; using MongoDB.Driver.Linq.Linq3Implementation; -using MongoDB.Driver.Tests; using MongoDB.Driver.Tests.Linq.Linq3Implementation; using Moq; using Xunit; @@ -48,10 +47,10 @@ public void AsQueryable_should_return_expected_result() public void TranslateExpressionToAggregateExpression_should_return_expected_result() { Expression> expression = c => c.X; - var serializerRegistry = BsonSerializer.SerializerRegistry; - var sourceSerializer = serializerRegistry.GetSerializer(); + var serializationDomain = BsonSerializer.DefaultSerializationDomain; + var sourceSerializer = serializationDomain.SerializerRegistry.GetSerializer(); - var result = LinqProviderAdapter.TranslateExpressionToAggregateExpression(expression, sourceSerializer, serializerRegistry, translationOptions: null); + var result = LinqProviderAdapter.TranslateExpressionToAggregateExpression(expression, sourceSerializer, serializationDomain, translationOptions: null); result.Should().Be("'$X'"); } @@ -60,10 +59,10 @@ public void TranslateExpressionToAggregateExpression_should_return_expected_resu public void TranslateExpressionToField_with_untyped_lambda_should_return_expected_result() { LambdaExpression expression = (Expression>)(c => c.X); - var serializerRegistry = BsonSerializer.SerializerRegistry; - var documentSerializer = serializerRegistry.GetSerializer(); + var serializationDomain = BsonSerializer.DefaultSerializationDomain; + var documentSerializer = serializationDomain.SerializerRegistry.GetSerializer(); - var result = LinqProviderAdapter.TranslateExpressionToField(expression, documentSerializer, serializerRegistry, translationOptions: null); + var result = LinqProviderAdapter.TranslateExpressionToField(expression, documentSerializer, serializationDomain, translationOptions: null); result.FieldName.Should().Be("X"); result.FieldSerializer.Should().BeOfType(typeof(Int32Serializer)); @@ -73,10 +72,10 @@ public void TranslateExpressionToField_with_untyped_lambda_should_return_expecte public void TranslateExpressionToField_with_typed_lambda_should_return_expected_result() { Expression> expression = c => c.X; - var serializerRegistry = BsonSerializer.SerializerRegistry; - var documentSerializer = serializerRegistry.GetSerializer(); + var serializationDomain = BsonSerializer.DefaultSerializationDomain; + var documentSerializer = serializationDomain.SerializerRegistry.GetSerializer(); - var result = LinqProviderAdapter.TranslateExpressionToField(expression, documentSerializer, serializerRegistry, translationOptions: null, allowScalarValueForArrayField: false); + var result = LinqProviderAdapter.TranslateExpressionToField(expression, documentSerializer, serializationDomain, translationOptions: null, allowScalarValueForArrayField: false); result.FieldName.Should().Be("X"); result.FieldSerializer.Should().BeOfType(typeof(Int32Serializer)); @@ -86,10 +85,10 @@ public void TranslateExpressionToField_with_typed_lambda_should_return_expected_ public void TranslateExpressionToFilter_should_return_expected_result() { Expression> expression = c => c.X == 0; - var serializerRegistry = BsonSerializer.SerializerRegistry; - var documentSerializer = serializerRegistry.GetSerializer(); + var serializationDomain = BsonSerializer.DefaultSerializationDomain; + var documentSerializer = serializationDomain.SerializerRegistry.GetSerializer(); - var result = LinqProviderAdapter.TranslateExpressionToFilter(expression, documentSerializer, serializerRegistry, translationOptions: null); + var result = LinqProviderAdapter.TranslateExpressionToFilter(expression, documentSerializer, serializationDomain, translationOptions: null); result.Should().Be("{ X : 0 }"); } @@ -98,10 +97,10 @@ public void TranslateExpressionToFilter_should_return_expected_result() public void TranslateExpressionToFindProjection_should_return_expected_result() { Expression> expression = c => c.X; - var serializerRegistry = BsonSerializer.SerializerRegistry; - var documentSerializer = serializerRegistry.GetSerializer(); + var serializationDomain = BsonSerializer.DefaultSerializationDomain; + var documentSerializer = serializationDomain.SerializerRegistry.GetSerializer(); - var result = LinqProviderAdapter.TranslateExpressionToFindProjection(expression, documentSerializer, serializerRegistry, translationOptions: null); + var result = LinqProviderAdapter.TranslateExpressionToFindProjection(expression, documentSerializer, serializationDomain, translationOptions: null); result.Document.Should().Be("{ X : 1, _id : 0 }"); result.ProjectionSerializer.ValueType.Should().Be(typeof(int)); @@ -114,10 +113,10 @@ public void TranslateExpressionToProjection_should_return_expected_result() void WithAnonymousOutputType(Expression> expression) { - var serializerRegistry = BsonSerializer.SerializerRegistry; - var inputSerializer = serializerRegistry.GetSerializer(); + var serializationDomain = BsonSerializer.DefaultSerializationDomain; + var inputSerializer = serializationDomain.SerializerRegistry.GetSerializer(); - var result = LinqProviderAdapter.TranslateExpressionToProjection(expression, inputSerializer, serializerRegistry, translationOptions: null); + var result = LinqProviderAdapter.TranslateExpressionToProjection(expression, inputSerializer, serializationDomain, translationOptions: null); result.Document.Should().Be("{ _id : '$_id', x : '$X' }"); result.ProjectionSerializer.ValueType.Should().Be(typeof(TOutput)); diff --git a/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs b/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs new file mode 100644 index 00000000000..5c7e655e134 --- /dev/null +++ b/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs @@ -0,0 +1,357 @@ +/* Copyright 2010-present MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Linq; +using MongoDB.Bson; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Conventions; +using MongoDB.Bson.Serialization.Serializers; +using MongoDB.Driver.Core.TestHelpers.XunitExtensions; +using MongoDB.Driver.Linq; +using Xunit; + +namespace MongoDB.Driver.Tests +{ + [Trait("Category", "Integration")] + public class MultipleRegistriesTests + { + [Fact] + public void TestSerialization() + { + RequireServer.Check(); + + // { + // var client = CreateClient(); + // var collection = GetTypedCollection(client); + // var bsonCollection = GetUntypedCollection(client); + // + // var person = new Person { Id = ObjectId.Parse("6797b56bf5495bf53aa3078f"), Name = "Mario", Age = 24 }; + // collection.InsertOne(person); + // + // var retrieved = bsonCollection.FindSync(FilterDefinition.Empty).ToList().Single(); + // var toString = retrieved.ToString(); + // + // var expectedVal = + // """{ "_id" : { "$oid" : "6797b56bf5495bf53aa3078f" }, "Name" : "Mario", "Age" : 24 }"""; + // Assert.Equal(expectedVal, toString); + // } + + //The first section demonstrates that the class maps are also separated + { + var customDomain = BsonSerializer.CreateSerializationDomain(); + customDomain.RegisterSerializer(new CustomStringSerializer()); + + var client = CreateClientWithDomain(customDomain); + var collection = GetTypedCollection(client); + var bsonCollection = GetUntypedCollection(client); + + var person = new Person { Id = ObjectId.Parse("6797b56bf5495bf53aa3078f"), Name = "Mario", Age = 24 }; + collection.InsertOne(person); + + var retrievedAsBson = bsonCollection.FindSync(FilterDefinition.Empty).ToList().Single(); + var toString = retrievedAsBson.ToString(); + + var expectedVal = + """{ "_id" : { "$oid" : "6797b56bf5495bf53aa3078f" }, "Name" : "Mariotest", "Age" : 24 }"""; + Assert.Equal(expectedVal, toString); + + var retrievedTyped = collection.FindSync(FilterDefinition.Empty).ToList().Single(); + Assert.Equal("Mario", retrievedTyped.Name); + } + } + + [Fact] + public void TestDeserialization() + { + RequireServer.Check(); + + { + var client = CreateClient(); + var collection = GetTypedCollection(client); + + var person = new Person1 { Id = ObjectId.Parse("6797b56bf5495bf53aa3078f"), Name = "Mariotest", Age = 24 }; + collection.InsertOne(person); + } + + { + var customDomain = BsonSerializer.CreateSerializationDomain(); + customDomain.RegisterSerializer(new CustomStringSerializer()); + + var client = CreateClientWithDomain(customDomain, dropCollection: false); + var collection = GetTypedCollection(client); + + var retrievedTyped = collection.FindSync(FilterDefinition.Empty).ToList().Single(); + Assert.Equal("Mario", retrievedTyped.Name); + } + } + + [Fact] + public void TestLinq() + { + RequireServer.Check(); + + var customDomain = BsonSerializer.CreateSerializationDomain(); + customDomain.RegisterSerializer(new CustomStringSerializer()); + + var client = CreateClientWithDomain(customDomain); + var collection = GetTypedCollection(client); + var untypedCollection = GetUntypedCollection(client); + + var person = new Person { Id = ObjectId.Parse("6797b56bf5495bf53aa3078f"), Name = "Mario", Age = 24 }; + collection.InsertOne(person); + + var retrievedAsBson = untypedCollection.FindSync(FilterDefinition.Empty).ToList().Single(); + var toString = retrievedAsBson.ToString(); + + var expectedVal = + """{ "_id" : { "$oid" : "6797b56bf5495bf53aa3078f" }, "Name" : "Mariotest", "Age" : 24 }"""; + Assert.Equal(expectedVal, toString); + + var retrievedTyped = collection.AsQueryable().Where(x => x.Name == "Mario").ToList(); //The string serializer is correctly serializing "Mario" to "Mariotest" + Assert.NotEmpty(retrievedTyped); + } + + [Fact] + public void TestConventions() + { + RequireServer.Check(); + + var customDomain = BsonSerializer.CreateSerializationDomain(); + + // Register an id generator convention that uses a custom ObjectIdGenerator + customDomain.RegisterIdGenerator(typeof(ObjectId), new CustomObjectIdGenerator()); + + //Register a convention to use lowercase for all fields on the Person class + var pack = new ConventionPack(); + pack.AddMemberMapConvention( + "LowerCaseElementName", + m => m.SetElementName(m.MemberName.ToLower())); + customDomain.ConventionRegistry.Register("myPack", pack, t => t == typeof(Person)); + + var client = CreateClientWithDomain(customDomain); + var collection = GetTypedCollection(client); + var untypedCollection = GetUntypedCollection(client); + + var person = new Person { Name = "Mario", Age = 24 }; //Id is not set, so the custom ObjectIdGenerator should be used + collection.InsertOne(person); + + var retrievedAsBson = untypedCollection.FindSync(FilterDefinition.Empty).ToList().Single(); + var toString = retrievedAsBson.ToString(); + + var expectedVal = + """{ "_id" : { "$oid" : "6797b56bf5495bf53aa3078f" }, "name" : "Mario", "age" : 24 }"""; + Assert.Equal(expectedVal, toString); + } + + [Fact] + public void TestDiscriminators() + { + RequireServer.Check(); + + var customDomain = BsonSerializer.CreateSerializationDomain(); + + customDomain.BsonClassMap.RegisterClassMap(cm => + { + cm.AutoMap(); + cm.SetIsRootClass(true); + }); + + customDomain.BsonClassMap.RegisterClassMap(cm => + { + cm.AutoMap(); + cm.SetDiscriminator("dp1"); + cm.MapMember( m => m.ExtraField1).SetSerializer(new CustomStringSerializer()); + }); + + customDomain.BsonClassMap.RegisterClassMap(cm => + { + cm.AutoMap(); + cm.SetDiscriminator("dp2"); + cm.MapMember( m => m.ExtraField2).SetSerializer(new CustomStringSerializer()); + }); + + var client = CreateClientWithDomain(customDomain); + var collection = GetTypedCollection(client); + + var bp1 = new DerivedPerson1 { Name = "Alice", Age = 30, ExtraField1 = "Field1" }; + var bp2 = new DerivedPerson2 { Name = "Bob", Age = 40, ExtraField2 = "Field2" }; + collection.InsertMany(new BasePerson[] { bp1, bp2 }); + + //Aggregate with OfType + var retrievedDerivedPerson1 = collection.Aggregate().OfType().Single(); + var retrievedDerivedPerson2 = collection.Aggregate().OfType().Single(); + + AssertDerivedPerson1(bp1, retrievedDerivedPerson1); + AssertDerivedPerson2(bp2, retrievedDerivedPerson2); + + //AppendStage with OfType + retrievedDerivedPerson1 = collection.AsQueryable().AppendStage(PipelineStageDefinitionBuilder.OfType()) + .OfType().Single(); + retrievedDerivedPerson2 = collection.AsQueryable().AppendStage(PipelineStageDefinitionBuilder.OfType()) + .OfType().Single(); + + AssertDerivedPerson1(bp1, retrievedDerivedPerson1); + AssertDerivedPerson2(bp2, retrievedDerivedPerson2); + + //LINQ with OfType + retrievedDerivedPerson1 = collection.AsQueryable().OfType().Single(); + retrievedDerivedPerson2 = collection.AsQueryable().OfType().Single(); + + AssertDerivedPerson1(bp1, retrievedDerivedPerson1); + AssertDerivedPerson2(bp2, retrievedDerivedPerson2); + + //Facet with OfType + + var pipeline1 = PipelineDefinition.Create( new [] { + PipelineStageDefinitionBuilder.OfType() }); + var facet1 = AggregateFacet.Create("facet1", pipeline1); + + var pipeline2 = PipelineDefinition.Create( new [] { + PipelineStageDefinitionBuilder.OfType() }); + var facet2 = AggregateFacet.Create("facet2", pipeline2); + + var result = collection.Aggregate().Facet(facet1, facet2).Single().Facets; + retrievedDerivedPerson1 = result[0].Output().Single(); + retrievedDerivedPerson2 = result[1].Output().Single(); + + AssertDerivedPerson1(bp1, retrievedDerivedPerson1); + AssertDerivedPerson2(bp2, retrievedDerivedPerson2); + + //Find with OfType + var retrievedBasePerson1 = collection.FindSync(Builders.Filter.OfType()).Single(); + var retrievedBasePerson2 = collection.FindSync(Builders.Filter.OfType()).Single(); + + AssertBasePerson(bp1, retrievedBasePerson1); + AssertBasePerson(bp2, retrievedBasePerson2); + + void AssertDerivedPerson1(DerivedPerson1 expected, DerivedPerson1 retrieved) + { + AssertBasePerson(expected, retrieved); + Assert.Equal(expected.ExtraField1, retrieved.ExtraField1); + } + + void AssertDerivedPerson2(DerivedPerson2 expected, DerivedPerson2 retrieved) + { + AssertBasePerson(expected, retrieved); + Assert.Equal(expected.ExtraField2, retrieved.ExtraField2); + } + + void AssertBasePerson(BasePerson expected, BasePerson retrieved) + { + Assert.Equal(expected.Id, retrieved.Id); + Assert.Equal(expected.Name, retrieved.Name); + Assert.Equal(expected.Age, retrieved.Age); + } + } + + private static IMongoCollection GetTypedCollection(IMongoClient client) => + client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName) + .GetCollection(DriverTestConfiguration.CollectionNamespace.CollectionName); + + private static IMongoCollection GetUntypedCollection(IMongoClient client) => + client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName) + .GetCollection(DriverTestConfiguration.CollectionNamespace.CollectionName); + + private static IMongoClient CreateClientWithDomain(IBsonSerializationDomain domain, bool dropCollection = true) + { + var client = DriverTestConfiguration.CreateMongoClient((MongoClientSettings c) => ((IInheritableMongoClientSettings)c).SerializationDomain = domain); + if (dropCollection) + { + var db = client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName); + db.DropCollection(DriverTestConfiguration.CollectionNamespace.CollectionName); + } + return client; + } + + private static IMongoClient CreateClient() + { + var client = DriverTestConfiguration.CreateMongoClient(); + var db = client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName); + db.DropCollection(DriverTestConfiguration.CollectionNamespace.CollectionName); + return client; + } + + public class Person + { + [BsonId] public ObjectId Id { get; set; } + public string Name { get; set; } + public int Age { get; set; } + } + + public class Person1 + { + [BsonId] public ObjectId Id { get; set; } + public string Name { get; set; } + public int Age { get; set; } + } + + public class BasePerson + { + [BsonId] public ObjectId Id { get; set; } = ObjectId.GenerateNewId(); + public string Name { get; set; } + public int Age { get; set; } + } + + public class DerivedPerson1 : BasePerson + { + public string ExtraField1 { get; set; } + } + + public class DerivedPerson2 : BasePerson + { + public string ExtraField2 { get; set; } + } + + + public class CustomStringSerializer : SealedClassSerializerBase //This serializer just adds "test" to any serialised string + { + /// + public override int GetHashCode() => 0; + + protected override string DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) + { + var bsonReader = context.Reader; + + var bsonType = bsonReader.GetCurrentBsonType(); + return bsonType switch + { + BsonType.String => bsonReader.ReadString().Replace("test", ""), + _ => throw CreateCannotDeserializeFromBsonTypeException(bsonType) + }; + } + + protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, + string value) + { + var bsonWriter = context.Writer; + bsonWriter.WriteString(value + "test"); + } + } + + public class CustomObjectIdGenerator : IIdGenerator + { + public object GenerateId(object container, object document) + { + return ObjectId.Parse("6797b56bf5495bf53aa3078f"); + } + + public bool IsEmpty(object id) + { + return true; + } + } + } +} \ No newline at end of file From 0595cb8fd769b20386632074938ba1bf65fba7d5 Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Wed, 20 Aug 2025 10:17:25 +0200 Subject: [PATCH 02/21] small correction --- .../Core/Operations/AggregateToCollectionOperation.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/MongoDB.Driver/Core/Operations/AggregateToCollectionOperation.cs b/src/MongoDB.Driver/Core/Operations/AggregateToCollectionOperation.cs index 39317008a31..427450364e7 100644 --- a/src/MongoDB.Driver/Core/Operations/AggregateToCollectionOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/AggregateToCollectionOperation.cs @@ -70,6 +70,12 @@ public AggregateToCollectionOperation(CollectionNamespace collectionNamespace, I _collectionNamespace = collectionNamespace; } + //EXIT + public AggregateToCollectionOperation(CollectionNamespace collectionNamespace, IEnumerable pipeline, MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, pipeline, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { + } + public bool? AllowDiskUse { get { return _allowDiskUse; } From d83811d2d535f09242402c653f4a9bbda4960fbb Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Wed, 20 Aug 2025 10:59:41 +0200 Subject: [PATCH 03/21] Lazy inizialization of DiscriminatedInterfaceSerializer --- .../Serialization/BsonClassMap.cs | 4 +- .../DiscriminatedInterfaceSerializer.cs | 60 ++++++++++++------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/MongoDB.Bson/Serialization/BsonClassMap.cs b/src/MongoDB.Bson/Serialization/BsonClassMap.cs index 1d965e89cff..40f3a0f9929 100644 --- a/src/MongoDB.Bson/Serialization/BsonClassMap.cs +++ b/src/MongoDB.Bson/Serialization/BsonClassMap.cs @@ -424,9 +424,9 @@ internal class FreezeContext /// The frozen class map. public BsonClassMap Freeze() => Freeze(BsonSerializer.DefaultSerializationDomain); - internal BsonClassMap Freeze(IBsonSerializationDomain domain) + internal BsonClassMap Freeze(IBsonSerializationDomain serializationDomain) { - var freezeContext = new FreezeContext { SerializationDomain = domain }; + var freezeContext = new FreezeContext { SerializationDomain = serializationDomain }; return Freeze(freezeContext); } diff --git a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs index 36719d18b57..62b7c902635 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs @@ -55,9 +55,11 @@ private static IBsonSerializer CreateInterfaceSerializer(IBsonSerial // private fields private readonly Type _interfaceType; - private readonly IDiscriminatorConvention _discriminatorConvention; private readonly IBsonSerializer _interfaceSerializer; - private readonly IBsonSerializer _objectSerializer; + private readonly Lazy _discriminatorConvention; + private readonly Lazy> _objectSerializer; + + private IBsonSerializationDomain _serializationDomain; // constructors /// @@ -109,26 +111,13 @@ public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorCo } _interfaceType = typeof(TInterface); - _discriminatorConvention = discriminatorConvention ?? interfaceSerializer.GetDiscriminatorConvention(); //QUESTION What do we do here? We don't have the domain close by, should we lazy initialize it during serialization/deserialization? + _discriminatorConvention = discriminatorConvention != null + ? new Lazy(() => discriminatorConvention) + : new Lazy(() => GetDiscriminatorConvention(_serializationDomain)); + _objectSerializer = objectSerializer != null + ? new Lazy>(() => objectSerializer) + : new Lazy>(() => GetObjectSerializer(_serializationDomain)); _interfaceSerializer = interfaceSerializer; - - if (objectSerializer == null) - { - objectSerializer = BsonSerializer.LookupSerializer(); //QUESTION What do we do here? We don't have the domain close by, should we lazy initialize it during serialization/deserialization? - if (objectSerializer is ObjectSerializer standardObjectSerializer) - { - Func allowedTypes = (Type type) => typeof(TInterface).IsAssignableFrom(type); - objectSerializer = standardObjectSerializer - .WithDiscriminatorConvention(_discriminatorConvention) - .WithAllowedTypes(allowedTypes, allowedTypes); - } - else - { - throw new BsonSerializationException("Can't set discriminator convention on custom object serializer."); - } - } - - _objectSerializer = objectSerializer; } // public properties @@ -149,6 +138,7 @@ public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorCo /// public override TInterface Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { + _serializationDomain = context.SerializationDomain; var bsonReader = context.Reader; if (bsonReader.GetCurrentBsonType() == BsonType.Null) @@ -158,7 +148,7 @@ public override TInterface Deserialize(BsonDeserializationContext context, BsonD } else { - var actualType = _discriminatorConvention.GetActualTypeInternal(bsonReader, typeof(TInterface), context.SerializationDomain); + var actualType = _discriminatorConvention.Value.GetActualTypeInternal(bsonReader, typeof(TInterface), context.SerializationDomain); if (actualType == _interfaceType) { var message = string.Format("Unable to determine actual type of object to deserialize for interface type {0}.", _interfaceType.FullName); @@ -193,6 +183,7 @@ obj is DiscriminatedInterfaceSerializer other && /// The document. public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TInterface value) { + _serializationDomain = context.SerializationDomain; var bsonWriter = context.Writer; if (value == null) @@ -202,7 +193,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati else { args.NominalType = typeof(object); - _objectSerializer.Serialize(context, args, value); + _objectSerializer.Value.Serialize(context, args, value); } } @@ -217,5 +208,28 @@ public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializati serializationInfo = null; return false; } + + private IDiscriminatorConvention GetDiscriminatorConvention(IBsonSerializationDomain serializationDomain) + { + return _interfaceSerializer.GetDiscriminatorConvention(serializationDomain); + } + + private IBsonSerializer GetObjectSerializer(IBsonSerializationDomain serializationDomain) + { + var objectSerializer = serializationDomain.LookupSerializer(); + if (objectSerializer is ObjectSerializer standardObjectSerializer) + { + var allowedTypes = (Type type) => typeof(TInterface).IsAssignableFrom(type); + objectSerializer = standardObjectSerializer + .WithDiscriminatorConvention(_discriminatorConvention.Value) + .WithAllowedTypes(allowedTypes, allowedTypes); + } + else + { + throw new BsonSerializationException("Can't set discriminator convention on custom object serializer."); + } + + return objectSerializer; + } } } From ef988c3f8d4f38044eabb33b57859dec02f65ca8 Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Wed, 20 Aug 2025 12:10:45 +0200 Subject: [PATCH 04/21] Small corrections-adjustements. --- src/MongoDB.Bson/IO/BsonWriterSettings.cs | 1 - .../Serialization/BsonDeserializationContext.cs | 12 +++++------- .../Serialization/BsonSerializationInfo.cs | 4 ++-- src/MongoDB.Bson/Serialization/BsonSerializer.cs | 6 +----- .../Serialization/IBsonSerializationDomain.cs | 15 +++++++++++++++ .../Serialization/Serializers/TupleSerializers.cs | 3 ++- 6 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/MongoDB.Bson/IO/BsonWriterSettings.cs b/src/MongoDB.Bson/IO/BsonWriterSettings.cs index 82b92538605..06957993d70 100644 --- a/src/MongoDB.Bson/IO/BsonWriterSettings.cs +++ b/src/MongoDB.Bson/IO/BsonWriterSettings.cs @@ -14,7 +14,6 @@ */ using System; -using MongoDB.Bson.Serialization; namespace MongoDB.Bson.IO { diff --git a/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs b/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs index 696e2f9c39b..37f1826f22f 100644 --- a/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs +++ b/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs @@ -46,9 +46,6 @@ private BsonDeserializationContext( _serializationDomain = serializationDomain; //FP Using this version to find error in an easier way for now //_serializationDomain = serializationDomain ?? BsonSerializer.DefaultSerializationDomain; - - _dynamicArraySerializer ??= _serializationDomain.BsonDefaults.DynamicArraySerializer; - _dynamicDocumentSerializer ??= _serializationDomain.BsonDefaults.DynamicDocumentSerializer; } // public properties @@ -177,10 +174,11 @@ internal Builder(BsonDeserializationContext other, IBsonReader reader, IBsonSeri _dynamicArraySerializer = other.DynamicArraySerializer; _dynamicDocumentSerializer = other.DynamicDocumentSerializer; } - - /* QUESTION I removed the part where we set the dynamic serializers from the BsonDefaults, and delay it until we have a serialization domain (when we build the DeserializationContext). - * This is technically changing the public behaviour, but it's in a builder, I do not thing it will affect anyone. Same done for the serialization context. - */ + else + { + _dynamicArraySerializer = serializationDomain.BsonDefaults.DynamicArraySerializer; + _dynamicDocumentSerializer = serializationDomain.BsonDefaults.DynamicDocumentSerializer; + } } // properties diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs b/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs index f91a52ea4e2..513c74338bb 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs @@ -155,7 +155,7 @@ public BsonValue SerializeValue(object value) var tempDocument = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(tempDocument)) { - //QUESTION Is it correct we only need a default domain here? + //QUESTION Is it correct we only need a standard domain here? var context = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("value"); @@ -175,7 +175,7 @@ public BsonArray SerializeValues(IEnumerable values) var tempDocument = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(tempDocument)) { - //QUESTION Is it correct we only need a default domain here? + //QUESTION Is it correct we only need a standard domain here? var context = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("values"); diff --git a/src/MongoDB.Bson/Serialization/BsonSerializer.cs b/src/MongoDB.Bson/Serialization/BsonSerializer.cs index a862d05cb81..c792c9d5839 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializer.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializer.cs @@ -64,11 +64,7 @@ public static bool UseZeroIdChecker internal static ReaderWriterLockSlim ConfigLock => _serializationDomain.ConfigLock; // public static methods - - /// - /// //TODO - /// - /// + //FP TODO: This is used only for testing, it can be removed later. internal static IBsonSerializationDomain CreateSerializationDomain() => new BsonSerializationDomain(); /// diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs b/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs index 34315129a4d..46aecd27b31 100644 --- a/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs +++ b/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs @@ -1,3 +1,18 @@ +/* Copyright 2010-present MongoDB Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + using System; using System.IO; using System.Threading; diff --git a/src/MongoDB.Bson/Serialization/Serializers/TupleSerializers.cs b/src/MongoDB.Bson/Serialization/Serializers/TupleSerializers.cs index 140f40c9259..638df6a4789 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/TupleSerializers.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/TupleSerializers.cs @@ -109,12 +109,13 @@ public sealed class TupleSerializer : SealedClassSerializerBase>, // private fields private readonly Lazy> _lazyItem1Serializer; + //DOMAIN-API This should be removed in the future. // constructors /// /// Initializes a new instance of the class. /// public TupleSerializer() - : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is + : this(BsonSerializer.SerializerRegistry) { } From 879f6c582907ad3199b1d29293ff1af843d2b324 Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Wed, 20 Aug 2025 12:20:45 +0200 Subject: [PATCH 05/21] Small fix --- .../Serializers/DiscriminatedInterfaceSerializer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs index 62b7c902635..3b11d10a101 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs @@ -168,7 +168,7 @@ public override bool Equals(object obj) return base.Equals(obj) && obj is DiscriminatedInterfaceSerializer other && - object.Equals(_discriminatorConvention, other._discriminatorConvention) && + object.Equals(_discriminatorConvention.Value, other._discriminatorConvention.Value) && object.Equals(_interfaceSerializer, other._interfaceSerializer); } From 43ea9c257c0eb5e9d50b3037ad88252191280033 Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Wed, 20 Aug 2025 17:32:21 +0200 Subject: [PATCH 06/21] Added missing check. --- .../Core/Operations/AggregateToCollectionOperation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MongoDB.Driver/Core/Operations/AggregateToCollectionOperation.cs b/src/MongoDB.Driver/Core/Operations/AggregateToCollectionOperation.cs index 427450364e7..c19753c83b3 100644 --- a/src/MongoDB.Driver/Core/Operations/AggregateToCollectionOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/AggregateToCollectionOperation.cs @@ -204,7 +204,7 @@ public BsonDocument CreateCommand(OperationContext operationContext, ICoreSessio { "pipeline", new BsonArray(_pipeline) }, { "allowDiskUse", () => _allowDiskUse.Value, _allowDiskUse.HasValue }, { "bypassDocumentValidation", () => _bypassDocumentValidation.Value, _bypassDocumentValidation.HasValue }, - { "maxTimeMS", () => MaxTimeHelper.ToMaxTimeMS(_maxTime.Value), _maxTime.HasValue }, + { "maxTimeMS", () => MaxTimeHelper.ToMaxTimeMS(_maxTime.Value), _maxTime.HasValue && !operationContext.IsRootContextTimeoutConfigured() }, { "collation", () => _collation.ToBsonDocument(), _collation != null }, { "readConcern", readConcern, readConcern != null }, { "writeConcern", writeConcern, writeConcern != null }, From 08247aa8f36390c462a6d464592125dc41fa7de4 Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Thu, 21 Aug 2025 14:40:53 +0200 Subject: [PATCH 07/21] Small fixes --- src/MongoDB.Bson/IO/IBsonReader.cs | 3 ++- src/MongoDB.Bson/Serialization/BsonSerializer.cs | 1 + .../Serialization/IBsonSerializationProvider.cs | 2 +- .../ExplicitEncryptionLibMongoCryptController.cs | 8 ++++---- src/MongoDB.Driver/Core/Bindings/CoreSession.cs | 1 - .../BinaryEncoders/CommandMessageBinaryEncoder.cs | 2 +- .../Serializers/GeoJsonBoundingBoxSerializer.cs | 4 +--- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/MongoDB.Bson/IO/IBsonReader.cs b/src/MongoDB.Bson/IO/IBsonReader.cs index 89f617fe124..9cf7e26f22f 100644 --- a/src/MongoDB.Bson/IO/IBsonReader.cs +++ b/src/MongoDB.Bson/IO/IBsonReader.cs @@ -17,7 +17,8 @@ namespace MongoDB.Bson.IO { - //FP This interface should have the settingg property as well, same way it's done for thr writer + //DOMAIN-API This interface should have the setting property as well probably., same way it's done for thr writer. + //Even if we don't need it now, it could be needed in the future. /// /// Represents a BSON reader. /// diff --git a/src/MongoDB.Bson/Serialization/BsonSerializer.cs b/src/MongoDB.Bson/Serialization/BsonSerializer.cs index c792c9d5839..6fde0c4874c 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializer.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializer.cs @@ -34,6 +34,7 @@ static BsonSerializer() _serializationDomain = new BsonSerializationDomain("MAIN"); } + //QUESTION I think we should have another property here, called StandardSerializationDomain, which would have only the standard serializers and conventions registered. internal static IBsonSerializationDomain DefaultSerializationDomain => _serializationDomain; // public static properties diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs b/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs index 6d1472eccea..73b54c69e3e 100644 --- a/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs +++ b/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs @@ -55,7 +55,7 @@ internal interface IDomainAwareBsonSerializationProvider : IRegistryAwareBsonSer { IBsonSerializationDomain SerializationDomain { get; } - //FP Can't use just GetSerializer because it's already used by the base interface. + //FP Can't use just GetSerializer name because it's already used by the base interface. IBsonSerializer GetSerializerWithDomain(Type type); } } diff --git a/src/MongoDB.Driver.Encryption/ExplicitEncryptionLibMongoCryptController.cs b/src/MongoDB.Driver.Encryption/ExplicitEncryptionLibMongoCryptController.cs index 5a12564dfcd..2bbd0555839 100644 --- a/src/MongoDB.Driver.Encryption/ExplicitEncryptionLibMongoCryptController.cs +++ b/src/MongoDB.Driver.Encryption/ExplicitEncryptionLibMongoCryptController.cs @@ -102,7 +102,7 @@ public Guid CreateDataKey( { var wrappedKeyBytes = ProcessStates(context, _keyVaultNamespace.DatabaseNamespace.DatabaseName, cancellationToken); - var wrappedKeyDocument = BsonSerializer.Deserialize(wrappedKeyBytes); //FP I think this is fine, as it should be default configuration. + var wrappedKeyDocument = BsonSerializer.Deserialize(wrappedKeyBytes); //FP I think this is fine for now, this should use the standard domain. var keyId = UnwrapKeyId(wrappedKeyDocument); _keyVaultCollection.Value.InsertOne(wrappedKeyDocument, cancellationToken: cancellationToken); @@ -131,7 +131,7 @@ public async Task CreateDataKeyAsync( { var wrappedKeyBytes = await ProcessStatesAsync(context, _keyVaultNamespace.DatabaseNamespace.DatabaseName, cancellationToken).ConfigureAwait(false); - var wrappedKeyDocument = BsonSerializer.Deserialize(wrappedKeyBytes); //FP I think this is fine, as it should be default configuration. + var wrappedKeyDocument = BsonSerializer.Deserialize(wrappedKeyBytes); //FP I think this is fine for now, this should use the standard domain. var keyId = UnwrapKeyId(wrappedKeyDocument); await _keyVaultCollection.Value.InsertOneAsync(wrappedKeyDocument, cancellationToken: cancellationToken).ConfigureAwait(false); @@ -555,7 +555,7 @@ private byte[] GetWrappedValueBytes(BsonValue value) private static BsonValue RenderFilter(FilterDefinition filter) { - var registry = BsonSerializer.SerializerRegistry; //FP I think this is fine, as it should be default configuration. + var registry = BsonSerializer.SerializerRegistry; //FP I think this is fine for now, this should use the standard domain. var serializer = registry.GetSerializer(); return filter.Render(new(serializer, registry)); } @@ -572,7 +572,7 @@ private static Guid UnwrapKeyId(BsonDocument wrappedKeyDocument) private static BsonValue UnwrapValue(byte[] encryptedWrappedBytes) { - var bsonDocument = BsonSerializer.Deserialize(encryptedWrappedBytes); //FP I think this is fine, as it should be default configuration. + var bsonDocument = BsonSerializer.Deserialize(encryptedWrappedBytes); //FP I think this is fine for now, this should use the standard domain. return bsonDocument["v"]; } } diff --git a/src/MongoDB.Driver/Core/Bindings/CoreSession.cs b/src/MongoDB.Driver/Core/Bindings/CoreSession.cs index 40235c3715b..f5b62fbf99d 100644 --- a/src/MongoDB.Driver/Core/Bindings/CoreSession.cs +++ b/src/MongoDB.Driver/Core/Bindings/CoreSession.cs @@ -46,7 +46,6 @@ public sealed class CoreSession : ICoreSession, ICoreSessionInternal private BsonTimestamp _snapshotTime; // constructors - //FP This constructor is only used by the tests. internal CoreSession( IClusterInternal cluster, ICoreServerSession serverSession, diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs index 8ae86a8c837..cfaee8b3429 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs @@ -29,7 +29,7 @@ internal sealed class CommandMessageBinaryEncoder : MessageBinaryEncoderBase, IM { private const int EncryptedMaxBatchSize = 2 * 1024 * 1024; // 2 MiB private static readonly ICommandMessageSectionFormatter __type0SectionFormatter = new Type0SectionFormatter(BsonSerializer.DefaultSerializationDomain); - //QUESTION Looking at the spec and our implementation, it seems that type 0 sections always serialize/deserialize RawBsonDocument, so they should use the default domain. Am I missing something? + //QUESTION Looking at the spec and our implementation, it seems that type 0 sections always serialize/deserialize RawBsonDocument, so they should use the standard domain. Am I missing something? // constructors public CommandMessageBinaryEncoder(Stream stream, MessageEncoderSettings encoderSettings) diff --git a/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonBoundingBoxSerializer.cs b/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonBoundingBoxSerializer.cs index 248e816a052..f3f95ab1623 100644 --- a/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonBoundingBoxSerializer.cs +++ b/src/MongoDB.Driver/GeoJsonObjectModel/Serializers/GeoJsonBoundingBoxSerializer.cs @@ -93,14 +93,12 @@ protected override GeoJsonBoundingBox DeserializeValue(BsonDeseria /// The value. protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, GeoJsonBoundingBox value) { - var bsonWriter = context.Writer; - // serialize min and max to a dummy document and then flatten the two arrays and serialize that var document = new BsonDocument(); using (var documentWriter = new BsonDocumentWriter(document)) { var documentContext = - BsonSerializationContext.CreateRoot(documentWriter, BsonSerializer.DefaultSerializationDomain); //FP Is this correct?; + BsonSerializationContext.CreateRoot(documentWriter, context.SerializationDomain); documentWriter.WriteStartDocument(); documentWriter.WriteName("min"); _coordinatesSerializer.Serialize(documentContext, value.Min); From a8ba0884877664aa0e4fea70ac29e3b39904c8f5 Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:56:43 +0200 Subject: [PATCH 08/21] Small fixes --- src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs | 2 +- src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs | 2 +- src/MongoDB.Bson/IO/BsonReaderSettings.cs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs b/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs index 3b1cc9f4a1e..1c510ed71e3 100644 --- a/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs +++ b/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs @@ -136,7 +136,7 @@ protected override BsonReaderSettings CloneImplementation() Encoding = _encoding, FixOldBinarySubTypeOnInput = _fixOldBinarySubTypeOnInput, FixOldDateTimeMaxValueOnInput = _fixOldDateTimeMaxValueOnInput, - MaxDocumentSize = _maxDocumentSize, + MaxDocumentSize = _maxDocumentSize }; return clone; diff --git a/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs b/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs index 5ee1a8c8676..96c8f3168de 100644 --- a/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs +++ b/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs @@ -122,7 +122,7 @@ protected override BsonWriterSettings CloneImplementation() Encoding = _encoding, FixOldBinarySubTypeOnOutput = _fixOldBinarySubTypeOnOutput, MaxDocumentSize = _maxDocumentSize, - MaxSerializationDepth = MaxSerializationDepth, + MaxSerializationDepth = MaxSerializationDepth }; return clone; } diff --git a/src/MongoDB.Bson/IO/BsonReaderSettings.cs b/src/MongoDB.Bson/IO/BsonReaderSettings.cs index 61992ad4c0d..649c02ff59c 100644 --- a/src/MongoDB.Bson/IO/BsonReaderSettings.cs +++ b/src/MongoDB.Bson/IO/BsonReaderSettings.cs @@ -14,7 +14,6 @@ */ using System; -using MongoDB.Bson.Serialization; namespace MongoDB.Bson.IO { From 59c3a47892fbd47a6bd40e231478680c1b4a9a9b Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Tue, 9 Sep 2025 11:09:12 +0200 Subject: [PATCH 09/21] Removed unnecessary comments. --- src/MongoDB.Bson/IO/BsonReader.cs | 3 --- src/MongoDB.Bson/IO/BsonWriter.cs | 4 ---- src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs | 1 - src/MongoDB.Bson/ObjectModel/BsonDocument.cs | 1 - src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs | 1 - src/MongoDB.Bson/ObjectModel/LazyBsonDocument.cs | 1 - src/MongoDB.Bson/ObjectModel/RawBsonArray.cs | 7 ------- src/MongoDB.Bson/ObjectModel/RawBsonDocument.cs | 9 --------- .../Serialization/BsonSerializationContext.cs | 2 +- src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs | 4 +++- src/MongoDB.Bson/Serialization/BsonSerializer.cs | 1 - .../Serialization/IBsonSerializerExtensions.cs | 2 -- .../Authentication/Oidc/AzureOidcCallback.cs | 2 +- src/MongoDB.Driver/Core/Bindings/CoreSession.cs | 1 - .../BinaryEncoders/CommandMessageBinaryEncoder.cs | 2 +- .../Encoders/JsonEncoders/QueryMessageJsonEncoder.cs | 1 - src/MongoDB.Driver/MongoClientSettings.cs | 1 - src/MongoDB.Driver/MongoCollectionSettings.cs | 1 - src/MongoDB.Driver/MongoDatabaseSettings.cs | 2 +- 19 files changed, 7 insertions(+), 39 deletions(-) diff --git a/src/MongoDB.Bson/IO/BsonReader.cs b/src/MongoDB.Bson/IO/BsonReader.cs index c1e119bccb0..d3b4d3bfaa7 100644 --- a/src/MongoDB.Bson/IO/BsonReader.cs +++ b/src/MongoDB.Bson/IO/BsonReader.cs @@ -321,14 +321,12 @@ public virtual IByteBuffer ReadRawBsonArray() // overridden in BsonBinaryReader to read the raw bytes from the stream // for all other streams, deserialize the array and reserialize it using a BsonBinaryWriter to get the raw bytes - //QUESTION Is it correct we only need a default domain here? var deserializationContext = BsonDeserializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain); var array = BsonArraySerializer.Instance.Deserialize(deserializationContext); using (var memoryStream = new MemoryStream()) using (var bsonWriter = new BsonBinaryWriter(memoryStream, BsonBinaryWriterSettings.Defaults)) { - //QUESTION Is it correct we only need a default domain here? var serializationContext = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain); bsonWriter.WriteStartDocument(); var startPosition = memoryStream.Position + 3; // just past BsonType, "x" and null byte @@ -353,7 +351,6 @@ public virtual IByteBuffer ReadRawBsonDocument() // overridden in BsonBinaryReader to read the raw bytes from the stream // for all other streams, deserialize the document and use ToBson to get the raw bytes - //QUESTION Is it correct we only need a default domain here? var deserializationContext = BsonDeserializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain); var document = BsonDocumentSerializer.Instance.Deserialize(deserializationContext); var bytes = document.ToBson(); diff --git a/src/MongoDB.Bson/IO/BsonWriter.cs b/src/MongoDB.Bson/IO/BsonWriter.cs index 1e88a64b400..fd166783f01 100644 --- a/src/MongoDB.Bson/IO/BsonWriter.cs +++ b/src/MongoDB.Bson/IO/BsonWriter.cs @@ -326,14 +326,12 @@ public virtual void WriteRawBsonArray(IByteBuffer slice) stream.Position = 0; using (var reader = new BsonBinaryReader(stream, BsonBinaryReaderSettings.Defaults)) { - //QUESTION Is it correct we only need a default domain here? var deserializationContext = BsonDeserializationContext.CreateRoot(reader, BsonSerializer.DefaultSerializationDomain); reader.ReadStartDocument(); reader.ReadName("x"); var array = BsonArraySerializer.Instance.Deserialize(deserializationContext); reader.ReadEndDocument(); - //QUESTION Is it correct we only need a default domain here? var serializationContext = BsonSerializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain); BsonArraySerializer.Instance.Serialize(serializationContext, array); } @@ -352,11 +350,9 @@ public virtual void WriteRawBsonDocument(IByteBuffer slice) using (var stream = new ByteBufferStream(slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, BsonBinaryReaderSettings.Defaults)) { - //QUESTION Is it correct we only need a default domain here? var deserializationContext = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); var document = BsonDocumentSerializer.Instance.Deserialize(deserializationContext); - //QUESTION Is it correct we only need a default domain here? var serializationContext = BsonSerializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain); BsonDocumentSerializer.Instance.Serialize(serializationContext, document); } diff --git a/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs b/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs index 67ff2a866c0..9cf9b3c2d28 100644 --- a/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs +++ b/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs @@ -60,7 +60,6 @@ public override void WriteEndDocument() Wrapped.PushSettings(_settingsConfigurator); try { - //QUESTION Is it correct we only need a default domain here? var context = BsonSerializationContext.CreateRoot(Wrapped, BsonSerializer.DefaultSerializationDomain); foreach (var element in _elements) { diff --git a/src/MongoDB.Bson/ObjectModel/BsonDocument.cs b/src/MongoDB.Bson/ObjectModel/BsonDocument.cs index e6a0a02d74d..f4ffd777487 100644 --- a/src/MongoDB.Bson/ObjectModel/BsonDocument.cs +++ b/src/MongoDB.Bson/ObjectModel/BsonDocument.cs @@ -331,7 +331,6 @@ public static BsonDocument Parse(string json) { using (var jsonReader = new JsonReader(json)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(jsonReader, BsonSerializer.DefaultSerializationDomain); var document = BsonDocumentSerializer.Instance.Deserialize(context); if (!jsonReader.IsAtEndOfFile()) diff --git a/src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs b/src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs index 98d44f5c5ec..3ca066512e1 100644 --- a/src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs +++ b/src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs @@ -173,7 +173,6 @@ private IEnumerable MaterializeThisLevel() using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); diff --git a/src/MongoDB.Bson/ObjectModel/LazyBsonDocument.cs b/src/MongoDB.Bson/ObjectModel/LazyBsonDocument.cs index 3e2c9d66292..aa0d5526db7 100644 --- a/src/MongoDB.Bson/ObjectModel/LazyBsonDocument.cs +++ b/src/MongoDB.Bson/ObjectModel/LazyBsonDocument.cs @@ -184,7 +184,6 @@ private IEnumerable MaterializeThisLevel() using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); diff --git a/src/MongoDB.Bson/ObjectModel/RawBsonArray.cs b/src/MongoDB.Bson/ObjectModel/RawBsonArray.cs index 2fefa970b51..9778f9d116c 100644 --- a/src/MongoDB.Bson/ObjectModel/RawBsonArray.cs +++ b/src/MongoDB.Bson/ObjectModel/RawBsonArray.cs @@ -128,7 +128,6 @@ public override IEnumerable Values using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); @@ -168,7 +167,6 @@ public override BsonValue this[int index] bsonReader.SkipName(); if (i == index) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); return DeserializeBsonValue(context); } @@ -316,7 +314,6 @@ public override bool Contains(BsonValue value) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); @@ -345,7 +342,6 @@ public override void CopyTo(BsonValue[] array, int arrayIndex) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); @@ -387,7 +383,6 @@ public override IEnumerator GetEnumerator() using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); @@ -434,7 +429,6 @@ public override int IndexOf(BsonValue value, int index, int count) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); @@ -495,7 +489,6 @@ public BsonArray Materialize(BsonBinaryReaderSettings binaryReaderSettings) using (var stream = new MemoryStream(bytes)) using (var reader = new BsonBinaryReader(stream, binaryReaderSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(reader, BsonSerializer.DefaultSerializationDomain); var materializedDocument = BsonDocumentSerializer.Instance.Deserialize(context); return materializedDocument["array"].AsBsonArray; diff --git a/src/MongoDB.Bson/ObjectModel/RawBsonDocument.cs b/src/MongoDB.Bson/ObjectModel/RawBsonDocument.cs index b58265261f2..56cca2d0cdf 100644 --- a/src/MongoDB.Bson/ObjectModel/RawBsonDocument.cs +++ b/src/MongoDB.Bson/ObjectModel/RawBsonDocument.cs @@ -102,7 +102,6 @@ public override IEnumerable Elements using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); @@ -165,7 +164,6 @@ public override IEnumerable Values using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); @@ -354,7 +352,6 @@ public override bool ContainsValue(BsonValue value) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); @@ -411,7 +408,6 @@ public override BsonElement GetElement(int index) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); @@ -467,7 +463,6 @@ public override IEnumerator GetEnumerator() using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); @@ -499,7 +494,6 @@ public override BsonValue GetValue(int index) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); @@ -582,7 +576,6 @@ public BsonDocument Materialize(BsonBinaryReaderSettings binaryReaderSettings) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var reader = new BsonBinaryReader(stream, binaryReaderSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(reader, BsonSerializer.DefaultSerializationDomain); return BsonDocumentSerializer.Instance.Deserialize(context); } @@ -706,7 +699,6 @@ public override bool TryGetElement(string name, out BsonElement element) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); @@ -742,7 +734,6 @@ public override bool TryGetValue(string name, out BsonValue value) using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs b/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs index 8c046d91911..42225737ce6 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs @@ -143,7 +143,7 @@ internal Builder(BsonSerializationContext other, IBsonWriter writer, IBsonSerial _isDynamicType = other._isDynamicType; } - /* QUESTION I removed the part where we set _isDynamicType from the BsonDefaults, and delay it until we have a serialization domain (when we build the SerializationContext). + /* FP I removed the part where we set _isDynamicType from the BsonDefaults, and delay it until we have a serialization domain (when we build the SerializationContext). * This is technically changing the public behaviour, but it's in a builder, I do not thing it will affect anyone. Same done for the deserialization context. */ } diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs b/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs index 513c74338bb..a59ab2fb0c0 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs @@ -155,7 +155,7 @@ public BsonValue SerializeValue(object value) var tempDocument = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(tempDocument)) { - //QUESTION Is it correct we only need a standard domain here? + //QUESTION Is it correct we only need a default domain here? var context = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("value"); @@ -165,6 +165,7 @@ public BsonValue SerializeValue(object value) } } + //DOMAIN-API This method should be probably removed, it's never used. /// /// Serializes the values. /// @@ -191,6 +192,7 @@ public BsonArray SerializeValues(IEnumerable values) } } + //DOMAIN-API This method should be probably removed, it's never used. /// /// Creates a new BsonSerializationInfo object using the elementName provided and copying all other attributes. /// diff --git a/src/MongoDB.Bson/Serialization/BsonSerializer.cs b/src/MongoDB.Bson/Serialization/BsonSerializer.cs index 6fde0c4874c..c792c9d5839 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializer.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializer.cs @@ -34,7 +34,6 @@ static BsonSerializer() _serializationDomain = new BsonSerializationDomain("MAIN"); } - //QUESTION I think we should have another property here, called StandardSerializationDomain, which would have only the standard serializers and conventions registered. internal static IBsonSerializationDomain DefaultSerializationDomain => _serializationDomain; // public static properties diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs b/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs index aa11d7bef91..b0fc03e3800 100644 --- a/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs +++ b/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs @@ -104,7 +104,6 @@ public static BsonValue ToBsonValue(this IBsonSerializer serializer, object valu var document = new BsonDocument(); using (var writer = new BsonDocumentWriter(document)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonSerializationContext.CreateRoot(writer, BsonSerializer.DefaultSerializationDomain); writer.WriteStartDocument(); writer.WriteName("x"); @@ -126,7 +125,6 @@ public static BsonValue ToBsonValue(this IBsonSerializer seriali var document = new BsonDocument(); using (var writer = new BsonDocumentWriter(document)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonSerializationContext.CreateRoot(writer, BsonSerializer.DefaultSerializationDomain); writer.WriteStartDocument(); writer.WriteName("x"); diff --git a/src/MongoDB.Driver/Authentication/Oidc/AzureOidcCallback.cs b/src/MongoDB.Driver/Authentication/Oidc/AzureOidcCallback.cs index ab4c8a11571..f27333ae583 100644 --- a/src/MongoDB.Driver/Authentication/Oidc/AzureOidcCallback.cs +++ b/src/MongoDB.Driver/Authentication/Oidc/AzureOidcCallback.cs @@ -46,7 +46,7 @@ protected override OidcAccessToken ProcessHttpResponse(Stream responseStream) using var responseReader = new StreamReader(responseStream); using var jsonReader = new JsonReader(responseReader); - var context = BsonDeserializationContext.CreateRoot(jsonReader, BsonSerializer.DefaultSerializationDomain); //QUESTION Is it ok to use the default domain here? + var context = BsonDeserializationContext.CreateRoot(jsonReader, BsonSerializer.DefaultSerializationDomain); var document = BsonDocumentSerializer.Instance.Deserialize(context); var accessToken = document.GetValue("access_token"); diff --git a/src/MongoDB.Driver/Core/Bindings/CoreSession.cs b/src/MongoDB.Driver/Core/Bindings/CoreSession.cs index f5b62fbf99d..c803063d954 100644 --- a/src/MongoDB.Driver/Core/Bindings/CoreSession.cs +++ b/src/MongoDB.Driver/Core/Bindings/CoreSession.cs @@ -447,7 +447,6 @@ public void WasUsed() // private methods private IReadOperation CreateAbortTransactionOperation(OperationContext operationContext) { - //QUESTION Is it correct we only need a default domain here? return new AbortTransactionOperation(_currentTransaction.RecoveryToken, GetTransactionWriteConcern(operationContext)); } diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs index cfaee8b3429..8ae86a8c837 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs @@ -29,7 +29,7 @@ internal sealed class CommandMessageBinaryEncoder : MessageBinaryEncoderBase, IM { private const int EncryptedMaxBatchSize = 2 * 1024 * 1024; // 2 MiB private static readonly ICommandMessageSectionFormatter __type0SectionFormatter = new Type0SectionFormatter(BsonSerializer.DefaultSerializationDomain); - //QUESTION Looking at the spec and our implementation, it seems that type 0 sections always serialize/deserialize RawBsonDocument, so they should use the standard domain. Am I missing something? + //QUESTION Looking at the spec and our implementation, it seems that type 0 sections always serialize/deserialize RawBsonDocument, so they should use the default domain. Am I missing something? // constructors public CommandMessageBinaryEncoder(Stream stream, MessageEncoderSettings encoderSettings) diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/QueryMessageJsonEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/QueryMessageJsonEncoder.cs index 80fc3eaba56..9ff7c4b97a6 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/QueryMessageJsonEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/QueryMessageJsonEncoder.cs @@ -32,7 +32,6 @@ public QueryMessageJsonEncoder(TextReader textReader, TextWriter textWriter, Mes : base(textReader, textWriter, encoderSettings) { _serializationDomain = encoderSettings?.GetOrDefault(MessageEncoderSettingsName.SerializationDomain, null) ?? BsonSerializer.DefaultSerializationDomain; - //QUESTION: Should we use the default serialization domain here? I think it's appropriate. } // methods diff --git a/src/MongoDB.Driver/MongoClientSettings.cs b/src/MongoDB.Driver/MongoClientSettings.cs index de5429f7958..49e264282a5 100644 --- a/src/MongoDB.Driver/MongoClientSettings.cs +++ b/src/MongoDB.Driver/MongoClientSettings.cs @@ -477,7 +477,6 @@ public ReadPreference ReadPreference IBsonSerializationDomain IInheritableMongoClientSettings.SerializationDomain { - //QUESTION Is this reasonable? get => _serializationDomain ?? BsonSerializer.DefaultSerializationDomain; set { diff --git a/src/MongoDB.Driver/MongoCollectionSettings.cs b/src/MongoDB.Driver/MongoCollectionSettings.cs index 1ed42c2ae9a..7e2bba031f1 100644 --- a/src/MongoDB.Driver/MongoCollectionSettings.cs +++ b/src/MongoDB.Driver/MongoCollectionSettings.cs @@ -124,7 +124,6 @@ public ReadPreference ReadPreference /// internal IBsonSerializationDomain SerializationDomain { - //QUESTION Is this reasonable? In normal uses cases the domain would be setup by ApplyDefaultValues, but for testing it would not work. get => _serializationDomain.Value ?? BsonSerializer.DefaultSerializationDomain; set { diff --git a/src/MongoDB.Driver/MongoDatabaseSettings.cs b/src/MongoDB.Driver/MongoDatabaseSettings.cs index 779b2ead274..4fa0f0fd35e 100644 --- a/src/MongoDB.Driver/MongoDatabaseSettings.cs +++ b/src/MongoDB.Driver/MongoDatabaseSettings.cs @@ -109,7 +109,7 @@ public ReadPreference ReadPreference /// internal IBsonSerializationDomain SerializationDomain { - get => _serializationDomain.Value ?? BsonSerializer.DefaultSerializationDomain; //QUESTION Is this reasonable? + get => _serializationDomain.Value ?? BsonSerializer.DefaultSerializationDomain; set { if (_isFrozen) { throw new InvalidOperationException("MongoCollectionSettings is frozen."); } From 27671aed9958f9bcfe271490e763a858e200086c Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Thu, 11 Sep 2025 10:57:59 +0200 Subject: [PATCH 10/21] Fixed BsonDocumentWrapper and added comments --- .../ObjectModel/BsonDocumentWrapper.cs | 27 ++++++++++--------- .../Serialization/BsonSerializationInfo.cs | 17 ++++++++++-- src/MongoDB.Driver/Command.cs | 3 ++- .../CommandUsingQueryMessageWireProtocol.cs | 6 ++--- .../JsonEncoders/ReplyMessageJsonEncoder.cs | 2 +- src/MongoDB.Driver/FilterDefinition.cs | 2 +- src/MongoDB.Driver/MongoCollectionImpl.cs | 6 ++--- src/MongoDB.Driver/ProjectionDefinition.cs | 4 +-- src/MongoDB.Driver/SortDefinition.cs | 2 +- src/MongoDB.Driver/UpdateDefinition.cs | 2 +- 10 files changed, 44 insertions(+), 27 deletions(-) diff --git a/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs b/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs index 8965a4d0f8a..aa21b5f0551 100644 --- a/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs +++ b/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs @@ -37,6 +37,7 @@ public class BsonDocumentWrapper : MaterializedOnDemandBsonDocument // private fields private readonly object _wrapped; private readonly IBsonSerializer _serializer; + private readonly IBsonSerializationDomain _serializationDomain; // constructors /// @@ -44,7 +45,7 @@ public class BsonDocumentWrapper : MaterializedOnDemandBsonDocument /// /// The value. public BsonDocumentWrapper(object value) - : this(value, UndiscriminatedActualTypeSerializer.Instance) + : this(value, UndiscriminatedActualTypeSerializer.Instance, BsonSerializer.DefaultSerializationDomain) { } @@ -54,14 +55,15 @@ public BsonDocumentWrapper(object value) /// The value. /// The serializer. public BsonDocumentWrapper(object value, IBsonSerializer serializer) + : this(value, serializer, BsonSerializer.DefaultSerializationDomain) { - if (serializer == null) - { - throw new ArgumentNullException("serializer"); - } + } + internal BsonDocumentWrapper(object value, IBsonSerializer serializer, IBsonSerializationDomain serializationDomain) + { + _serializer = serializer ?? throw new ArgumentNullException(nameof(serializer)); + _serializationDomain = serializationDomain; _wrapped = value; - _serializer = serializer; } // public properties @@ -84,6 +86,7 @@ public object Wrapped get { return _wrapped; } } + // DOMAIN-API All the various Create methods are used only in testing, the version without the domain should be removed. // public static methods /// /// Creates a new instance of the BsonDocumentWrapper class. @@ -111,7 +114,7 @@ public static BsonDocumentWrapper Create(Type nominalType, object value) => internal static BsonDocumentWrapper Create(Type nominalType, object value, IBsonSerializationDomain domain) { var serializer = domain.LookupSerializer(nominalType); - return new BsonDocumentWrapper(value, serializer); + return new BsonDocumentWrapper(value, serializer, domain); } /// @@ -139,7 +142,7 @@ internal static IEnumerable CreateMultiple(IE } var serializer = domain.LookupSerializer(typeof(TNominalType)); - return values.Select(v => new BsonDocumentWrapper(v, serializer)); + return values.Select(v => new BsonDocumentWrapper(v, serializer, domain)); } /// @@ -171,7 +174,7 @@ internal static IEnumerable CreateMultiple(Type nominalType } var serializer = domain.LookupSerializer(nominalType); - return values.Cast().Select(v => new BsonDocumentWrapper(v, serializer)); + return values.Cast().Select(v => new BsonDocumentWrapper(v, serializer, domain)); } // public methods @@ -191,7 +194,8 @@ public override BsonValue Clone() { return new BsonDocumentWrapper( _wrapped, - _serializer); + _serializer, + _serializationDomain); } } @@ -206,8 +210,7 @@ protected override IEnumerable Materialize() var writerSettings = BsonDocumentWriterSettings.Defaults; using (var bsonWriter = new BsonDocumentWriter(bsonDocument, writerSettings)) { - //QUESTION Is it correct we only need a default domain here? - var context = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain); + var context = BsonSerializationContext.CreateRoot(bsonWriter, _serializationDomain); _serializer.Serialize(context, _wrapped); } diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs b/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs index a59ab2fb0c0..0e4bbd35e70 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs @@ -108,6 +108,20 @@ public Type NominalType get { return _nominalType; } } + /* DOMAIN-API Both DeserializeValue and SerializeValue should be changed to accept a domain as input. + * DeserializeValue is only used by BsonDocumentBackedClass + * SerializeValue is used by BsonDocumentBackedClass and also by GridFS buckets to serialize the Id field. + * + * BsonDocumentBackedClass is the base for a few classes in the driver (GridFSFileInfo, ChangeStreamPreAndPostImagesOptions, etc). + * For those classes we can use the default domain, as no custom serialization is expected. + * + * GridFS buckets on the other hand allow the user to specify a custom Id serializer, which may require a custom domain. + * But looking at the docs it seems that ObjectId is the preferred type for the Id field, and I suppose there won't need to be custom serialization. + * + * Thus for now I think it's acceptable to use the default domain in SerializeValue too, but we should revisit this decision at a later time. + */ + + //DOMAIN-API This method should be changed to accept a domain as input. /// /// Deserializes the value. /// @@ -118,7 +132,6 @@ public object DeserializeValue(BsonValue value) var tempDocument = new BsonDocument("value", value); using (var reader = new BsonDocumentReader(tempDocument)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonDeserializationContext.CreateRoot(reader, BsonSerializer.DefaultSerializationDomain); reader.ReadStartDocument(); reader.ReadName("value"); @@ -145,6 +158,7 @@ obj is BsonSerializationInfo other && /// public override int GetHashCode() => 0; + //DOMAIN-API This method should be changed to accept a domain as input. /// /// Serializes the value. /// @@ -155,7 +169,6 @@ public BsonValue SerializeValue(object value) var tempDocument = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(tempDocument)) { - //QUESTION Is it correct we only need a default domain here? var context = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("value"); diff --git a/src/MongoDB.Driver/Command.cs b/src/MongoDB.Driver/Command.cs index 4f7248ff1ea..7c20d7f0d76 100644 --- a/src/MongoDB.Driver/Command.cs +++ b/src/MongoDB.Driver/Command.cs @@ -221,12 +221,13 @@ public IBsonSerializer ResultSerializer get { return _resultSerializer; } } + // DOMAIN-API: We need to pass also the domain here (or only the domain) /// public override RenderedCommand Render(IBsonSerializerRegistry serializerRegistry) { var serializer = serializerRegistry.GetSerializer(_obj.GetType()); return new RenderedCommand( - new BsonDocumentWrapper(_obj, serializer), + new BsonDocumentWrapper(_obj, serializer, BsonSerializer.DefaultSerializationDomain), _resultSerializer ?? serializerRegistry.GetSerializer()); } } diff --git a/src/MongoDB.Driver/Core/WireProtocol/CommandUsingQueryMessageWireProtocol.cs b/src/MongoDB.Driver/Core/WireProtocol/CommandUsingQueryMessageWireProtocol.cs index feaa20cee41..1e908fe8a7c 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/CommandUsingQueryMessageWireProtocol.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/CommandUsingQueryMessageWireProtocol.cs @@ -185,7 +185,7 @@ private BsonDocument CombineCommandWithPayloads(ConnectionDescription connection } var payloadAppendingSerializer = new ElementAppendingSerializer(BsonDocumentSerializer.Instance, extraElements); - return new BsonDocumentWrapper(_command, payloadAppendingSerializer); + return new BsonDocumentWrapper(_command, payloadAppendingSerializer, _serializationDomain); } private BsonArray CreatePayloadArray(Type1CommandMessageSection payload, ConnectionDescription connectionDescription) @@ -200,7 +200,7 @@ private BsonArray CreatePayloadArray(Type1CommandMessageSection payload, Connect payloadSerializer = CreateFixedCountPayloadSerializer(payload); } - var documents = new BsonDocumentWrapper(payload.Documents, payloadSerializer); + var documents = new BsonDocumentWrapper(payload.Documents, payloadSerializer, _serializationDomain); return new BsonArray { documents }; } @@ -377,7 +377,7 @@ private BsonDocument WrapCommandForQueryMessage(BsonDocument command, Connection extraElements.Add(clusterTime); } var appendExtraElementsSerializer = new ElementAppendingSerializer(BsonDocumentSerializer.Instance, extraElements); - var commandWithExtraElements = new BsonDocumentWrapper(command, appendExtraElementsSerializer); + var commandWithExtraElements = new BsonDocumentWrapper(command, appendExtraElementsSerializer, _serializationDomain); var serverType = connectionDescription != null ? connectionDescription.HelloResult.ServerType : ServerType.Unknown; var readPreferenceDocument = QueryHelper.CreateReadPreferenceDocument(serverType, _readPreference, out secondaryOk); diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/ReplyMessageJsonEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/ReplyMessageJsonEncoder.cs index 87bed75b0bb..834e85f6c87 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/ReplyMessageJsonEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/ReplyMessageJsonEncoder.cs @@ -104,7 +104,7 @@ public void WriteMessage(ReplyMessage message) BsonArray documents = null; if (!message.QueryFailure) { - var wrappers = message.Documents.Select(d => new BsonDocumentWrapper(d, _serializer)); + var wrappers = message.Documents.Select(d => new BsonDocumentWrapper(d, _serializer, _serializationDomain)); documents = new BsonArray(wrappers); } diff --git a/src/MongoDB.Driver/FilterDefinition.cs b/src/MongoDB.Driver/FilterDefinition.cs index 12e03969c72..8ea1f885fc2 100644 --- a/src/MongoDB.Driver/FilterDefinition.cs +++ b/src/MongoDB.Driver/FilterDefinition.cs @@ -275,7 +275,7 @@ public object Object public override BsonDocument Render(RenderArgs args) { var serializer = args.SerializerRegistry.GetSerializer(_obj.GetType()); - return new BsonDocumentWrapper(_obj, serializer); + return new BsonDocumentWrapper(_obj, serializer, args.SerializationDomain); } } } diff --git a/src/MongoDB.Driver/MongoCollectionImpl.cs b/src/MongoDB.Driver/MongoCollectionImpl.cs index 700c8911297..d16684439d3 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -679,7 +679,7 @@ private WriteRequest ConvertWriteModelToWriteRequest(WriteModel model { _documentSerializer.SetDocumentIdIfMissing(this, insertOneModel.Document, renderArgs.SerializationDomain); } - return new InsertRequest(new BsonDocumentWrapper(insertOneModel.Document, _documentSerializer)) + return new InsertRequest(new BsonDocumentWrapper(insertOneModel.Document, _documentSerializer, renderArgs.SerializationDomain)) { CorrelationId = index }; @@ -706,7 +706,7 @@ private WriteRequest ConvertWriteModelToWriteRequest(WriteModel model return new UpdateRequest( UpdateType.Replacement, replaceOneModel.Filter.Render(renderArgs), - new BsonDocumentWrapper(replaceOneModel.Replacement, _documentSerializer)) + new BsonDocumentWrapper(replaceOneModel.Replacement, _documentSerializer, renderArgs.SerializationDomain)) { Collation = replaceOneModel.Collation, CorrelationId = index, @@ -1010,7 +1010,7 @@ private FindOneAndReplaceOperation CreateFindOneAndReplaceOperation return new FindOneAndReplaceOperation( _collectionNamespace, filter.Render(renderArgs), - new BsonDocumentWrapper(replacement, _documentSerializer), + new BsonDocumentWrapper(replacement, _documentSerializer, renderArgs.SerializationDomain), new FindAndModifyValueDeserializer(renderedProjection.ProjectionSerializer), _messageEncoderSettings, _settings.SerializationDomain) diff --git a/src/MongoDB.Driver/ProjectionDefinition.cs b/src/MongoDB.Driver/ProjectionDefinition.cs index 99c58af8107..1936c46c8c3 100644 --- a/src/MongoDB.Driver/ProjectionDefinition.cs +++ b/src/MongoDB.Driver/ProjectionDefinition.cs @@ -393,7 +393,7 @@ public object Object public override BsonDocument Render(RenderArgs args) { var serializer = args.SerializerRegistry.GetSerializer(_obj.GetType()); - return new BsonDocumentWrapper(_obj, serializer); + return new BsonDocumentWrapper(_obj, serializer, args.SerializationDomain); } } @@ -439,7 +439,7 @@ public override RenderedProjectionDefinition Render(RenderArgs( - new BsonDocumentWrapper(_obj, serializer), + new BsonDocumentWrapper(_obj, serializer, args.SerializationDomain), _projectionSerializer ?? args.GetSerializer()); } } diff --git a/src/MongoDB.Driver/SortDefinition.cs b/src/MongoDB.Driver/SortDefinition.cs index a7d6a8bfaed..0de0efd6bab 100644 --- a/src/MongoDB.Driver/SortDefinition.cs +++ b/src/MongoDB.Driver/SortDefinition.cs @@ -178,7 +178,7 @@ public object Object public override BsonDocument Render(RenderArgs args) { var serializer = args.SerializerRegistry.GetSerializer(_obj.GetType()); - return new BsonDocumentWrapper(_obj, serializer); + return new BsonDocumentWrapper(_obj, serializer, args.SerializationDomain); } } } diff --git a/src/MongoDB.Driver/UpdateDefinition.cs b/src/MongoDB.Driver/UpdateDefinition.cs index 45fbe905edf..26414195148 100644 --- a/src/MongoDB.Driver/UpdateDefinition.cs +++ b/src/MongoDB.Driver/UpdateDefinition.cs @@ -241,7 +241,7 @@ public object Object public override BsonValue Render(RenderArgs args) { var serializer = args.SerializerRegistry.GetSerializer(_obj.GetType()); - return new BsonDocumentWrapper(_obj, serializer); + return new BsonDocumentWrapper(_obj, serializer, args.SerializationDomain); } } } From f8915ab6ed811707dfce69c872493eaf8146a031 Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Thu, 11 Sep 2025 10:59:09 +0200 Subject: [PATCH 11/21] Removed docs and make some methods private --- .../ObjectModel/BsonDocumentWrapper.cs | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs b/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs index aa21b5f0551..1d5dfd3f9a6 100644 --- a/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs +++ b/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs @@ -86,7 +86,7 @@ public object Wrapped get { return _wrapped; } } - // DOMAIN-API All the various Create methods are used only in testing, the version without the domain should be removed. + // DOMAIN-API All the various Create methods are used only in testing, the versions without the domain should be removed. // public static methods /// /// Creates a new instance of the BsonDocumentWrapper class. @@ -111,7 +111,7 @@ internal static BsonDocumentWrapper Create(TNominalType value, IBs public static BsonDocumentWrapper Create(Type nominalType, object value) => Create(nominalType, value, BsonSerializer.DefaultSerializationDomain); - internal static BsonDocumentWrapper Create(Type nominalType, object value, IBsonSerializationDomain domain) + private static BsonDocumentWrapper Create(Type nominalType, object value, IBsonSerializationDomain domain) { var serializer = domain.LookupSerializer(nominalType); return new BsonDocumentWrapper(value, serializer, domain); @@ -126,15 +126,7 @@ internal static BsonDocumentWrapper Create(Type nominalType, object value, IBson public static IEnumerable CreateMultiple(IEnumerable values) => CreateMultiple(values, BsonSerializer.DefaultSerializationDomain); - /// - /// //TODO - /// - /// - /// - /// - /// - /// - internal static IEnumerable CreateMultiple(IEnumerable values, IBsonSerializationDomain domain) + private static IEnumerable CreateMultiple(IEnumerable values, IBsonSerializationDomain domain) { if (values == null) { @@ -154,15 +146,7 @@ internal static IEnumerable CreateMultiple(IE public static IEnumerable CreateMultiple(Type nominalType, IEnumerable values) => CreateMultiple(nominalType, values, BsonSerializer.DefaultSerializationDomain); - /// - /// //TODO - /// - /// - /// - /// - /// - /// - internal static IEnumerable CreateMultiple(Type nominalType, IEnumerable values, IBsonSerializationDomain domain) + private static IEnumerable CreateMultiple(Type nominalType, IEnumerable values, IBsonSerializationDomain domain) { if (nominalType == null) { From 7f454849555a8e4d1e4ccacccf4c697315ab1a2c Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Thu, 11 Sep 2025 11:09:52 +0200 Subject: [PATCH 12/21] Small corrections --- src/MongoDB.Bson/BsonExtensionMethods.cs | 30 ++++++++++-------------- 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/MongoDB.Bson/BsonExtensionMethods.cs b/src/MongoDB.Bson/BsonExtensionMethods.cs index bd52c52e832..2702533b613 100644 --- a/src/MongoDB.Bson/BsonExtensionMethods.cs +++ b/src/MongoDB.Bson/BsonExtensionMethods.cs @@ -25,7 +25,7 @@ namespace MongoDB.Bson /// public static class BsonExtensionMethods { - //DOMAIN-API We should remove this and use the version with the domain. + //DOMAIN-API We should remove all the methods that do not take a serialization domain. //QUESTION: Do we want to do something now about this...? It's used also internally, but it seems in most cases it's used for "default serialization", so it should be ok. /// /// Serializes an object to a BSON byte array. @@ -43,21 +43,16 @@ public static byte[] ToBson( IBsonSerializer serializer = null, BsonBinaryWriterSettings writerSettings = null, Action configurator = null, - BsonSerializationArgs args = default(BsonSerializationArgs), - int estimatedBsonSize = 0) - { - args.SetOrValidateNominalType(typeof(TNominalType), ""); - - return ToBson(obj, typeof(TNominalType), writerSettings, serializer, configurator, args, estimatedBsonSize); - } + BsonSerializationArgs args = default, + int estimatedBsonSize = 0) => ToBson(obj, BsonSerializer.DefaultSerializationDomain, serializer, writerSettings, configurator, args, estimatedBsonSize); - internal static byte[] ToBson( + private static byte[] ToBson( this TNominalType obj, IBsonSerializationDomain serializationDomain, IBsonSerializer serializer = null, BsonBinaryWriterSettings writerSettings = null, Action configurator = null, - BsonSerializationArgs args = default(BsonSerializationArgs), + BsonSerializationArgs args = default, int estimatedBsonSize = 0) { args.SetOrValidateNominalType(typeof(TNominalType), ""); @@ -65,7 +60,6 @@ internal static byte[] ToBson( return ToBson(obj, typeof(TNominalType), serializationDomain, writerSettings, serializer, configurator, args, estimatedBsonSize); } - //DOMAIN-API We should remove this and use the version with the domain. /// /// Serializes an object to a BSON byte array. /// @@ -89,14 +83,14 @@ public static byte[] ToBson( int estimatedBsonSize = 0) => ToBson(obj, nominalType, BsonSerializer.DefaultSerializationDomain, writerSettings, serializer, configurator, args, estimatedBsonSize); - internal static byte[] ToBson( + private static byte[] ToBson( this object obj, Type nominalType, IBsonSerializationDomain serializationDomain, BsonBinaryWriterSettings writerSettings = null, IBsonSerializer serializer = null, Action configurator = null, - BsonSerializationArgs args = default(BsonSerializationArgs), + BsonSerializationArgs args = default, int estimatedBsonSize = 0) { if (estimatedBsonSize < 0) @@ -144,7 +138,7 @@ public static BsonDocument ToBsonDocument( this TNominalType obj, IBsonSerializer serializer = null, Action configurator = null, - BsonSerializationArgs args = default(BsonSerializationArgs)) + BsonSerializationArgs args = default) { args.SetOrValidateNominalType(typeof(TNominalType), ""); return ToBsonDocument(obj, typeof(TNominalType), serializer, configurator, args); @@ -169,7 +163,7 @@ public static BsonDocument ToBsonDocument( BsonSerializationArgs args = default) => ToBsonDocument(obj, nominalType, BsonSerializer.DefaultSerializationDomain, serializer, configurator, args); - internal static BsonDocument ToBsonDocument( + private static BsonDocument ToBsonDocument( this object obj, Type nominalType, IBsonSerializationDomain serializationDomain, @@ -237,7 +231,7 @@ public static string ToJson( JsonWriterSettings writerSettings = null, IBsonSerializer serializer = null, Action configurator = null, - BsonSerializationArgs args = default(BsonSerializationArgs)) + BsonSerializationArgs args = default) { args.SetOrValidateNominalType(typeof(TNominalType), ""); return ToJson(obj, typeof(TNominalType), writerSettings, serializer, configurator, args); @@ -266,14 +260,14 @@ public static string ToJson( BsonSerializationArgs args = default) => ToJson(obj, nominalType, BsonSerializer.DefaultSerializationDomain, writerSettings, serializer, configurator, args); - internal static string ToJson( + private static string ToJson( this object obj, Type nominalType, IBsonSerializationDomain domain, JsonWriterSettings writerSettings = null, IBsonSerializer serializer = null, Action configurator = null, - BsonSerializationArgs args = default(BsonSerializationArgs)) + BsonSerializationArgs args = default) { if (nominalType == null) { From acd8a640d4dd66d31050e19551788425e2a8aa3b Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Thu, 11 Sep 2025 11:27:44 +0200 Subject: [PATCH 13/21] Removed other comments. --- .../Serialization/BsonSerializationInfo.cs | 1 - .../Serializers/DictionarySerializerBase.cs | 28 ++++++++----------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs b/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs index 0e4bbd35e70..31d2e983539 100644 --- a/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs +++ b/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs @@ -189,7 +189,6 @@ public BsonArray SerializeValues(IEnumerable values) var tempDocument = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(tempDocument)) { - //QUESTION Is it correct we only need a standard domain here? var context = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("values"); diff --git a/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs b/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs index da4be08eae8..1fd027bf286 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs @@ -262,7 +262,7 @@ private TDictionary DeserializeDocumentRepresentation(BsonDeserializationContext bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) { - var key = DeserializeKeyString(bsonReader.ReadName()); + var key = DeserializeKeyString(bsonReader.ReadName(), context.SerializationDomain); var value = _valueSerializer.Deserialize(context); dictionary.Add(key, value); } @@ -270,13 +270,12 @@ private TDictionary DeserializeDocumentRepresentation(BsonDeserializationContext return dictionary; } - private object DeserializeKeyString(string keyString) + private object DeserializeKeyString(string keyString, IBsonSerializationDomain serializationDomain) { var keyDocument = new BsonDocument("k", keyString); using (var keyReader = new BsonDocumentReader(keyDocument)) { - //QUESTION Is it correct we only need a default domain here? - var context = BsonDeserializationContext.CreateRoot(keyReader, BsonSerializer.DefaultSerializationDomain); + var context = BsonDeserializationContext.CreateRoot(keyReader, serializationDomain); keyReader.ReadStartDocument(); keyReader.ReadName("k"); var key = _keySerializer.Deserialize(context); @@ -321,19 +320,18 @@ private void SerializeDocumentRepresentation(BsonSerializationContext context, T bsonWriter.WriteStartDocument(); foreach (DictionaryEntry dictionaryEntry in value) { - bsonWriter.WriteName(SerializeKeyString(dictionaryEntry.Key)); + bsonWriter.WriteName(SerializeKeyString(dictionaryEntry.Key, context.SerializationDomain)); _valueSerializer.Serialize(context, dictionaryEntry.Value); } bsonWriter.WriteEndDocument(); } - private string SerializeKeyString(object key) + private string SerializeKeyString(object key, IBsonSerializationDomain serializationDomain) { var keyDocument = new BsonDocument(); using (var keyWriter = new BsonDocumentWriter(keyDocument)) { - //QUESTION Is it correct we only need a default domain here? - var context = BsonSerializationContext.CreateRoot(keyWriter, BsonSerializer.DefaultSerializationDomain); + var context = BsonSerializationContext.CreateRoot(keyWriter, serializationDomain); keyWriter.WriteStartDocument(); keyWriter.WriteName("k"); _keySerializer.Serialize(context, key); @@ -669,7 +667,7 @@ private TDictionary DeserializeDocumentRepresentation(BsonDeserializationContext bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) { - var key = DeserializeKeyString(bsonReader.ReadName()); + var key = DeserializeKeyString(bsonReader.ReadName(), context.SerializationDomain); var value = _lazyValueSerializer.Value.Deserialize(context); accumulator.Add(new KeyValuePair(key, value)); } @@ -678,13 +676,12 @@ private TDictionary DeserializeDocumentRepresentation(BsonDeserializationContext return FinalizeAccumulator(accumulator); } - private TKey DeserializeKeyString(string keyString) + private TKey DeserializeKeyString(string keyString, IBsonSerializationDomain serializationDomain) { var keyDocument = new BsonDocument("k", keyString); using (var keyReader = new BsonDocumentReader(keyDocument)) { - //QUESTION Is it correct we only need a default domain here? - var context = BsonDeserializationContext.CreateRoot(keyReader, BsonSerializer.DefaultSerializationDomain); + var context = BsonDeserializationContext.CreateRoot(keyReader, serializationDomain); keyReader.ReadStartDocument(); keyReader.ReadName("k"); var key = _lazyKeySerializer.Value.Deserialize(context); @@ -729,19 +726,18 @@ private void SerializeDocumentRepresentation(BsonSerializationContext context, T bsonWriter.WriteStartDocument(); foreach (var keyValuePair in value) { - bsonWriter.WriteName(SerializeKeyString(keyValuePair.Key)); + bsonWriter.WriteName(SerializeKeyString(keyValuePair.Key, context.SerializationDomain)); _lazyValueSerializer.Value.Serialize(context, keyValuePair.Value); } bsonWriter.WriteEndDocument(); } - private string SerializeKeyString(TKey key) + private string SerializeKeyString(TKey key, IBsonSerializationDomain serializationDomain) { var keyDocument = new BsonDocument(); using (var keyWriter = new BsonDocumentWriter(keyDocument)) { - //QUESTION Is it correct we only need a default domain here? - var context = BsonSerializationContext.CreateRoot(keyWriter, BsonSerializer.DefaultSerializationDomain); + var context = BsonSerializationContext.CreateRoot(keyWriter, serializationDomain); keyWriter.WriteStartDocument(); keyWriter.WriteName("k"); _lazyKeySerializer.Value.Serialize(context, key); From 681f4614df8a5a492038bf41a3e94dfad2344ab3 Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Mon, 15 Sep 2025 10:07:22 +0200 Subject: [PATCH 14/21] Small corrections --- src/MongoDB.Bson/BsonExtensionMethods.cs | 2 +- src/MongoDB.Driver/Authentication/SaslAuthenticator.cs | 2 +- src/MongoDB.Driver/Core/Bindings/CoreSession.cs | 2 +- .../Core/Connections/ConnectionInitializer.cs | 2 +- src/MongoDB.Driver/Core/Connections/HelloHelper.cs | 2 +- .../Core/WireProtocol/Messages/CommandMessageSection.cs | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/MongoDB.Bson/BsonExtensionMethods.cs b/src/MongoDB.Bson/BsonExtensionMethods.cs index 2702533b613..09b317f6dc8 100644 --- a/src/MongoDB.Bson/BsonExtensionMethods.cs +++ b/src/MongoDB.Bson/BsonExtensionMethods.cs @@ -26,7 +26,7 @@ namespace MongoDB.Bson public static class BsonExtensionMethods { //DOMAIN-API We should remove all the methods that do not take a serialization domain. - //QUESTION: Do we want to do something now about this...? It's used also internally, but it seems in most cases it's used for "default serialization", so it should be ok. + //QUESTION: Do we want to do something now about this...? The methods are also used internally, but it seems in most cases it's used for "default serialization" and for "ToString" methods, so it should be ok. /// /// Serializes an object to a BSON byte array. /// diff --git a/src/MongoDB.Driver/Authentication/SaslAuthenticator.cs b/src/MongoDB.Driver/Authentication/SaslAuthenticator.cs index d7aefdc4653..ab2b6a60425 100644 --- a/src/MongoDB.Driver/Authentication/SaslAuthenticator.cs +++ b/src/MongoDB.Driver/Authentication/SaslAuthenticator.cs @@ -257,7 +257,7 @@ private CommandWireProtocol CreateCommandProtocol(BsonDocument com resultSerializer: BsonDocumentSerializer.Instance, messageEncoderSettings: null, serverApi: _serverApi, - serializationDomain: BsonSerializer.DefaultSerializationDomain); //QUESTION Is it correct to use the default serialization domain here? + serializationDomain: BsonSerializer.DefaultSerializationDomain); private BsonDocument CreateStartCommand(byte[] bytesToSendToServer) { diff --git a/src/MongoDB.Driver/Core/Bindings/CoreSession.cs b/src/MongoDB.Driver/Core/Bindings/CoreSession.cs index c803063d954..f01d7594f03 100644 --- a/src/MongoDB.Driver/Core/Bindings/CoreSession.cs +++ b/src/MongoDB.Driver/Core/Bindings/CoreSession.cs @@ -454,7 +454,7 @@ private IReadOperation CreateCommitTransactionOperation(OperationC { var writeConcern = GetCommitTransactionWriteConcern(operationContext, isCommitRetry); var maxCommitTime = _currentTransaction.TransactionOptions.MaxCommitTime; - //QUESTION Is it correct we only need a default domain here? + //We only use BsonDocumentSerializer with the domain, so using the default one is fine. return new CommitTransactionOperation(_currentTransaction.RecoveryToken, writeConcern, BsonSerializer.DefaultSerializationDomain) { MaxCommitTime = maxCommitTime }; } diff --git a/src/MongoDB.Driver/Core/Connections/ConnectionInitializer.cs b/src/MongoDB.Driver/Core/Connections/ConnectionInitializer.cs index 1a123ece262..00cd4734e82 100644 --- a/src/MongoDB.Driver/Core/Connections/ConnectionInitializer.cs +++ b/src/MongoDB.Driver/Core/Connections/ConnectionInitializer.cs @@ -163,7 +163,7 @@ private CommandWireProtocol CreateGetLastErrorProtocol(ServerApi s resultSerializer: BsonDocumentSerializer.Instance, messageEncoderSettings: null, serverApi: serverApi, - serializationDomain: BsonSerializer.DefaultSerializationDomain); //QUESTION Is it correct to use the default serialization domain here? + serializationDomain: BsonSerializer.DefaultSerializationDomain); return getLastErrorProtocol; } diff --git a/src/MongoDB.Driver/Core/Connections/HelloHelper.cs b/src/MongoDB.Driver/Core/Connections/HelloHelper.cs index 4aee3aa65fa..4382c8f969f 100644 --- a/src/MongoDB.Driver/Core/Connections/HelloHelper.cs +++ b/src/MongoDB.Driver/Core/Connections/HelloHelper.cs @@ -81,7 +81,7 @@ internal static CommandWireProtocol CreateProtocol( resultSerializer: BsonDocumentSerializer.Instance, messageEncoderSettings: null, serverApi, - serializationDomain: BsonSerializer.DefaultSerializationDomain); //QUESTION Is it correct to use the default serialization domain here? + serializationDomain: BsonSerializer.DefaultSerializationDomain); //Here and in similar cases using the default serialization domain is ok because we only serialize/deserialize BsonDocuments } internal static HelloResult GetResult( diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/CommandMessageSection.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/CommandMessageSection.cs index 384ff5425f6..528d9c8ede5 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/CommandMessageSection.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/CommandMessageSection.cs @@ -36,9 +36,9 @@ internal abstract class CommandMessageSection internal abstract class Type0CommandMessageSection : CommandMessageSection { // constructors - public Type0CommandMessageSection(object document, IBsonSerializer documentSerializer) + protected Type0CommandMessageSection(object document, IBsonSerializer documentSerializer) { - Ensure.IsNotNull((object)document, nameof(document)); + Ensure.IsNotNull(document, nameof(document)); Document = document; DocumentSerializer = Ensure.IsNotNull(documentSerializer, nameof(documentSerializer)); } @@ -86,7 +86,7 @@ protected BatchableCommandMessageSection( internal abstract class Type1CommandMessageSection : BatchableCommandMessageSection { // constructors - public Type1CommandMessageSection( + protected Type1CommandMessageSection( string identifier, IBatchableSource documents, IBsonSerializer documentSerializer, From d23c75de353dbbb66055e77f9eed48fefd405e1a Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Mon, 15 Sep 2025 18:54:52 +0200 Subject: [PATCH 15/21] Added domain to missing place --- .../AggregateExpressionDefinition.cs | 2 +- .../CommandMessageBinaryEncoder.cs | 2 +- .../JsonEncoders/CommandMessageJsonEncoder.cs | 2 +- ...pingWithOutputExpressionStageDefinitions.cs | 4 ++-- .../Misc/SerializationHelper.cs | 18 +++++++++++++----- ...dMethodToAggregationExpressionTranslator.cs | 2 +- ...tMethodToAggregationExpressionTranslator.cs | 2 +- ...yMethodToAggregationExpressionTranslator.cs | 2 +- ...tMethodToAggregationExpressionTranslator.cs | 7 ++++--- ...yMethodToAggregationExpressionTranslator.cs | 2 +- ...tMethodToAggregationExpressionTranslator.cs | 2 +- ...tMethodToAggregationExpressionTranslator.cs | 2 +- ...mMethodToAggregationExpressionTranslator.cs | 2 +- ...wMethodToAggregationExpressionTranslator.cs | 2 +- ...ontainsMethodToExecutableQueryTranslator.cs | 2 +- .../ExpressionToFilterTranslator.cs | 2 +- ...skComparisonExpressionToFilterTranslator.cs | 2 +- ...ToComparisonExpressionToFilterTranslator.cs | 2 +- .../ComparisonExpressionToFilterTranslator.cs | 2 +- .../MemberExpressionToFilterTranslator.cs | 4 ++-- .../ParameterExpressionToFilterTranslator.cs | 2 +- ...tainsInPredicateMethodToFilterTranslator.cs | 2 +- ...tainsInPredicateMethodToFilterTranslator.cs | 2 +- .../ContainsKeyMethodToFilterTranslator.cs | 6 +++--- .../ContainsMethodToFilterTranslator.cs | 4 ++-- .../ContainsValueMethodToFilterTranslator.cs | 2 +- .../EqualsMethodToFilterTranslator.cs | 2 +- .../HasFlagMethodToFilterTranslator.cs | 2 +- .../StringInOrNinMethodToFilterTranslator.cs | 4 ++-- .../GetItemMethodToFilterFieldTranslator.cs | 2 +- .../DocumentsMethodToPipelineTranslator.cs | 2 +- .../ExpressionToSetStageTranslator.cs | 2 +- src/MongoDB.Driver/RangeWindowBoundary.cs | 12 ++++++------ .../Search/OperatorSearchDefinitions.cs | 8 ++++---- src/MongoDB.Driver/SetFieldDefinition.cs | 2 +- 35 files changed, 64 insertions(+), 55 deletions(-) diff --git a/src/MongoDB.Driver/AggregateExpressionDefinition.cs b/src/MongoDB.Driver/AggregateExpressionDefinition.cs index eb898f917f0..7add6ae43a7 100644 --- a/src/MongoDB.Driver/AggregateExpressionDefinition.cs +++ b/src/MongoDB.Driver/AggregateExpressionDefinition.cs @@ -174,7 +174,7 @@ public DocumentsAggregateExpressionDefinition( public override BsonValue Render(RenderArgs args) { var documentSerializer = _documentSerializer ?? args.SerializerRegistry.GetSerializer(); - return SerializationHelper.SerializeValues(documentSerializer, _documents); + return SerializationHelper.SerializeValues(args.SerializationDomain, documentSerializer, _documents); } } } diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs index 8ae86a8c837..b16f9732c84 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/CommandMessageBinaryEncoder.cs @@ -28,8 +28,8 @@ namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders internal sealed class CommandMessageBinaryEncoder : MessageBinaryEncoderBase, IMessageEncoder { private const int EncryptedMaxBatchSize = 2 * 1024 * 1024; // 2 MiB + // Looking at our implementation, it seems that type 0 sections always serialize/deserialize RawBsonDocument/BsonDocument, so they should use the default domain. private static readonly ICommandMessageSectionFormatter __type0SectionFormatter = new Type0SectionFormatter(BsonSerializer.DefaultSerializationDomain); - //QUESTION Looking at the spec and our implementation, it seems that type 0 sections always serialize/deserialize RawBsonDocument, so they should use the default domain. Am I missing something? // constructors public CommandMessageBinaryEncoder(Stream stream, MessageEncoderSettings encoderSettings) diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandMessageJsonEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandMessageJsonEncoder.cs index ae5b1bdef97..81ade7809ed 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandMessageJsonEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/JsonEncoders/CommandMessageJsonEncoder.cs @@ -33,7 +33,7 @@ internal sealed class CommandMessageJsonEncoder : MessageJsonEncoderBase, IMessa public CommandMessageJsonEncoder(TextReader textReader, TextWriter textWriter, MessageEncoderSettings encoderSettings) : base(textReader, textWriter, encoderSettings) { - //QUESTION Looking at the spec and our implementation, it seems that type 0 sections always serialize/deserialize RawBsonDocument, so they should use the default domain. Am I missing something? + // Looking at our implementation, it seems that type 0 sections always serialize/deserialize RawBsonDocument/BsonDocument, so they should use the default domain. _type0SectionFormatter = new Type0SectionFormatter(BsonSerializer.DefaultSerializationDomain); _type1SectionFormatter = new Type1SectionFormatter(SerializationDomain); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/GroupingWithOutputExpressionStageDefinitions.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/GroupingWithOutputExpressionStageDefinitions.cs index 565cf37e6c9..8b33b6a77f2 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/GroupingWithOutputExpressionStageDefinitions.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/GroupingWithOutputExpressionStageDefinitions.cs @@ -109,8 +109,8 @@ protected override AstStage RenderGroupingStage( var groupByTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, partiallyEvaluatedGroupBy, inputSerializer, asRoot: true); var valueSerializer = (IBsonSerializer)groupByTranslation.Serializer; - var serializedBoundaries = SerializationHelper.SerializeValues(valueSerializer, _boundaries); - var serializedDefault = _options != null && _options.DefaultBucket.HasValue ? SerializationHelper.SerializeValue(valueSerializer, _options.DefaultBucket.Value) : null; + var serializedBoundaries = SerializationHelper.SerializeValues(context.SerializationDomain, valueSerializer, _boundaries); + var serializedDefault = _options != null && _options.DefaultBucket.HasValue ? SerializationHelper.SerializeValue(context.SerializationDomain, valueSerializer, _options.DefaultBucket.Value) : null; var pushElements = AstExpression.AccumulatorField("_elements", AstUnaryAccumulatorOperator.Push, AstExpression.RootVar); groupingOutputSerializer = IGroupingSerializer.Create(valueSerializer, inputSerializer); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/SerializationHelper.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/SerializationHelper.cs index ae6b638f51e..3df97abbec3 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/SerializationHelper.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/SerializationHelper.cs @@ -195,11 +195,14 @@ public static bool IsRepresentedAsIntegerOrNullableInteger(IBsonSerializer seria } public static BsonValue SerializeValue(IBsonSerializer serializer, ConstantExpression constantExpression, Expression containingExpression) + => SerializeValue(BsonSerializer.DefaultSerializationDomain, serializer, constantExpression, containingExpression); + + public static BsonValue SerializeValue(IBsonSerializationDomain serializationDomain, IBsonSerializer serializer, ConstantExpression constantExpression, Expression containingExpression) { var value = constantExpression.Value; if (value == null || serializer.ValueType.IsAssignableFrom(value.GetType())) { - return SerializeValue(serializer, value); + return SerializeValue(serializationDomain, serializer, value); } if (value.GetType().ImplementsIEnumerable(out var itemType) && @@ -209,27 +212,32 @@ itemSerializationInfo.Serializer is var itemSerializer && itemSerializer.ValueType.IsAssignableFrom(itemType)) { var ienumerableSerializer = IEnumerableSerializer.Create(itemSerializer); - return SerializeValue(ienumerableSerializer, value); + return SerializeValue(serializationDomain, ienumerableSerializer, value); } throw new ExpressionNotSupportedException(constantExpression, containingExpression, because: "it was not possible to determine how to serialize the constant"); } + public static BsonValue SerializeValue(IBsonSerializer serializer, object value) + => SerializeValue(BsonSerializer.DefaultSerializationDomain, serializer, value); + + //FP Isn't this similar to what SerializationInfo does...? + public static BsonValue SerializeValue(IBsonSerializationDomain serializationDomain, IBsonSerializer serializer, object value) { var document = new BsonDocument(); using (var writer = new BsonDocumentWriter(document)) { writer.WriteStartDocument(); writer.WriteName("_v"); - var context = BsonSerializationContext.CreateRoot(writer, BsonSerializer.DefaultSerializationDomain); //QUESTION Is it ok here to use the default domain? + var context = BsonSerializationContext.CreateRoot(writer, serializationDomain); serializer.Serialize(context, value); writer.WriteEndDocument(); } return document["_v"]; } - public static BsonArray SerializeValues(IBsonSerializer itemSerializer, IEnumerable values) + public static BsonArray SerializeValues(IBsonSerializationDomain serializationDomain, IBsonSerializer itemSerializer, IEnumerable values) { var document = new BsonDocument(); using (var writer = new BsonDocumentWriter(document)) @@ -237,7 +245,7 @@ public static BsonArray SerializeValues(IBsonSerializer itemSerializer, IEnumera writer.WriteStartDocument(); writer.WriteName("_v"); writer.WriteStartArray(); - var context = BsonSerializationContext.CreateRoot(writer, BsonSerializer.DefaultSerializationDomain); //QUESTION Is it ok here to use the default domain? + var context = BsonSerializationContext.CreateRoot(writer, serializationDomain); foreach(var value in values) { itemSerializer.Serialize(context, value); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/AppendOrPrependMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/AppendOrPrependMethodToAggregationExpressionTranslator.cs index 5a7a2942f70..e0273e6d9a3 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/AppendOrPrependMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/AppendOrPrependMethodToAggregationExpressionTranslator.cs @@ -56,7 +56,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC if (elementExpression is ConstantExpression elementConstantExpression) { var value = elementConstantExpression.Value; - var serializedValue = SerializationHelper.SerializeValue(itemSerializer, value); + var serializedValue = SerializationHelper.SerializeValue(context.SerializationDomain, itemSerializer, value); elementTranslation = new TranslatedExpression(elementExpression, AstExpression.Constant(serializedValue), itemSerializer); } else diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ConstantMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ConstantMethodToAggregationExpressionTranslator.cs index 47b39ab3e75..b3af43d6200 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ConstantMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ConstantMethodToAggregationExpressionTranslator.cs @@ -58,7 +58,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC if (serializer != null) { - var serializedValue = SerializationHelper.SerializeValue(serializer, value); + var serializedValue = SerializationHelper.SerializeValue(context.SerializationDomain, serializer, value); var ast = AstExpression.Constant(serializedValue); return new TranslatedExpression(expression, ast, serializer); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ContainsKeyMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ContainsKeyMethodToAggregationExpressionTranslator.cs index 452a3839fca..d4daf7f2beb 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ContainsKeyMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ContainsKeyMethodToAggregationExpressionTranslator.cs @@ -64,7 +64,7 @@ private static AstExpression GetKeyFieldName(TranslationContext context, Express if (keyExpression is ConstantExpression keyConstantExpression) { var keyValue = keyConstantExpression.Value; - var serializedKeyValue = SerializationHelper.SerializeValue(keySerializer, keyValue); + var serializedKeyValue = SerializationHelper.SerializeValue(context.SerializationDomain, keySerializer, keyValue); ThrowIfKeyIsNotRepresentedAsAString(expression, serializedKeyValue.BsonType); return AstExpression.Constant(serializedKeyValue); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ConvertMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ConvertMethodToAggregationExpressionTranslator.cs index 9f6844b3031..bdada669439 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ConvertMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ConvertMethodToAggregationExpressionTranslator.cs @@ -59,7 +59,7 @@ private static (BsonBinarySubType? subType, ByteOrder? byteOrder, string format, { return optionsExpression switch { - ConstantExpression constantExpression => TranslateOptions(constantExpression, toSerializer), + ConstantExpression constantExpression => TranslateOptions(context.SerializationDomain, constantExpression, toSerializer), MemberInitExpression memberInitExpressionExpression => TranslateOptions(context, expression, memberInitExpressionExpression, toSerializer), _ => throw new ExpressionNotSupportedException(optionsExpression, containingExpression: expression, because: "the options argument must be either a constant or a member initialization expression.") }; @@ -67,6 +67,7 @@ private static (BsonBinarySubType? subType, ByteOrder? byteOrder, string format, private static (BsonBinarySubType? subType, ByteOrder? byteOrder, string format, AstExpression onErrorAst, AstExpression onNullAst) TranslateOptions( + IBsonSerializationDomain serializationDomain, ConstantExpression optionsExpression, IBsonSerializer toSerializer) { @@ -78,13 +79,13 @@ private static (BsonBinarySubType? subType, ByteOrder? byteOrder, string format, { if (options.OnErrorWasSet(out var onErrorValue)) { - var serializedOnErrorValue = SerializationHelper.SerializeValue(toSerializer, onErrorValue); + var serializedOnErrorValue = SerializationHelper.SerializeValue(serializationDomain, toSerializer, onErrorValue); onErrorAst = AstExpression.Constant(serializedOnErrorValue); } if (options.OnNullWasSet(out var onNullValue)) { - var serializedOnNullValue = SerializationHelper.SerializeValue(toSerializer, onNullValue); + var serializedOnNullValue = SerializationHelper.SerializeValue(serializationDomain, toSerializer, onNullValue); onNullAst = AstExpression.Constant(serializedOnNullValue); } } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/DefaultIfEmptyMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/DefaultIfEmptyMethodToAggregationExpressionTranslator.cs index 3d66a096ad8..665b3ddf87a 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/DefaultIfEmptyMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/DefaultIfEmptyMethodToAggregationExpressionTranslator.cs @@ -64,7 +64,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC { var sourceItemSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer); var defaultValue = sourceItemSerializer.ValueType.GetDefaultValue(); - var serializedDefaultValue = SerializationHelper.SerializeValue(sourceItemSerializer, defaultValue); + var serializedDefaultValue = SerializationHelper.SerializeValue(context.SerializationDomain, sourceItemSerializer, defaultValue); defaultValueAst = AstExpression.Constant(new BsonArray { serializedDefaultValue }); } var ast = AstExpression.Let( diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ElementAtMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ElementAtMethodToAggregationExpressionTranslator.cs index 17cb037c144..e4f06d28a28 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ElementAtMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ElementAtMethodToAggregationExpressionTranslator.cs @@ -57,7 +57,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC if (method.IsOneOf(__elementAtOrDefaultMethods)) { var defaultValue = itemSerializer.ValueType.GetDefaultValue(); - var serializedDefaultValue = SerializationHelper.SerializeValue(itemSerializer, defaultValue); + var serializedDefaultValue = SerializationHelper.SerializeValue(context.SerializationDomain, itemSerializer, defaultValue); var (sourceVarBinding, sourceAst) = AstExpression.UseVarIfNotSimple("source", sourceTranslation.Ast); var (indexVarBinding, indexAst) = AstExpression.UseVarIfNotSimple("index", indexTranslation.Ast); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/FirstOrLastMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/FirstOrLastMethodToAggregationExpressionTranslator.cs index 932d4c6856b..967c0bb09e6 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/FirstOrLastMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/FirstOrLastMethodToAggregationExpressionTranslator.cs @@ -111,7 +111,7 @@ public static TranslatedExpression Translate(TranslationContext context, MethodC if (method.IsOneOf(__orDefaultMethods)) { var defaultValue = itemSerializer.ValueType.GetDefaultValue(); - var serializedDefaultValue = SerializationHelper.SerializeValue(itemSerializer, defaultValue); + var serializedDefaultValue = SerializationHelper.SerializeValue(context.SerializationDomain, itemSerializer, defaultValue); var (valuesVarBinding, valuesAst) = AstExpression.UseVarIfNotSimple("values", sourceAst); ast = AstExpression.Let( diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/GetItemMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/GetItemMethodToAggregationExpressionTranslator.cs index 88bf49554f6..269f9424c1b 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/GetItemMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/GetItemMethodToAggregationExpressionTranslator.cs @@ -130,7 +130,7 @@ private static TranslatedExpression TranslateIDictionaryGetItemWithKey(Translati if (keyExpression is ConstantExpression constantKeyExpression) { var key = constantKeyExpression.Value; - var serializedKey = SerializationHelper.SerializeValue(keySerializer, key); + var serializedKey = SerializationHelper.SerializeValue(context.SerializationDomain, keySerializer, key); if (!(serializedKey is BsonString)) { diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WindowMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WindowMethodToAggregationExpressionTranslator.cs index 501b56dec22..3310552d39e 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WindowMethodToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/WindowMethodToAggregationExpressionTranslator.cs @@ -577,7 +577,7 @@ private static AstWindow ToAstWindow( } } - return new AstWindow("range", lowerBoundary.Render(lowerBoundaryValueSerializer), upperBoundary.Render(upperBoundaryValueSerializer), unit); + return new AstWindow("range", lowerBoundary.Render(serializationDomain, lowerBoundaryValueSerializer), upperBoundary.Render(serializationDomain, upperBoundaryValueSerializer), unit); } throw new ArgumentException($"Invalid window type: {window.GetType().FullName}."); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/ContainsMethodToExecutableQueryTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/ContainsMethodToExecutableQueryTranslator.cs index 9e4be249624..22fb3e9589b 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/ContainsMethodToExecutableQueryTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToExecutableQueryTranslators/ContainsMethodToExecutableQueryTranslator.cs @@ -68,7 +68,7 @@ public static ExecutableQuery Translate(MongoQueryPr var itemExpression = arguments[1]; var itemValue = itemExpression.GetConstantValue(containingExpression: expression); - var serializedValue = SerializationHelper.SerializeValue(pipeline.OutputSerializer, itemValue); + var serializedValue = SerializationHelper.SerializeValue(context.SerializationDomain, pipeline.OutputSerializer, itemValue); AstFilter filter = AstFilter.Eq(AstFilter.Field("_v"), serializedValue); pipeline = pipeline.AddStages( diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionToFilterTranslator.cs index d003c36d9af..71ca1c11be3 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionToFilterTranslator.cs @@ -120,7 +120,7 @@ private static AstFilter TranslateUsingQueryOperators(TranslationContext context if (expression.Type == typeof(bool)) { var fieldTranslation = ExpressionToFilterFieldTranslator.Translate(context, expression); - var serializedTrue = SerializationHelper.SerializeValue(fieldTranslation.Serializer, true); + var serializedTrue = SerializationHelper.SerializeValue(context.SerializationDomain, fieldTranslation.Serializer, true); return AstFilter.Eq(fieldTranslation.Ast, serializedTrue); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/BitMaskComparisonExpressionToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/BitMaskComparisonExpressionToFilterTranslator.cs index e98b480fe1e..e282e2833f8 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/BitMaskComparisonExpressionToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/BitMaskComparisonExpressionToFilterTranslator.cs @@ -84,7 +84,7 @@ public static AstFilter Translate( var bitMaskExpression = leftBinaryExpression.Right; var bitMask = bitMaskExpression.GetConstantValue(containingExpression: expression); - var serializedBitMask = SerializationHelper.SerializeValue(fieldTranslation.Serializer, bitMask); + var serializedBitMask = SerializationHelper.SerializeValue(context.SerializationDomain, fieldTranslation.Serializer, bitMask); var rightValue = rightExpression.GetConstantValue(containingExpression: expression); var zeroValue = Activator.CreateInstance(bitMask.GetType()); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/CompareToComparisonExpressionToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/CompareToComparisonExpressionToFilterTranslator.cs index 500395dbf42..4075336df56 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/CompareToComparisonExpressionToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/CompareToComparisonExpressionToFilterTranslator.cs @@ -47,7 +47,7 @@ public static AstFilter Translate( var valueExpression = leftMethodCallExpression.Arguments[0]; var value = valueExpression.GetConstantValue(containingExpression: expression); - var serializedValue = SerializationHelper.SerializeValue(fieldTranslation.Serializer, value); + var serializedValue = SerializationHelper.SerializeValue(context.SerializationDomain, fieldTranslation.Serializer, value); var rightValue = rightExpression.GetConstantValue(containingExpression: expression); if (rightValue == 0) diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ComparisonExpressionToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ComparisonExpressionToFilterTranslator.cs index 46e6c9c459e..745b1cf2412 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ComparisonExpressionToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ComparisonExpressionToFilterTranslator.cs @@ -90,7 +90,7 @@ public static AstFilter Translate(TranslationContext context, BinaryExpression e } var fieldTranslation = ExpressionToFilterFieldTranslator.Translate(context, leftExpression); - var serializedComparand = SerializationHelper.SerializeValue(fieldTranslation.Serializer, comparandExpression, expression); + var serializedComparand = SerializationHelper.SerializeValue(context.SerializationDomain, fieldTranslation.Serializer, comparandExpression, expression); return AstFilter.Compare(fieldTranslation.Ast, comparisonOperator, serializedComparand); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/MemberExpressionToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/MemberExpressionToFilterTranslator.cs index 2378513e9ba..d47238e9671 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/MemberExpressionToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/MemberExpressionToFilterTranslator.cs @@ -34,7 +34,7 @@ public static AstFilter Translate(TranslationContext context, MemberExpression e if (fieldInfo.FieldType == typeof(bool)) { var fieldTranslation = ExpressionToFilterFieldTranslator.Translate(context, expression); - var serializedTrue = SerializationHelper.SerializeValue(fieldTranslation.Serializer, true); + var serializedTrue = SerializationHelper.SerializeValue(context.SerializationDomain, fieldTranslation.Serializer, true); return AstFilter.Eq(fieldTranslation.Ast, serializedTrue); } } @@ -51,7 +51,7 @@ public static AstFilter Translate(TranslationContext context, MemberExpression e if (propertyInfo.PropertyType == typeof(bool)) { var fieldTranslation = ExpressionToFilterFieldTranslator.Translate(context, expression); - var serializedTrue = SerializationHelper.SerializeValue(fieldTranslation.Serializer, true); + var serializedTrue = SerializationHelper.SerializeValue(context.SerializationDomain, fieldTranslation.Serializer, true); return AstFilter.Eq(fieldTranslation.Ast, serializedTrue); } } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ParameterExpressionToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ParameterExpressionToFilterTranslator.cs index 7a703c3bc76..79decc008a8 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ParameterExpressionToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ExpressionTranslators/ParameterExpressionToFilterTranslator.cs @@ -29,7 +29,7 @@ public static AstFilter Translate(TranslationContext context, ParameterExpressio { var serializer = symbol.Serializer; var field = AstFilter.Field(symbol.Name); - var serializedTrue = SerializationHelper.SerializeValue(serializer, true); + var serializedTrue = SerializationHelper.SerializeValue(context.SerializationDomain, serializer, true); return AstFilter.Eq(field, serializedTrue); } } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/AllWithContainsInPredicateMethodToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/AllWithContainsInPredicateMethodToFilterTranslator.cs index cabda2421f0..ca679e7132c 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/AllWithContainsInPredicateMethodToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/AllWithContainsInPredicateMethodToFilterTranslator.cs @@ -57,7 +57,7 @@ public static AstFilter Translate(TranslationContext context, Expression arrayFi var arrayFieldTranslation = ExpressionToFilterFieldTranslator.TranslateEnumerable(context, arrayFieldExpression); var itemSerializer = ArraySerializerHelper.GetItemSerializer(arrayFieldTranslation.Serializer); var values = (IEnumerable)arrayConstantExpression.Value; - var serializedValues = SerializationHelper.SerializeValues(itemSerializer, values); + var serializedValues = SerializationHelper.SerializeValues(context.SerializationDomain, itemSerializer, values); return AstFilter.All(arrayFieldTranslation.Ast, serializedValues); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/AnyWithContainsInPredicateMethodToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/AnyWithContainsInPredicateMethodToFilterTranslator.cs index 53d9f10f4b8..5d5d4c2a0b9 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/AnyWithContainsInPredicateMethodToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/AnyWithContainsInPredicateMethodToFilterTranslator.cs @@ -66,7 +66,7 @@ public static AstFilter Translate(TranslationContext context, Expression arrayFi var arrayFieldTranslation = ExpressionToFilterFieldTranslator.TranslateEnumerable(context, arrayFieldExpression); var itemSerializer = ArraySerializerHelper.GetItemSerializer(arrayFieldTranslation.Serializer); var values = (IEnumerable)arrayConstantExpression.Value; - var serializedValues = SerializationHelper.SerializeValues(itemSerializer, values); + var serializedValues = SerializationHelper.SerializeValues(context.SerializationDomain, itemSerializer, values); return AstFilter.In(arrayFieldTranslation.Ast, serializedValues); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/ContainsKeyMethodToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/ContainsKeyMethodToFilterTranslator.cs index 48398cec982..4d5214efbaf 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/ContainsKeyMethodToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/ContainsKeyMethodToFilterTranslator.cs @@ -43,7 +43,7 @@ public static AstFilter Translate(TranslationContext context, MethodCallExpressi switch (dictionaryRepresentation) { case DictionaryRepresentation.Document: - var key = GetKeyStringConstant(expression, keyExpression, dictionarySerializer.KeySerializer); + var key = GetKeyStringConstant(context.SerializationDomain, expression, keyExpression, dictionarySerializer.KeySerializer); var keyField = fieldTranslation.Ast.SubField(key); return AstFilter.Exists(keyField); @@ -65,12 +65,12 @@ private static IBsonDictionarySerializer GetDictionarySerializer(Expression expr throw new ExpressionNotSupportedException(expression, because: $"class {field.Serializer.GetType().FullName} does not implement the IBsonDictionarySerializer interface"); } - private static string GetKeyStringConstant(Expression expression, Expression keyExpression, IBsonSerializer keySerializer) + private static string GetKeyStringConstant(IBsonSerializationDomain serializationDomain, Expression expression, Expression keyExpression, IBsonSerializer keySerializer) { if (keyExpression is ConstantExpression keyConstantExpression) { var keyValue = keyConstantExpression.Value; - var serializedKeyValue = SerializationHelper.SerializeValue(keySerializer, keyValue); + var serializedKeyValue = SerializationHelper.SerializeValue(serializationDomain, keySerializer, keyValue); if (serializedKeyValue.BsonType == BsonType.String) { return serializedKeyValue.AsString; diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/ContainsMethodToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/ContainsMethodToFilterTranslator.cs index 574a93809c6..412c3f3dc10 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/ContainsMethodToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/ContainsMethodToFilterTranslator.cs @@ -76,13 +76,13 @@ private static AstFilter Translate(TranslationContext context, Expression expres var fieldTranslation = ExpressionToFilterFieldTranslator.TranslateEnumerable(context, fieldExpression); var itemSerializer = ArraySerializerHelper.GetItemSerializer(fieldTranslation.Serializer); var value = itemExpression.GetConstantValue(containingExpression: expression); - var serializedValue = SerializationHelper.SerializeValue(itemSerializer, value); + var serializedValue = SerializationHelper.SerializeValue(context.SerializationDomain, itemSerializer, value); return AstFilter.ElemMatch(fieldTranslation.Ast, AstFilter.Eq(AstFilter.Field("@"), serializedValue)); // @ represents the implied element } var itemTranslation = ExpressionToFilterFieldTranslator.Translate(context, itemExpression); var sourceValues = fieldExpression.GetConstantValue(containingExpression: expression); - var serializedValues = SerializationHelper.SerializeValues(itemTranslation.Serializer, sourceValues); + var serializedValues = SerializationHelper.SerializeValues(context.SerializationDomain, itemTranslation.Serializer, sourceValues); return AstFilter.In(itemTranslation.Ast, serializedValues); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/ContainsValueMethodToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/ContainsValueMethodToFilterTranslator.cs index 2066d8f789a..3d9e49498da 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/ContainsValueMethodToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/ContainsValueMethodToFilterTranslator.cs @@ -44,7 +44,7 @@ public static AstFilter Translate(TranslationContext context, MethodCallExpressi { var valueField = AstFilter.Field("v"); var value = constantValueExpression.Value; - var serializedValue = SerializationHelper.SerializeValue(valueSerializer, value); + var serializedValue = SerializationHelper.SerializeValue(context.SerializationDomain, valueSerializer, value); switch (dictionaryRepresentation) { diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/EqualsMethodToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/EqualsMethodToFilterTranslator.cs index ec3271f443f..df339b39457 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/EqualsMethodToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/EqualsMethodToFilterTranslator.cs @@ -72,7 +72,7 @@ private static AstFilter Translate(TranslationContext context, Expression expres var fieldTranslation = ExpressionToFilterFieldTranslator.Translate(context, fieldExpression); var value = valueExpression.GetConstantValue(containingExpression: expression); - var serializedValue = SerializationHelper.SerializeValue(fieldTranslation.Serializer, value); + var serializedValue = SerializationHelper.SerializeValue(context.SerializationDomain, fieldTranslation.Serializer, value); return AstFilter.Eq(fieldTranslation.Ast, serializedValue); } } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/HasFlagMethodToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/HasFlagMethodToFilterTranslator.cs index 6b17bf6de5e..25a6d7ebd10 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/HasFlagMethodToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/HasFlagMethodToFilterTranslator.cs @@ -37,7 +37,7 @@ public static AstFilter Translate(TranslationContext context, MethodCallExpressi var flagExpression = arguments[0]; var flag = flagExpression.GetConstantValue(containingExpression: expression); - var serializedFlag = SerializationHelper.SerializeValue(fieldTranslation.Serializer, flag); + var serializedFlag = SerializationHelper.SerializeValue(context.SerializationDomain, fieldTranslation.Serializer, flag); return AstFilter.BitsAllSet(fieldTranslation.Ast, serializedFlag); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/StringInOrNinMethodToFilterTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/StringInOrNinMethodToFilterTranslator.cs index 845b016ca9e..b12241db4b6 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/StringInOrNinMethodToFilterTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/MethodTranslators/StringInOrNinMethodToFilterTranslator.cs @@ -72,12 +72,12 @@ public static AstFilter Translate(TranslationContext context, MethodCallExpressi if (value?.Type == typeof(BsonRegularExpression)) { var regularExpression = value.RegularExpression; - serializedValue = SerializationHelper.SerializeValue(regularExpressionSerializer, regularExpression); + serializedValue = SerializationHelper.SerializeValue(context.SerializationDomain, regularExpressionSerializer, regularExpression); } else { var @string = value?.String; - serializedValue = SerializationHelper.SerializeValue(stringSerializer, @string); + serializedValue = SerializationHelper.SerializeValue(context.SerializationDomain, stringSerializer, @string); } serializedValues.Add(serializedValue); } diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/GetItemMethodToFilterFieldTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/GetItemMethodToFilterFieldTranslator.cs index d6411ae7bfe..6631e70bcb9 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/GetItemMethodToFilterFieldTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/GetItemMethodToFilterFieldTranslator.cs @@ -97,7 +97,7 @@ private static TranslatedFilterField TranslateDictionaryGetItemWithKey(Translati var keySerializer = dictionarySerializer.KeySerializer; var valueSerializer = dictionarySerializer.ValueSerializer; - var serializedKey = SerializationHelper.SerializeValue(keySerializer, key); + var serializedKey = SerializationHelper.SerializeValue(context.SerializationDomain, keySerializer, key); if (serializedKey is not BsonString) { throw new ExpressionNotSupportedException(expression, because: "key did not serialize as a string"); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/DocumentsMethodToPipelineTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/DocumentsMethodToPipelineTranslator.cs index c03f0a8725d..a433fff76d3 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/DocumentsMethodToPipelineTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/DocumentsMethodToPipelineTranslator.cs @@ -61,7 +61,7 @@ public static TranslatedPipeline Translate(TranslationContext context, MethodCal documentSerializer = context.SerializationDomain.LookupSerializer(documentType); } - var serializedDocuments = SerializationHelper.SerializeValues(documentSerializer, documents); + var serializedDocuments = SerializationHelper.SerializeValues(context.SerializationDomain, documentSerializer, documents); var documentsStage = AstStage.Documents(serializedDocuments); pipeline = pipeline.AddStage(documentsStage, documentSerializer); diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToSetStageTranslators/ExpressionToSetStageTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToSetStageTranslators/ExpressionToSetStageTranslator.cs index 018c2ae5051..b4d72df86c8 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToSetStageTranslators/ExpressionToSetStageTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToSetStageTranslators/ExpressionToSetStageTranslator.cs @@ -148,7 +148,7 @@ private static AstComputedField CreateComputedField(TranslationContext context, if (valueExpression is ConstantExpression constantValueExpression) { var value = constantValueExpression.Value; - var serializedValue = SerializationHelper.SerializeValue(memberSerializer, value); + var serializedValue = SerializationHelper.SerializeValue(context.SerializationDomain, memberSerializer, value); valueAst = AstExpression.Constant(serializedValue); } else diff --git a/src/MongoDB.Driver/RangeWindowBoundary.cs b/src/MongoDB.Driver/RangeWindowBoundary.cs index 004a077030b..95d5ea38504 100644 --- a/src/MongoDB.Driver/RangeWindowBoundary.cs +++ b/src/MongoDB.Driver/RangeWindowBoundary.cs @@ -30,7 +30,7 @@ namespace MongoDB.Driver public abstract class RangeWindowBoundary { internal RangeWindowBoundary() { } // disallow user defined subclasses - internal abstract BsonValue Render(IBsonSerializer valueSerializer); + internal abstract BsonValue Render(IBsonSerializationDomain serializationDomain, IBsonSerializer valueSerializer); } /// @@ -53,7 +53,7 @@ internal KeywordRangeWindowBoundary(string keyword) /// public override string ToString() => $"\"{_keyword}\""; - internal override BsonValue Render(IBsonSerializer valueSerializer) => _keyword; + internal override BsonValue Render(IBsonSerializationDomain serializationDomain, IBsonSerializer valueSerializer) => _keyword; } /// @@ -92,13 +92,13 @@ internal ValueRangeWindowBoundary(TValue value) /// public override string ToString() => _value.ToString(); - internal override BsonValue Render(IBsonSerializer valueSerializer) + internal override BsonValue Render(IBsonSerializationDomain serializationDomain, IBsonSerializer valueSerializer) { if (valueSerializer == null) { - throw new ArgumentNullException("A value serializer is required to serialize range values.", nameof(valueSerializer)); + throw new ArgumentNullException(nameof(valueSerializer), "A value serializer is required to serialize range values."); } - return SerializationHelper.SerializeValue(valueSerializer, _value); + return SerializationHelper.SerializeValue(serializationDomain, valueSerializer, _value); } } @@ -129,7 +129,7 @@ internal TimeRangeWindowBoundary(int value, string unit) /// public override string ToString() => $"{_value} ({_unit})"; - internal override BsonValue Render(IBsonSerializer valueSerializer) => _value; + internal override BsonValue Render(IBsonSerializationDomain serializationDomain, IBsonSerializer valueSerializer) => _value; } internal static class ValueRangeWindowBoundaryConvertingValueSerializerFactory diff --git a/src/MongoDB.Driver/Search/OperatorSearchDefinitions.cs b/src/MongoDB.Driver/Search/OperatorSearchDefinitions.cs index 28304fae5ad..98edd715313 100644 --- a/src/MongoDB.Driver/Search/OperatorSearchDefinitions.cs +++ b/src/MongoDB.Driver/Search/OperatorSearchDefinitions.cs @@ -147,7 +147,7 @@ private protected override BsonDocument RenderArguments( _ => fieldSerializer }; - serializedValue = SerializationHelper.SerializeValue(valueSerializer, _value); + serializedValue = SerializationHelper.SerializeValue(args.SerializationDomain, valueSerializer, _value); } else { @@ -263,7 +263,7 @@ private protected override BsonDocument RenderArguments( _ => new ArraySerializer((IBsonSerializer)fieldSerializer) }; - serializedValues = SerializationHelper.SerializeValue(arraySerializer, _values); + serializedValues = SerializationHelper.SerializeValue(args.SerializationDomain, arraySerializer, _values); } else { @@ -400,8 +400,8 @@ private protected override BsonDocument RenderArguments( _ => fieldSerializer }; - serializedMin = _range.Min == null ? null : SerializationHelper.SerializeValue(valueSerializer, _range.Min.Value); - serializedMax = _range.Max == null ? null : SerializationHelper.SerializeValue(valueSerializer, _range.Max.Value); + serializedMin = _range.Min == null ? null : SerializationHelper.SerializeValue(args.SerializationDomain, valueSerializer, _range.Min.Value); + serializedMax = _range.Max == null ? null : SerializationHelper.SerializeValue(args.SerializationDomain, valueSerializer, _range.Max.Value); } else { diff --git a/src/MongoDB.Driver/SetFieldDefinition.cs b/src/MongoDB.Driver/SetFieldDefinition.cs index 74caf0475fc..7f8d3a81b13 100644 --- a/src/MongoDB.Driver/SetFieldDefinition.cs +++ b/src/MongoDB.Driver/SetFieldDefinition.cs @@ -61,7 +61,7 @@ public ConstantSetFieldDefinition(FieldDefinition field, TFie public override BsonElement Render(RenderArgs args) { var renderedField = _field.Render(args); - var serializedValue = SerializationHelper.SerializeValue(renderedField.ValueSerializer, _value); + var serializedValue = SerializationHelper.SerializeValue(args.SerializationDomain, renderedField.ValueSerializer, _value); return new BsonElement(renderedField.FieldName, serializedValue); } From ee3592e91fc134f1638f970252a0b24492af73d7 Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Mon, 15 Sep 2025 19:19:37 +0200 Subject: [PATCH 16/21] Small fixes --- src/MongoDB.Driver/Authentication/MongoDBX509Authenticator.cs | 2 +- .../BinaryEncoders/ClientBulkWriteOpsSectionFormatter.cs | 2 +- .../Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/MongoDB.Driver/Authentication/MongoDBX509Authenticator.cs b/src/MongoDB.Driver/Authentication/MongoDBX509Authenticator.cs index ee7a68c199b..fc5f5ce2b7b 100644 --- a/src/MongoDB.Driver/Authentication/MongoDBX509Authenticator.cs +++ b/src/MongoDB.Driver/Authentication/MongoDBX509Authenticator.cs @@ -113,7 +113,7 @@ private CommandWireProtocol CreateAuthenticateProtocol() resultSerializer: BsonDocumentSerializer.Instance, messageEncoderSettings: null, serverApi: _serverApi, - serializationDomain: BsonSerializer.DefaultSerializationDomain); //QUESTION Is this correct? Using a default serialization domain? + serializationDomain: BsonSerializer.DefaultSerializationDomain); return protocol; } diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ClientBulkWriteOpsSectionFormatter.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ClientBulkWriteOpsSectionFormatter.cs index b1478d40e7b..dc59c379ca8 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ClientBulkWriteOpsSectionFormatter.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ClientBulkWriteOpsSectionFormatter.cs @@ -29,9 +29,9 @@ internal sealed class ClientBulkWriteOpsSectionFormatter : ICommandMessageSectio { private readonly long? _maxSize; private readonly Dictionary _nsInfos; + private readonly IBsonSerializationDomain _serializationDomain; private MemoryStream _nsInfoMemoryStream; private BsonBinaryWriter _nsInfoWriter; - private IBsonSerializationDomain _serializationDomain; private Dictionary _idsMap; private int _currentIndex; diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs index 7146d4eec7b..2b2d3e254bb 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs @@ -156,7 +156,6 @@ private void WriteOptionalFields(BsonBinaryWriter binaryWriter, BsonDocument fie { if (fields != null) { - //QUESTION Is it correct we only need a default domain here? var context = BsonSerializationContext.CreateRoot(binaryWriter, BsonSerializer.DefaultSerializationDomain); BsonDocumentSerializer.Instance.Serialize(context, fields); } From 01e7d597e2cf06626e0d43d3d0065d67d145ebc1 Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Wed, 17 Sep 2025 09:19:04 +0200 Subject: [PATCH 17/21] Small improvements --- src/MongoDB.Bson/Serialization/BsonMemberMap.cs | 2 +- .../Serialization/IBsonSerializationProvider.cs | 1 - .../Core/Operations/CreateSearchIndexesOperation.cs | 1 - .../Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs | 1 - .../Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs | 6 ++++-- .../Encoders/BinaryEncoders/ReplyMessageBinaryEncoder.cs | 8 ++++---- .../Messages/Encoders/MessageEncoderSettings.cs | 3 ++- src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs | 2 +- src/MongoDB.Driver/RenderArgs.cs | 6 +++--- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/MongoDB.Bson/Serialization/BsonMemberMap.cs b/src/MongoDB.Bson/Serialization/BsonMemberMap.cs index 1181af3c7a8..21316fcee54 100644 --- a/src/MongoDB.Bson/Serialization/BsonMemberMap.cs +++ b/src/MongoDB.Bson/Serialization/BsonMemberMap.cs @@ -56,7 +56,7 @@ public BsonMemberMap(BsonClassMap classMap, MemberInfo memberInfo) { _classMap = classMap; _memberInfo = memberInfo; - _memberType = BsonClassMap.GetMemberInfoType(memberInfo); //FP This is more of a utility method, it can stay like this + _memberType = BsonClassMap.GetMemberInfoType(memberInfo); _memberTypeIsBsonValue = typeof(BsonValue).GetTypeInfo().IsAssignableFrom(_memberType); Reset(); diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs b/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs index 73b54c69e3e..d93b10d544f 100644 --- a/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs +++ b/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs @@ -55,7 +55,6 @@ internal interface IDomainAwareBsonSerializationProvider : IRegistryAwareBsonSer { IBsonSerializationDomain SerializationDomain { get; } - //FP Can't use just GetSerializer name because it's already used by the base interface. IBsonSerializer GetSerializerWithDomain(Type type); } } diff --git a/src/MongoDB.Driver/Core/Operations/CreateSearchIndexesOperation.cs b/src/MongoDB.Driver/Core/Operations/CreateSearchIndexesOperation.cs index 43210821099..f325b125986 100644 --- a/src/MongoDB.Driver/Core/Operations/CreateSearchIndexesOperation.cs +++ b/src/MongoDB.Driver/Core/Operations/CreateSearchIndexesOperation.cs @@ -37,7 +37,6 @@ internal sealed class CreateSearchIndexesOperation : IWriteOperation _requests; private readonly IBsonSerializationDomain _serializationDomain; - //FP We should remove all the docs in those internal classes, at least for constructors. // constructors /// /// Initializes a new instance of the class. diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs index 71c07ee442b..3606b5fc91c 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs @@ -84,7 +84,6 @@ protected int? MaxWireDocumentSize protected IBsonSerializationDomain SerializationDomain => _encoderSettings?.GetOrDefault(MessageEncoderSettingsName.SerializationDomain, null) ?? BsonSerializer.DefaultSerializationDomain; - //QUESTION Is this correct? If we don't have a domain in the encoder settings, just use the default one? // methods public BsonBinaryReader CreateBinaryReader() diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs index 2b2d3e254bb..3efbe5c22bd 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/QueryMessageBinaryEncoder.cs @@ -25,10 +25,13 @@ namespace MongoDB.Driver.Core.WireProtocol.Messages.Encoders.BinaryEncoders { internal sealed class QueryMessageBinaryEncoder : MessageBinaryEncoderBase, IMessageEncoder { + private readonly IBsonSerializationDomain _serializationDomain; + // constructors public QueryMessageBinaryEncoder(Stream stream, MessageEncoderSettings encoderSettings) : base(stream, encoderSettings) { + _serializationDomain = encoderSettings?.GetOrDefault(MessageEncoderSettingsName.SerializationDomain, null) ?? BsonSerializer.DefaultSerializationDomain; } // methods @@ -169,8 +172,7 @@ private void WriteQuery(BsonBinaryWriter binaryWriter, BsonDocument query, IElem binaryWriter.PushElementNameValidator(queryValidator); try { - //QUESTION Is it correct we only need a default domain here? - var context = BsonSerializationContext.CreateRoot(binaryWriter, BsonSerializer.DefaultSerializationDomain); + var context = BsonSerializationContext.CreateRoot(binaryWriter, _serializationDomain); BsonDocumentSerializer.Instance.Serialize(context, query ?? new BsonDocument()); } finally diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ReplyMessageBinaryEncoder.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ReplyMessageBinaryEncoder.cs index 51594e6f2ff..70b7cb1d882 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ReplyMessageBinaryEncoder.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ReplyMessageBinaryEncoder.cs @@ -28,12 +28,14 @@ internal class ReplyMessageBinaryEncoder : MessageBinaryEncoderBase, { // fields private readonly IBsonSerializer _serializer; + private readonly IBsonSerializationDomain _serializationDomain; // constructors public ReplyMessageBinaryEncoder(Stream stream, MessageEncoderSettings encoderSettings, IBsonSerializer serializer) : base(stream, encoderSettings) { _serializer = Ensure.IsNotNull(serializer, nameof(serializer)); + _serializationDomain = encoderSettings?.GetOrDefault(MessageEncoderSettingsName.SerializationDomain, null) ?? BsonSerializer.DefaultSerializationDomain; } // methods @@ -124,16 +126,14 @@ public void WriteMessage(ReplyMessage message) stream.WriteInt32(message.NumberReturned); if (message.QueryFailure) { - //QUESTION Is it correct we only need a default domain here? - var context = BsonSerializationContext.CreateRoot(binaryWriter, BsonSerializer.DefaultSerializationDomain); + var context = BsonSerializationContext.CreateRoot(binaryWriter, _serializationDomain); _serializer.Serialize(context, message.QueryFailureDocument); } else { foreach (var doc in message.Documents) { - //QUESTION Is it correct we only need a default domain here? - var context = BsonSerializationContext.CreateRoot(binaryWriter, BsonSerializer.DefaultSerializationDomain); + var context = BsonSerializationContext.CreateRoot(binaryWriter, _serializationDomain); _serializer.Serialize(context, doc); } } diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs index 112d77816ca..e9d1af98cd2 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs @@ -41,7 +41,8 @@ internal static class MessageEncoderSettingsName public const string ShellVersion = nameof(ShellVersion); // other encoders (if any) might use additional settings - public const string SerializationDomain = nameof(SerializationDomain); //FP I think I should try to remove it from here.. + public const string SerializationDomain = nameof(SerializationDomain); + //QUESTION Should this be removed from here? If so, what do we do with all the Encoders that use it? } internal sealed class MessageEncoderSettings : IEnumerable> diff --git a/src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs b/src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs index 8cc047a228e..b5059b70bce 100644 --- a/src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs +++ b/src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs @@ -568,7 +568,7 @@ public static PipelineStageDefinition Facet( { outputSerializer = (IBsonSerializer)new AggregateFacetResultsSerializer( materializedFacets.Select(f => f.Name), - materializedFacets.Select(f => f.OutputSerializer ?? args.SerializerRegistry.GetSerializer(f.OutputType))); //QUESTION What do we do? Do we delay the setting of the serializer..? + materializedFacets.Select(f => f.OutputSerializer ?? args.SerializerRegistry.GetSerializer(f.OutputType))); } else { diff --git a/src/MongoDB.Driver/RenderArgs.cs b/src/MongoDB.Driver/RenderArgs.cs index d9ed451eb12..3645d66d06e 100644 --- a/src/MongoDB.Driver/RenderArgs.cs +++ b/src/MongoDB.Driver/RenderArgs.cs @@ -55,7 +55,7 @@ public RenderArgs( IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry, PathRenderArgs pathRenderArgs = default, - bool renderDollarForm = default, + bool renderDollarForm = false, bool renderForFind = false, bool renderForElemMatch = false, ExpressionTranslationOptions translationOptions = null) @@ -84,7 +84,7 @@ internal RenderArgs( IBsonSerializer documentSerializer, IBsonSerializationDomain serializationDomain, PathRenderArgs pathRenderArgs = default, - bool renderDollarForm = default, + bool renderDollarForm = false, bool renderForFind = false, bool renderForElemMatch = false, ExpressionTranslationOptions translationOptions = null) @@ -131,7 +131,7 @@ public readonly IBsonSerializer DocumentSerializer /// /// Gets the serializer registry. /// - public readonly IBsonSerializerRegistry SerializerRegistry //TODO: we should probably remove this property + public readonly IBsonSerializerRegistry SerializerRegistry //DOMAIN-API: we should probably remove this property and use the domain directly { get => _serializerRegistry; init => _serializerRegistry = Ensure.IsNotNull(value, nameof(value)); From 643408ac9eae8e0f8b49d8056dc5862428875c75 Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Thu, 18 Sep 2025 18:25:40 +0200 Subject: [PATCH 18/21] Removed useless OfType --- tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs b/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs index 5c7e655e134..27d9f657f00 100644 --- a/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs +++ b/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs @@ -198,10 +198,8 @@ public void TestDiscriminators() AssertDerivedPerson2(bp2, retrievedDerivedPerson2); //AppendStage with OfType - retrievedDerivedPerson1 = collection.AsQueryable().AppendStage(PipelineStageDefinitionBuilder.OfType()) - .OfType().Single(); - retrievedDerivedPerson2 = collection.AsQueryable().AppendStage(PipelineStageDefinitionBuilder.OfType()) - .OfType().Single(); + retrievedDerivedPerson1 = collection.AsQueryable().AppendStage(PipelineStageDefinitionBuilder.OfType()).Single(); + retrievedDerivedPerson2 = collection.AsQueryable().AppendStage(PipelineStageDefinitionBuilder.OfType()).Single(); AssertDerivedPerson1(bp1, retrievedDerivedPerson1); AssertDerivedPerson2(bp2, retrievedDerivedPerson2); From 48ba1a3f3feeb6bbf782a1a2e438c5c89201e41f Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Fri, 10 Oct 2025 10:48:42 +0200 Subject: [PATCH 19/21] Improved tests --- .../MultipleRegistriesTests.cs | 58 ++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs b/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs index 27d9f657f00..1915502e108 100644 --- a/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs +++ b/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs @@ -28,26 +28,29 @@ namespace MongoDB.Driver.Tests [Trait("Category", "Integration")] public class MultipleRegistriesTests { + private readonly string _defaultObjectIdString = "6797b56bf5495bf53aa3078f"; + private readonly ObjectId _defaultId = ObjectId.Parse("6797b56bf5495bf53aa3078f"); + [Fact] public void TestSerialization() { RequireServer.Check(); - // { - // var client = CreateClient(); - // var collection = GetTypedCollection(client); - // var bsonCollection = GetUntypedCollection(client); - // - // var person = new Person { Id = ObjectId.Parse("6797b56bf5495bf53aa3078f"), Name = "Mario", Age = 24 }; - // collection.InsertOne(person); - // - // var retrieved = bsonCollection.FindSync(FilterDefinition.Empty).ToList().Single(); - // var toString = retrieved.ToString(); - // - // var expectedVal = - // """{ "_id" : { "$oid" : "6797b56bf5495bf53aa3078f" }, "Name" : "Mario", "Age" : 24 }"""; - // Assert.Equal(expectedVal, toString); - // } + { + var client = CreateClient(); + var collection = GetTypedCollection(client); + var bsonCollection = GetUntypedCollection(client); + + var person = new Person { Id = _defaultId, Name = "Mario", Age = 24 }; + collection.InsertOne(person); + + var retrieved = bsonCollection.FindSync(FilterDefinition.Empty).ToList().Single(); + var toString = retrieved.ToString(); + + var expectedVal = + $$"""{ "_id" : { "$oid" : "{{_defaultObjectIdString}}" }, "Name" : "Mario", "Age" : 24 }"""; + Assert.Equal(expectedVal, toString); + } //The first section demonstrates that the class maps are also separated { @@ -58,14 +61,14 @@ public void TestSerialization() var collection = GetTypedCollection(client); var bsonCollection = GetUntypedCollection(client); - var person = new Person { Id = ObjectId.Parse("6797b56bf5495bf53aa3078f"), Name = "Mario", Age = 24 }; + var person = new Person { Id = _defaultId, Name = "Mario", Age = 24 }; collection.InsertOne(person); var retrievedAsBson = bsonCollection.FindSync(FilterDefinition.Empty).ToList().Single(); var toString = retrievedAsBson.ToString(); var expectedVal = - """{ "_id" : { "$oid" : "6797b56bf5495bf53aa3078f" }, "Name" : "Mariotest", "Age" : 24 }"""; + $$"""{ "_id" : { "$oid" : "{{_defaultObjectIdString}}" }, "Name" : "Mariotest", "Age" : 24 }"""; Assert.Equal(expectedVal, toString); var retrievedTyped = collection.FindSync(FilterDefinition.Empty).ToList().Single(); @@ -82,7 +85,7 @@ public void TestDeserialization() var client = CreateClient(); var collection = GetTypedCollection(client); - var person = new Person1 { Id = ObjectId.Parse("6797b56bf5495bf53aa3078f"), Name = "Mariotest", Age = 24 }; + var person = new Person1 { Id = _defaultId, Name = "Mariotest", Age = 24 }; collection.InsertOne(person); } @@ -110,14 +113,14 @@ public void TestLinq() var collection = GetTypedCollection(client); var untypedCollection = GetUntypedCollection(client); - var person = new Person { Id = ObjectId.Parse("6797b56bf5495bf53aa3078f"), Name = "Mario", Age = 24 }; + var person = new Person { Id = _defaultId, Name = "Mario", Age = 24 }; collection.InsertOne(person); var retrievedAsBson = untypedCollection.FindSync(FilterDefinition.Empty).ToList().Single(); var toString = retrievedAsBson.ToString(); var expectedVal = - """{ "_id" : { "$oid" : "6797b56bf5495bf53aa3078f" }, "Name" : "Mariotest", "Age" : 24 }"""; + $$"""{ "_id" : { "$oid" : "{{_defaultObjectIdString}}" }, "Name" : "Mariotest", "Age" : 24 }"""; Assert.Equal(expectedVal, toString); var retrievedTyped = collection.AsQueryable().Where(x => x.Name == "Mario").ToList(); //The string serializer is correctly serializing "Mario" to "Mariotest" @@ -152,7 +155,7 @@ public void TestConventions() var toString = retrievedAsBson.ToString(); var expectedVal = - """{ "_id" : { "$oid" : "6797b56bf5495bf53aa3078f" }, "name" : "Mario", "age" : 24 }"""; + $$"""{ "_id" : { "$oid" : "{{_defaultObjectIdString}}" }, "Name" : "Mario", "Age" : 24 }"""; Assert.Equal(expectedVal, toString); } @@ -314,7 +317,9 @@ public class DerivedPerson2 : BasePerson } - public class CustomStringSerializer : SealedClassSerializerBase //This serializer just adds "test" to any serialised string + // This serializer adds the _appended variable to any serialised string + public class CustomStringSerializer(string appended = "test") + : SealedClassSerializerBase { /// public override int GetHashCode() => 0; @@ -326,16 +331,15 @@ protected override string DeserializeValue(BsonDeserializationContext context, B var bsonType = bsonReader.GetCurrentBsonType(); return bsonType switch { - BsonType.String => bsonReader.ReadString().Replace("test", ""), + BsonType.String => bsonReader.ReadString().Replace(appended, ""), _ => throw CreateCannotDeserializeFromBsonTypeException(bsonType) }; } - protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, - string value) + protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, string value) { var bsonWriter = context.Writer; - bsonWriter.WriteString(value + "test"); + bsonWriter.WriteString(value + appended); } } @@ -343,7 +347,7 @@ public class CustomObjectIdGenerator : IIdGenerator { public object GenerateId(object container, object document) { - return ObjectId.Parse("6797b56bf5495bf53aa3078f"); + return ObjectId.Parse("6797b56bf5495bf53aa3078f"); } public bool IsEmpty(object id) From 6204c3ea906ef1373ce580aab2dd7c75ebbf8999 Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Wed, 15 Oct 2025 19:26:54 +0200 Subject: [PATCH 20/21] Fixed tests --- .../MultipleRegistriesTests.cs | 67 +++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs b/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs index 1915502e108..1b7dfb45409 100644 --- a/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs +++ b/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs @@ -36,6 +36,7 @@ public void TestSerialization() { RequireServer.Check(); + // The first section demonstrates that the class maps are also separated { var client = CreateClient(); var collection = GetTypedCollection(client); @@ -52,10 +53,9 @@ public void TestSerialization() Assert.Equal(expectedVal, toString); } - //The first section demonstrates that the class maps are also separated { var customDomain = BsonSerializer.CreateSerializationDomain(); - customDomain.RegisterSerializer(new CustomStringSerializer()); + customDomain.RegisterSerializer(new CustomStringSerializer("test1")); var client = CreateClientWithDomain(customDomain); var collection = GetTypedCollection(client); @@ -68,12 +68,71 @@ public void TestSerialization() var toString = retrievedAsBson.ToString(); var expectedVal = - $$"""{ "_id" : { "$oid" : "{{_defaultObjectIdString}}" }, "Name" : "Mariotest", "Age" : 24 }"""; + $$"""{ "_id" : { "$oid" : "{{_defaultObjectIdString}}" }, "Name" : "Mariotest1", "Age" : 24 }"""; Assert.Equal(expectedVal, toString); var retrievedTyped = collection.FindSync(FilterDefinition.Empty).ToList().Single(); Assert.Equal("Mario", retrievedTyped.Name); } + + { + var customDomain = BsonSerializer.CreateSerializationDomain(); + customDomain.RegisterSerializer(new CustomStringSerializer("test2")); + + var client = CreateClientWithDomain(customDomain); + var collection = GetTypedCollection(client); + var bsonCollection = GetUntypedCollection(client); + + var person = new Person { Id = _defaultId, Name = "Mario", Age = 24 }; + collection.InsertOne(person); + + var retrievedAsBson = bsonCollection.FindSync(FilterDefinition.Empty).ToList().Single(); + var toString = retrievedAsBson.ToString(); + + var expectedVal = + $$"""{ "_id" : { "$oid" : "{{_defaultObjectIdString}}" }, "Name" : "Mariotest2", "Age" : 24 }"""; + Assert.Equal(expectedVal, toString); + + var retrievedTyped = collection.FindSync(FilterDefinition.Empty).ToList().Single(); + Assert.Equal("Mario", retrievedTyped.Name); + } + } + + [Fact] + public void TestMultipleDomainSimultaneously() + { + RequireServer.Check(); + + var objectId1 = ObjectId.GenerateNewId(); + var objectId2 = ObjectId.GenerateNewId(); + + var client = CreateClient(); + var collection = GetTypedCollection(client); + var bsonCollection = GetUntypedCollection(client); + + var customDomain = BsonSerializer.CreateSerializationDomain(); + customDomain.RegisterSerializer(new CustomStringSerializer("test1")); + var client2 = CreateClientWithDomain(customDomain); + var collection2 = GetTypedCollection(client2); + var bsonCollection2 = GetUntypedCollection(client2); + + var person = new Person { Id = objectId1, Name = "Mario", Age = 24 }; + var person2 = new Person { Id = objectId2, Name = "Mario", Age = 24 }; + collection.InsertOne(person); + collection2.InsertOne(person2); + + var retrieved = bsonCollection.FindSync(Builders.Filter.Eq("_id", objectId1)).ToList().Single(); + var expectedVal = + $$"""{ "_id" : { "$oid" : "{{objectId1.ToString()}}" }, "Name" : "Mario", "Age" : 24 }"""; + Assert.Equal(expectedVal, retrieved.ToString()); + + var retrievedAsBson = bsonCollection2.FindSync(Builders.Filter.Eq("_id", objectId2)).ToList().Single(); + var expectedVal2 = + $$"""{ "_id" : { "$oid" : "{{objectId2.ToString()}}" }, "Name" : "Mariotest1", "Age" : 24 }"""; + Assert.Equal(expectedVal2, retrievedAsBson.ToString()); + + var retrievedTyped = collection2.FindSync(p => p.Id == objectId2).ToList().Single(); + Assert.Equal("Mario", retrievedTyped.Name); } [Fact] @@ -155,7 +214,7 @@ public void TestConventions() var toString = retrievedAsBson.ToString(); var expectedVal = - $$"""{ "_id" : { "$oid" : "{{_defaultObjectIdString}}" }, "Name" : "Mario", "Age" : 24 }"""; + $$"""{ "_id" : { "$oid" : "{{_defaultObjectIdString}}" }, "name" : "Mario", "Age" : 24 }"""; Assert.Equal(expectedVal, toString); } From c7537c6b83d64e0d2eb795456d58ef708190353c Mon Sep 17 00:00:00 2001 From: Ferdinando Papale <4850119+papafe@users.noreply.github.com> Date: Thu, 16 Oct 2025 09:47:58 +0200 Subject: [PATCH 21/21] Corrected test --- tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs b/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs index 1b7dfb45409..d0a79134432 100644 --- a/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs +++ b/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs @@ -214,7 +214,7 @@ public void TestConventions() var toString = retrievedAsBson.ToString(); var expectedVal = - $$"""{ "_id" : { "$oid" : "{{_defaultObjectIdString}}" }, "name" : "Mario", "Age" : 24 }"""; + $$"""{ "_id" : { "$oid" : "{{_defaultObjectIdString}}" }, "name" : "Mario", "age" : 24 }"""; Assert.Equal(expectedVal, toString); }