diff --git a/src/MongoDB.Bson/BsonDefaults.cs b/src/MongoDB.Bson/BsonDefaults.cs index 9352d3228ff..9a6cbf40bdb 100644 --- a/src/MongoDB.Bson/BsonDefaults.cs +++ b/src/MongoDB.Bson/BsonDefaults.cs @@ -13,9 +13,6 @@ * limitations under the License. */ -using System; -using System.Collections.Generic; -using System.Dynamic; using MongoDB.Bson.Serialization; namespace MongoDB.Bson { @@ -24,33 +21,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 +36,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 DynamicSerializer are used only in a handful of serializers, so they should be removed from here (and possibly from the public API altogether). + * MaxDocumentSize should probably be removed from the public API too, as it should come from the server. + * MaxSerializationDepeth is definitely usedful. Does it make sense to keep it global...? + */ + /// /// 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 +59,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..09b317f6dc8 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 all the methods that do not take a serialization domain. + //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. /// @@ -41,12 +43,21 @@ public static byte[] ToBson( IBsonSerializer serializer = null, BsonBinaryWriterSettings writerSettings = null, Action configurator = null, - BsonSerializationArgs args = default(BsonSerializationArgs), + BsonSerializationArgs args = default, + int estimatedBsonSize = 0) => ToBson(obj, BsonSerializer.DefaultSerializationDomain, serializer, writerSettings, configurator, args, estimatedBsonSize); + + private static byte[] ToBson( + this TNominalType obj, + IBsonSerializationDomain serializationDomain, + IBsonSerializer serializer = null, + BsonBinaryWriterSettings writerSettings = null, + Action configurator = null, + BsonSerializationArgs args = default, int estimatedBsonSize = 0) { args.SetOrValidateNominalType(typeof(TNominalType), ""); - return ToBson(obj, typeof(TNominalType), writerSettings, serializer, configurator, args, estimatedBsonSize); + return ToBson(obj, typeof(TNominalType), serializationDomain, writerSettings, serializer, configurator, args, estimatedBsonSize); } /// @@ -68,7 +79,18 @@ public static byte[] ToBson( BsonBinaryWriterSettings writerSettings = null, IBsonSerializer serializer = null, Action configurator = null, - BsonSerializationArgs args = default(BsonSerializationArgs), + BsonSerializationArgs args = default, + int estimatedBsonSize = 0) => ToBson(obj, nominalType, BsonSerializer.DefaultSerializationDomain, writerSettings, + serializer, configurator, args, estimatedBsonSize); + + private static byte[] ToBson( + this object obj, + Type nominalType, + IBsonSerializationDomain serializationDomain, + BsonBinaryWriterSettings writerSettings = null, + IBsonSerializer serializer = null, + Action configurator = null, + BsonSerializationArgs args = default, int estimatedBsonSize = 0) { if (estimatedBsonSize < 0) @@ -84,7 +106,7 @@ public static byte[] ToBson( if (serializer == null) { - serializer = BsonSerializer.LookupSerializer(nominalType); + serializer = serializationDomain.LookupSerializer(nominalType); } if (serializer.ValueType != nominalType) { @@ -96,7 +118,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(); @@ -116,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); @@ -138,7 +160,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); + + private static BsonDocument ToBsonDocument( + this object obj, + Type nominalType, + IBsonSerializationDomain serializationDomain, + IBsonSerializer serializer = null, + Action configurator = null, + BsonSerializationArgs args = default) { if (nominalType == null) { @@ -165,7 +196,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 +208,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; @@ -200,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); @@ -226,7 +257,17 @@ public static string ToJson( JsonWriterSettings writerSettings = null, IBsonSerializer serializer = null, Action configurator = null, - BsonSerializationArgs args = default(BsonSerializationArgs)) + BsonSerializationArgs args = default) + => ToJson(obj, nominalType, BsonSerializer.DefaultSerializationDomain, writerSettings, serializer, configurator, args); + + private static string ToJson( + this object obj, + Type nominalType, + IBsonSerializationDomain domain, + JsonWriterSettings writerSettings = null, + IBsonSerializer serializer = null, + Action configurator = null, + BsonSerializationArgs args = default) { if (nominalType == null) { @@ -236,7 +277,7 @@ public static string ToJson( if (serializer == null) { - serializer = BsonSerializer.LookupSerializer(nominalType); + serializer = domain.LookupSerializer(nominalType); } if (serializer.ValueType != nominalType) { @@ -248,7 +289,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/BsonReader.cs b/src/MongoDB.Bson/IO/BsonReader.cs index 25724b855e7..d3b4d3bfaa7 100644 --- a/src/MongoDB.Bson/IO/BsonReader.cs +++ b/src/MongoDB.Bson/IO/BsonReader.cs @@ -321,13 +321,13 @@ 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); + 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); + 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 +351,7 @@ 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); + 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/BsonWriter.cs b/src/MongoDB.Bson/IO/BsonWriter.cs index 3fd705fa31b..fd166783f01 100644 --- a/src/MongoDB.Bson/IO/BsonWriter.cs +++ b/src/MongoDB.Bson/IO/BsonWriter.cs @@ -326,13 +326,13 @@ public virtual void WriteRawBsonArray(IByteBuffer slice) stream.Position = 0; using (var reader = new BsonBinaryReader(stream, BsonBinaryReaderSettings.Defaults)) { - var deserializationContext = BsonDeserializationContext.CreateRoot(reader); + 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); + var serializationContext = BsonSerializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain); BsonArraySerializer.Instance.Serialize(serializationContext, array); } } @@ -350,10 +350,10 @@ 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); + var deserializationContext = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); var document = BsonDocumentSerializer.Instance.Deserialize(deserializationContext); - var serializationContext = BsonSerializationContext.CreateRoot(this); + 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 0e83adcdb91..9cf9b3c2d28 100644 --- a/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs +++ b/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs @@ -60,7 +60,7 @@ public override void WriteEndDocument() Wrapped.PushSettings(_settingsConfigurator); try { - var context = BsonSerializationContext.CreateRoot(Wrapped); + 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..9cf7e26f22f 100644 --- a/src/MongoDB.Bson/IO/IBsonReader.cs +++ b/src/MongoDB.Bson/IO/IBsonReader.cs @@ -17,6 +17,8 @@ namespace MongoDB.Bson.IO { + //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/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..f4ffd777487 100644 --- a/src/MongoDB.Bson/ObjectModel/BsonDocument.cs +++ b/src/MongoDB.Bson/ObjectModel/BsonDocument.cs @@ -331,7 +331,7 @@ public static BsonDocument Parse(string json) { using (var jsonReader = new JsonReader(json)) { - var context = BsonDeserializationContext.CreateRoot(jsonReader); + 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..1d5dfd3f9a6 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 versions without the domain should be removed. // public static methods /// /// Creates a new instance of the BsonDocumentWrapper class. @@ -91,9 +94,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,10 +108,13 @@ 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); + + private static BsonDocumentWrapper Create(Type nominalType, object value, IBsonSerializationDomain domain) { - var serializer = BsonSerializer.LookupSerializer(nominalType); - return new BsonDocumentWrapper(value, serializer); + var serializer = domain.LookupSerializer(nominalType); + return new BsonDocumentWrapper(value, serializer, domain); } /// @@ -114,15 +123,18 @@ 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); + + private static IEnumerable CreateMultiple(IEnumerable values, IBsonSerializationDomain domain) { if (values == null) { throw new ArgumentNullException("values"); } - var serializer = BsonSerializer.LookupSerializer(typeof(TNominalType)); - return values.Select(v => new BsonDocumentWrapper(v, serializer)); + var serializer = domain.LookupSerializer(typeof(TNominalType)); + return values.Select(v => new BsonDocumentWrapper(v, serializer, domain)); } /// @@ -131,7 +143,10 @@ 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); + + private static IEnumerable CreateMultiple(Type nominalType, IEnumerable values, IBsonSerializationDomain domain) { if (nominalType == null) { @@ -142,8 +157,8 @@ public static IEnumerable CreateMultiple(Type nominalType, throw new ArgumentNullException("values"); } - var serializer = BsonSerializer.LookupSerializer(nominalType); - return values.Cast().Select(v => new BsonDocumentWrapper(v, serializer)); + var serializer = domain.LookupSerializer(nominalType); + return values.Cast().Select(v => new BsonDocumentWrapper(v, serializer, domain)); } // public methods @@ -163,7 +178,8 @@ public override BsonValue Clone() { return new BsonDocumentWrapper( _wrapped, - _serializer); + _serializer, + _serializationDomain); } } @@ -178,7 +194,7 @@ protected override IEnumerable Materialize() var writerSettings = BsonDocumentWriterSettings.Defaults; using (var bsonWriter = new BsonDocumentWriter(bsonDocument, writerSettings)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, _serializationDomain); _serializer.Serialize(context, _wrapped); } diff --git a/src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs b/src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs index f9232489f4f..3ca066512e1 100644 --- a/src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs +++ b/src/MongoDB.Bson/ObjectModel/LazyBsonArray.cs @@ -173,7 +173,7 @@ private IEnumerable MaterializeThisLevel() using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + 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..aa0d5526db7 100644 --- a/src/MongoDB.Bson/ObjectModel/LazyBsonDocument.cs +++ b/src/MongoDB.Bson/ObjectModel/LazyBsonDocument.cs @@ -184,7 +184,7 @@ private IEnumerable MaterializeThisLevel() using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + 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..9778f9d116c 100644 --- a/src/MongoDB.Bson/ObjectModel/RawBsonArray.cs +++ b/src/MongoDB.Bson/ObjectModel/RawBsonArray.cs @@ -128,7 +128,7 @@ public override IEnumerable Values using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -167,7 +167,7 @@ public override BsonValue this[int index] bsonReader.SkipName(); if (i == index) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); return DeserializeBsonValue(context); } @@ -314,7 +314,7 @@ 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); + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -342,7 +342,7 @@ 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); + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -383,7 +383,7 @@ public override IEnumerator GetEnumerator() using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -429,7 +429,7 @@ 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); + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); var i = 0; @@ -489,7 +489,7 @@ public BsonArray Materialize(BsonBinaryReaderSettings binaryReaderSettings) using (var stream = new MemoryStream(bytes)) using (var reader = new BsonBinaryReader(stream, binaryReaderSettings)) { - var context = BsonDeserializationContext.CreateRoot(reader); + 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..56cca2d0cdf 100644 --- a/src/MongoDB.Bson/ObjectModel/RawBsonDocument.cs +++ b/src/MongoDB.Bson/ObjectModel/RawBsonDocument.cs @@ -102,7 +102,7 @@ public override IEnumerable Elements using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -164,7 +164,7 @@ public override IEnumerable Values using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -352,7 +352,7 @@ 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); + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -408,7 +408,7 @@ 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); + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); var i = 0; @@ -463,7 +463,7 @@ public override IEnumerator GetEnumerator() using (var stream = new ByteBufferStream(_slice, ownsBuffer: false)) using (var bsonReader = new BsonBinaryReader(stream, _readerSettings)) { - var context = BsonDeserializationContext.CreateRoot(bsonReader); + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -494,7 +494,7 @@ 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); + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); var i = 0; @@ -576,7 +576,7 @@ 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); + var context = BsonDeserializationContext.CreateRoot(reader, BsonSerializer.DefaultSerializationDomain); return BsonDocumentSerializer.Instance.Deserialize(context); } } @@ -699,7 +699,7 @@ 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); + var context = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain); bsonReader.ReadStartDocument(); while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) @@ -734,7 +734,7 @@ 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); + 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..40f3a0f9929 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 serializationDomain) + { + var freezeContext = new FreezeContext { SerializationDomain = serializationDomain }; + 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..37f1826f22f 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,9 @@ 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; } // public properties @@ -54,6 +60,11 @@ public bool AllowDuplicateElementNames get { return _allowDuplicateElementNames; } } + /// + /// //TODO + /// + internal IBsonSerializationDomain SerializationDomain => _serializationDomain; + /// /// Gets the dynamic array serializer. /// @@ -87,6 +98,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 +111,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 +137,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 +156,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,6 +167,7 @@ internal Builder(BsonDeserializationContext other, IBsonReader reader) } _reader = reader; + _serializationDomain = serializationDomain; if (other != null) { _allowDuplicateElementNames = other.AllowDuplicateElementNames; @@ -156,8 +176,8 @@ internal Builder(BsonDeserializationContext other, IBsonReader reader) } else { - _dynamicArraySerializer = BsonDefaults.DynamicArraySerializer; - _dynamicDocumentSerializer = BsonDefaults.DynamicDocumentSerializer; + _dynamicArraySerializer = serializationDomain.BsonDefaults.DynamicArraySerializer; + _dynamicDocumentSerializer = serializationDomain.BsonDefaults.DynamicDocumentSerializer; } } @@ -209,6 +229,8 @@ public IBsonReader Reader get { return _reader; } } + internal IBsonSerializationDomain SerializationDomain => _serializationDomain; + // public methods /// /// Builds the BsonDeserializationContext instance. @@ -216,7 +238,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..21316fcee54 100644 --- a/src/MongoDB.Bson/Serialization/BsonMemberMap.cs +++ b/src/MongoDB.Bson/Serialization/BsonMemberMap.cs @@ -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..42225737ce6 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); - } + + /* 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. + */ } // 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..31d2e983539 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,7 @@ public object DeserializeValue(BsonValue value) var tempDocument = new BsonDocument("value", value); using (var reader = new BsonDocumentReader(tempDocument)) { - var context = BsonDeserializationContext.CreateRoot(reader); + var context = BsonDeserializationContext.CreateRoot(reader, BsonSerializer.DefaultSerializationDomain); reader.ReadStartDocument(); reader.ReadName("value"); var deserializedValue = _serializer.Deserialize(context); @@ -144,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. /// @@ -154,7 +169,7 @@ public BsonValue SerializeValue(object value) var tempDocument = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(tempDocument)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("value"); _serializer.Serialize(context, value); @@ -163,6 +178,7 @@ public BsonValue SerializeValue(object value) } } + //DOMAIN-API This method should be probably removed, it's never used. /// /// Serializes the values. /// @@ -173,7 +189,7 @@ public BsonArray SerializeValues(IEnumerable values) var tempDocument = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(tempDocument)) { - var context = BsonSerializationContext.CreateRoot(bsonWriter); + var context = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("values"); bsonWriter.WriteStartArray(); @@ -188,6 +204,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/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..c792c9d5839 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,17 @@ 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 + //FP TODO: This is used only for testing, it can be removed later. + internal static IBsonSerializationDomain CreateSerializationDomain() => new BsonSerializationDomain(); + /// /// Deserializes an object from a BsonDocument. /// @@ -97,12 +75,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 +85,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 +95,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 +105,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 +115,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 +125,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 +135,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 +145,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 +155,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 +165,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 +175,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 +185,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 +199,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 +208,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 +216,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 +224,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 +246,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 +254,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 +270,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 +285,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 +293,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 +307,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 +324,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 +333,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 +342,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..46aecd27b31 --- /dev/null +++ b/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs @@ -0,0 +1,332 @@ +/* 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; +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..d93b10d544f 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,12 @@ 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; } + + IBsonSerializer GetSerializerWithDomain(Type type); + } } diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs b/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs index fd5998c93b3..b0fc03e3800 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,7 @@ public static BsonValue ToBsonValue(this IBsonSerializer serializer, object valu var document = new BsonDocument(); using (var writer = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(writer); + var context = BsonSerializationContext.CreateRoot(writer, BsonSerializer.DefaultSerializationDomain); writer.WriteStartDocument(); writer.WriteName("x"); serializer.Serialize(context, value); @@ -117,7 +125,7 @@ public static BsonValue ToBsonValue(this IBsonSerializer seriali var document = new BsonDocument(); using (var writer = new BsonDocumentWriter(document)) { - var context = BsonSerializationContext.CreateRoot(writer); + 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..1fd027bf286 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. /// @@ -260,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); } @@ -268,12 +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)) { - var context = BsonDeserializationContext.CreateRoot(keyReader); + var context = BsonDeserializationContext.CreateRoot(keyReader, serializationDomain); keyReader.ReadStartDocument(); keyReader.ReadName("k"); var key = _keySerializer.Deserialize(context); @@ -318,18 +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)) { - var context = BsonSerializationContext.CreateRoot(keyWriter); + var context = BsonSerializationContext.CreateRoot(keyWriter, serializationDomain); keyWriter.WriteStartDocument(); keyWriter.WriteName("k"); _keySerializer.Serialize(context, key); @@ -373,6 +375,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 +384,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. /// @@ -662,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)); } @@ -671,12 +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)) { - var context = BsonDeserializationContext.CreateRoot(keyReader); + var context = BsonDeserializationContext.CreateRoot(keyReader, serializationDomain); keyReader.ReadStartDocument(); keyReader.ReadName("k"); var key = _lazyKeySerializer.Value.Deserialize(context); @@ -721,18 +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)) { - var context = BsonSerializationContext.CreateRoot(keyWriter); + var context = BsonSerializationContext.CreateRoot(keyWriter, serializationDomain); 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..3b11d10a101 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs @@ -41,23 +41,25 @@ 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 // 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 /// @@ -75,7 +77,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,26 +111,13 @@ public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorCo } _interfaceType = typeof(TInterface); - _discriminatorConvention = discriminatorConvention ?? interfaceSerializer.GetDiscriminatorConvention(); + _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(); - 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.GetActualType(bsonReader, typeof(TInterface)); + 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); @@ -178,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); } @@ -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; + } } } 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..638df6a4789 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/TupleSerializers.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/TupleSerializers.cs @@ -109,6 +109,7 @@ 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. @@ -208,7 +209,7 @@ public sealed class TupleSerializer : SealedClassSerializerBase class. /// public TupleSerializer() - : this(BsonSerializer.SerializerRegistry) + : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is { } @@ -318,7 +319,7 @@ public sealed class TupleSerializer : SealedClassSerializerBase class. /// public TupleSerializer() - : this(BsonSerializer.SerializerRegistry) + : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is { } @@ -443,7 +444,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 +586,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 +744,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 +918,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 +1108,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..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); + 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); + 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; + 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); + 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/AggregateExpressionDefinition.cs b/src/MongoDB.Driver/AggregateExpressionDefinition.cs index 85ae3f37e6a..7add6ae43a7 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); } } @@ -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/Authentication/MongoDBX509Authenticator.cs b/src/MongoDB.Driver/Authentication/MongoDBX509Authenticator.cs index 68d3379bb4b..fc5f5ce2b7b 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); return protocol; } diff --git a/src/MongoDB.Driver/Authentication/Oidc/AzureOidcCallback.cs b/src/MongoDB.Driver/Authentication/Oidc/AzureOidcCallback.cs index 8b4c3100ee0..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); + 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/Authentication/SaslAuthenticator.cs b/src/MongoDB.Driver/Authentication/SaslAuthenticator.cs index 96209fd8d9b..ab2b6a60425 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); 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/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/Bindings/CoreSession.cs b/src/MongoDB.Driver/Core/Bindings/CoreSession.cs index 954c639e244..f01d7594f03 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; @@ -453,7 +454,8 @@ private IReadOperation CreateCommitTransactionOperation(OperationC { var writeConcern = GetCommitTransactionWriteConcern(operationContext, isCommitRetry); var maxCommitTime = _currentTransaction.TransactionOptions.MaxCommitTime; - return new CommitTransactionOperation(_currentTransaction.RecoveryToken, writeConcern) { MaxCommitTime = maxCommitTime }; + //We only use BsonDocumentSerializer with the domain, so using the default one is fine. + 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..00cd4734e82 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); return getLastErrorProtocol; } diff --git a/src/MongoDB.Driver/Core/Connections/HelloHelper.cs b/src/MongoDB.Driver/Core/Connections/HelloHelper.cs index ee5a8caae9e..4382c8f969f 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); //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/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..c19753c83b3 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,23 +45,37 @@ 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; } + //EXIT + public AggregateToCollectionOperation(CollectionNamespace collectionNamespace, IEnumerable pipeline, MessageEncoderSettings messageEncoderSettings) + : this(collectionNamespace, pipeline, messageEncoderSettings, BsonSerializer.DefaultSerializationDomain) + { + } + public bool? AllowDiskUse { get { return _allowDiskUse; } @@ -205,7 +220,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..f325b125986 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,6 +35,7 @@ internal sealed class CreateSearchIndexesOperation : IWriteOperation _requests; + private readonly IBsonSerializationDomain _serializationDomain; // constructors /// @@ -42,14 +44,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 +93,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..1e908fe8a7c 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 @@ -182,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) @@ -197,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 }; } @@ -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); } } @@ -374,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/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/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, 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..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,13 +29,13 @@ internal sealed class ClientBulkWriteOpsSectionFormatter : ICommandMessageSectio { private readonly long? _maxSize; private readonly Dictionary _nsInfos; + private readonly IBsonSerializationDomain _serializationDomain; private MemoryStream _nsInfoMemoryStream; private BsonBinaryWriter _nsInfoWriter; - private IBsonSerializerRegistry _serializerRegistry; 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..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,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(); + // 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); // 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..3606b5fc91c 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,9 @@ protected int? MaxWireDocumentSize } } + protected IBsonSerializationDomain SerializationDomain + => _encoderSettings?.GetOrDefault(MessageEncoderSettingsName.SerializationDomain, null) ?? BsonSerializer.DefaultSerializationDomain; + // 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..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 @@ -85,7 +88,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 +159,7 @@ private void WriteOptionalFields(BsonBinaryWriter binaryWriter, BsonDocument fie { if (fields != null) { - var context = BsonSerializationContext.CreateRoot(binaryWriter); + var context = BsonSerializationContext.CreateRoot(binaryWriter, BsonSerializer.DefaultSerializationDomain); BsonDocumentSerializer.Instance.Serialize(context, fields); } } @@ -169,7 +172,7 @@ private void WriteQuery(BsonBinaryWriter binaryWriter, BsonDocument query, IElem binaryWriter.PushElementNameValidator(queryValidator); try { - var context = BsonSerializationContext.CreateRoot(binaryWriter); + 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 d785716b2df..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 @@ -60,7 +62,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 +71,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 +126,14 @@ public void WriteMessage(ReplyMessage message) stream.WriteInt32(message.NumberReturned); if (message.QueryFailure) { - var context = BsonSerializationContext.CreateRoot(binaryWriter); + var context = BsonSerializationContext.CreateRoot(binaryWriter, _serializationDomain); _serializer.Serialize(context, message.QueryFailureDocument); } else { foreach (var doc in message.Documents) { - var context = BsonSerializationContext.CreateRoot(binaryWriter); + var context = BsonSerializationContext.CreateRoot(binaryWriter, _serializationDomain); _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..81ade7809ed 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) { + // 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); } // 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..9ff7c4b97a6 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,20 @@ 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; } // 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 +104,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..834e85f6c87 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); } @@ -102,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); } @@ -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..e9d1af98cd2 100644 --- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs +++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs @@ -41,6 +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); + //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/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..8ea1f885fc2 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); } } } @@ -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/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..f3f95ab1623 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); @@ -93,13 +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); + var documentContext = + BsonSerializationContext.CreateRoot(documentWriter, context.SerializationDomain); 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..8b33b6a77f2 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,17 +100,17 @@ 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; - 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); @@ -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..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); + 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); + var context = BsonSerializationContext.CreateRoot(writer, serializationDomain); 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/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/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..b3af43d6200 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); @@ -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/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/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/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..3310552d39e 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); @@ -578,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}."); @@ -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/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/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/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/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/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/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/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/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/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/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/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/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..a433fff76d3 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/DocumentsMethodToPipelineTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToPipelineTranslators/DocumentsMethodToPipelineTranslator.cs @@ -58,10 +58,10 @@ 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); + 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/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/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/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..49e264282a5 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,20 @@ public ReadPreference ReadPreference } } + IBsonSerializationDomain IInheritableMongoClientSettings.SerializationDomain + { + 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 +961,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..d16684439d3 100644 --- a/src/MongoDB.Driver/MongoCollectionImpl.cs +++ b/src/MongoDB.Driver/MongoCollectionImpl.cs @@ -677,9 +677,9 @@ 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)) + 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, @@ -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, @@ -1004,9 +1010,10 @@ 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) + _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..7e2bba031f1 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,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; + set + { + if (_isFrozen) { throw new InvalidOperationException("MongoCollectionSettings is frozen."); } + if (value == null) + { + throw new ArgumentNullException("value"); + } + _serializationDomain.Value = value; + } } /// @@ -180,6 +195,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 +335,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..4fa0f0fd35e 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; + 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..b5059b70bce 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))); + } + 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..1936c46c8c3 100644 --- a/src/MongoDB.Driver/ProjectionDefinition.cs +++ b/src/MongoDB.Driver/ProjectionDefinition.cs @@ -277,11 +277,11 @@ public override RenderedProjectionDefinition 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/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/RenderArgs.cs b/src/MongoDB.Driver/RenderArgs.cs index 1f6e2452a23..3645d66d06e 100644 --- a/src/MongoDB.Driver/RenderArgs.cs +++ b/src/MongoDB.Driver/RenderArgs.cs @@ -38,7 +38,9 @@ public record struct 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. /// @@ -53,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) @@ -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 = false, + 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 //DOMAIN-API: we should probably remove this property and use the domain directly { 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/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); } 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/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/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..26414195148 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. /// @@ -240,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); } } } 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..e1e2b33275e --- /dev/null +++ b/tests/MongoDB.Driver.Tests/MultipleRegistriesTests.cs @@ -0,0 +1,517 @@ +/* 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 + { + private readonly string _defaultObjectIdString = "6797b56bf5495bf53aa3078f"; + private readonly ObjectId _defaultId = ObjectId.Parse("6797b56bf5495bf53aa3078f"); + + [Fact] + public void TestSerialization() + { + RequireServer.Check(); + + // The first section demonstrates that the class maps are also separated + { + 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); + } + + { + var customDomain = BsonSerializer.CreateSerializationDomain(); + customDomain.RegisterSerializer(new CustomStringSerializer("test1")); + + 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" : "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] + public void TestDeserialization() + { + RequireServer.Check(); + + { + var client = CreateClient(); + var collection = GetTypedCollection(client); + + var person = new Person1 { Id = _defaultId, 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 = _defaultId, Name = "Mario", Age = 24 }; + collection.InsertOne(person); + + var retrievedAsBson = untypedCollection.FindSync(FilterDefinition.Empty).ToList().Single(); + var toString = retrievedAsBson.ToString(); + + var expectedVal = + $$"""{ "_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" + 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" : "{{_defaultObjectIdString}}" }, "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.SetDiscriminator("bp"); + 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 untypedCollection = GetUntypedCollection(client); + + var bp1 = new DerivedPerson1 { Name = "Alice", Age = 30, ExtraField1 = "Field1" }; + var bp2 = new DerivedPerson2 { Name = "Bob", Age = 40, ExtraField2 = "Field2" }; + collection.InsertMany([bp1, bp2]); + + var retrieved1 = untypedCollection.FindSync(Builders.Filter.Eq("_id", bp1.Id)).ToList().Single(); + var retrieved2 = untypedCollection.FindSync(Builders.Filter.Eq("_id", bp2.Id)).ToList().Single(); + + var expectedDiscriminator1 = + $"""_t" : ["bp", "dp1"]"""; + var expectedDiscriminator2 = + $"""_t" : ["bp", "dp2"]"""; + Assert.Contains(expectedDiscriminator1, retrieved1.ToString()); + Assert.Contains(expectedDiscriminator2, retrieved2.ToString()); + + //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()).Single(); + retrievedDerivedPerson2 = collection.AsQueryable().AppendStage(PipelineStageDefinitionBuilder.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); + } + } + + [Fact] + public void TestDiscriminatorsWithAttributes() + { + RequireServer.Check(); + + var customDomain = BsonSerializer.CreateSerializationDomain(); + customDomain.RegisterSerializer(new CustomStringSerializer()); + + var client = CreateClientWithDomain(customDomain); + var collection = GetTypedCollection(client); + var untypedCollection = GetUntypedCollection(client); + + var bp1 = new DerivedPersonAttribute1 { Name = "Alice", Age = 30, ExtraField1 = "Field1" }; + var bp2 = new DerivedPersonAttribute2 { Name = "Bob", Age = 40, ExtraField2 = "Field2" }; + collection.InsertMany([bp1, bp2]); + + var retrieved1 = untypedCollection.FindSync(Builders.Filter.Eq("_id", bp1.Id)).ToList().Single(); + var retrieved2 = untypedCollection.FindSync(Builders.Filter.Eq("_id", bp2.Id)).ToList().Single(); + + var expectedDiscriminator1 = + $"""_t" : ["bp", "dp1"]"""; + var expectedDiscriminator2 = + $"""_t" : ["bp", "dp2"]"""; + Assert.Contains(expectedDiscriminator1, retrieved1.ToString()); + Assert.Contains(expectedDiscriminator2, retrieved2.ToString()); + + //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()).Single(); + retrievedDerivedPerson2 = collection.AsQueryable().AppendStage(PipelineStageDefinitionBuilder.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); + + + void AssertDerivedPerson1(DerivedPersonAttribute1 expected, DerivedPersonAttribute1 retrieved) + { + AssertBasePerson(expected, retrieved); + Assert.Equal(expected.ExtraField1, retrieved.ExtraField1); + } + + void AssertDerivedPerson2(DerivedPersonAttribute2 expected, DerivedPersonAttribute2 retrieved) + { + AssertBasePerson(expected, retrieved); + Assert.Equal(expected.ExtraField2, retrieved.ExtraField2); + } + + void AssertBasePerson(BasePersonAttribute expected, BasePersonAttribute 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; } + } + + [BsonDiscriminator("bp", RootClass = true)] + public class BasePersonAttribute + { + [BsonId] public ObjectId Id { get; set; } = ObjectId.GenerateNewId(); + public string Name { get; set; } + public int Age { get; set; } + } + + [BsonDiscriminator("dp1")] + public class DerivedPersonAttribute1 : BasePersonAttribute + { + public string ExtraField1 { get; set; } + } + + [BsonDiscriminator("dp2")] + public class DerivedPersonAttribute2 : BasePersonAttribute + { + public string ExtraField2 { get; set; } + } + + // This serializer adds the _appended variable to any serialised string + public class CustomStringSerializer(string appended = "test") + : SealedClassSerializerBase + { + /// + 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(appended, ""), + _ => throw CreateCannotDeserializeFromBsonTypeException(bsonType) + }; + } + + protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, string value) + { + var bsonWriter = context.Writer; + bsonWriter.WriteString(value + appended); + } + } + + 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