diff --git a/src/MongoDB.Bson/BsonDefaults.cs b/src/MongoDB.Bson/BsonDefaults.cs
index 9352d3228ff..47c01789356 100644
--- a/src/MongoDB.Bson/BsonDefaults.cs
+++ b/src/MongoDB.Bson/BsonDefaults.cs
@@ -24,33 +24,14 @@ namespace MongoDB.Bson
///
public static class BsonDefaults
{
- // private static fields
- private static bool __dynamicArraySerializerWasSet;
- private static IBsonSerializer __dynamicArraySerializer;
- private static bool __dynamicDocumentSerializerWasSet;
- private static IBsonSerializer __dynamicDocumentSerializer;
- private static int __maxDocumentSize = int.MaxValue;
- private static int __maxSerializationDepth = 100;
-
// public static properties
///
/// Gets or sets the dynamic array serializer.
///
public static IBsonSerializer DynamicArraySerializer
{
- get
- {
- if (!__dynamicArraySerializerWasSet)
- {
- __dynamicArraySerializer = BsonSerializer.LookupSerializer>();
- }
- return __dynamicArraySerializer;
- }
- set
- {
- __dynamicArraySerializerWasSet = true;
- __dynamicArraySerializer = value;
- }
+ get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicArraySerializer;
+ set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicArraySerializer = value;
}
///
@@ -58,28 +39,22 @@ public static IBsonSerializer DynamicArraySerializer
///
public static IBsonSerializer DynamicDocumentSerializer
{
- get
- {
- if (!__dynamicDocumentSerializerWasSet)
- {
- __dynamicDocumentSerializer = BsonSerializer.LookupSerializer();
- }
- return __dynamicDocumentSerializer;
- }
- set
- {
- __dynamicDocumentSerializerWasSet = true;
- __dynamicDocumentSerializer = value;
- }
+ get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicDocumentSerializer;
+ set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicDocumentSerializer = value;
}
+ /* DOMAIN-API We should modify the API to have those two values (and in the writer/reader settings where they are used) be nullable.
+ * The problem is that we need to now when these values have been set externally or not. If they have not, then they should
+ * be retrieved from the closest domain.
+ */
+
///
/// Gets or sets the default max document size. The default is 4MiB.
///
public static int MaxDocumentSize
{
- get { return __maxDocumentSize; }
- set { __maxDocumentSize = value; }
+ get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxDocumentSize;
+ set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxDocumentSize = value;
}
///
@@ -87,8 +62,8 @@ public static int MaxDocumentSize
///
public static int MaxSerializationDepth
{
- get { return __maxSerializationDepth; }
- set { __maxSerializationDepth = value; }
+ get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxSerializationDepth;
+ set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxSerializationDepth = value;
}
}
}
diff --git a/src/MongoDB.Bson/BsonDefaultsDomain.cs b/src/MongoDB.Bson/BsonDefaultsDomain.cs
new file mode 100644
index 00000000000..b105e739374
--- /dev/null
+++ b/src/MongoDB.Bson/BsonDefaultsDomain.cs
@@ -0,0 +1,73 @@
+/* Copyright 2010-present MongoDB Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.Collections.Generic;
+using System.Dynamic;
+using MongoDB.Bson.Serialization;
+
+namespace MongoDB.Bson
+{
+ internal class BsonDefaultsDomain : IBsonDefaults
+ {
+ private IBsonSerializationDomain _serializationDomain;
+ private bool _dynamicArraySerializerWasSet;
+ private IBsonSerializer _dynamicArraySerializer;
+ private bool _dynamicDocumentSerializerWasSet;
+ private IBsonSerializer _dynamicDocumentSerializer;
+
+ public BsonDefaultsDomain(IBsonSerializationDomain serializationDomain)
+ {
+ _serializationDomain = serializationDomain;
+ }
+
+ public IBsonSerializer DynamicArraySerializer
+ {
+ get
+ {
+ if (!_dynamicArraySerializerWasSet)
+ {
+ _dynamicArraySerializer = _serializationDomain.LookupSerializer>();
+ }
+ return _dynamicArraySerializer;
+ }
+ set
+ {
+ _dynamicArraySerializerWasSet = true;
+ _dynamicArraySerializer = value;
+ }
+ }
+
+ public IBsonSerializer DynamicDocumentSerializer
+ {
+ get
+ {
+ if (!_dynamicDocumentSerializerWasSet)
+ {
+ _dynamicDocumentSerializer = _serializationDomain.LookupSerializer();
+ }
+ return _dynamicDocumentSerializer;
+ }
+ set
+ {
+ _dynamicDocumentSerializerWasSet = true;
+ _dynamicDocumentSerializer = value;
+ }
+ }
+
+ public int MaxDocumentSize { get; set; } = int.MaxValue;
+
+ public int MaxSerializationDepth { get; set; } = 100;
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/BsonExtensionMethods.cs b/src/MongoDB.Bson/BsonExtensionMethods.cs
index bcb41a8271f..d78db9a54d9 100644
--- a/src/MongoDB.Bson/BsonExtensionMethods.cs
+++ b/src/MongoDB.Bson/BsonExtensionMethods.cs
@@ -25,6 +25,8 @@ namespace MongoDB.Bson
///
public static class BsonExtensionMethods
{
+ //DOMAIN-API We should remove this and use the version with the domain.
+ //QUESTION: Do we want to do something now about this...? It's used also internally, but it seems in most cases it's used for "default serialization", so it should be ok.
///
/// Serializes an object to a BSON byte array.
///
@@ -49,6 +51,21 @@ public static byte[] ToBson(
return ToBson(obj, typeof(TNominalType), writerSettings, serializer, configurator, args, estimatedBsonSize);
}
+ internal static byte[] ToBson(
+ this TNominalType obj,
+ IBsonSerializationDomain serializationDomain,
+ IBsonSerializer serializer = null,
+ BsonBinaryWriterSettings writerSettings = null,
+ Action configurator = null,
+ BsonSerializationArgs args = default(BsonSerializationArgs),
+ int estimatedBsonSize = 0)
+ {
+ args.SetOrValidateNominalType(typeof(TNominalType), "");
+
+ return ToBson(obj, typeof(TNominalType), serializationDomain, writerSettings, serializer, configurator, args, estimatedBsonSize);
+ }
+
+ //DOMAIN-API We should remove this and use the version with the domain.
///
/// Serializes an object to a BSON byte array.
///
@@ -68,6 +85,17 @@ public static byte[] ToBson(
BsonBinaryWriterSettings writerSettings = null,
IBsonSerializer serializer = null,
Action configurator = null,
+ BsonSerializationArgs args = default,
+ int estimatedBsonSize = 0) => ToBson(obj, nominalType, BsonSerializer.DefaultSerializationDomain, writerSettings,
+ serializer, configurator, args, estimatedBsonSize);
+
+ internal static byte[] ToBson(
+ this object obj,
+ Type nominalType,
+ IBsonSerializationDomain serializationDomain,
+ BsonBinaryWriterSettings writerSettings = null,
+ IBsonSerializer serializer = null,
+ Action configurator = null,
BsonSerializationArgs args = default(BsonSerializationArgs),
int estimatedBsonSize = 0)
{
@@ -84,7 +112,7 @@ public static byte[] ToBson(
if (serializer == null)
{
- serializer = BsonSerializer.LookupSerializer(nominalType);
+ serializer = serializationDomain.LookupSerializer(nominalType);
}
if (serializer.ValueType != nominalType)
{
@@ -138,7 +166,16 @@ public static BsonDocument ToBsonDocument(
Type nominalType,
IBsonSerializer serializer = null,
Action configurator = null,
- BsonSerializationArgs args = default(BsonSerializationArgs))
+ BsonSerializationArgs args = default) => ToBsonDocument(obj, nominalType,
+ BsonSerializer.DefaultSerializationDomain, serializer, configurator, args);
+
+ internal static BsonDocument ToBsonDocument(
+ this object obj,
+ Type nominalType,
+ IBsonSerializationDomain serializationDomain,
+ IBsonSerializer serializer = null,
+ Action configurator = null,
+ BsonSerializationArgs args = default)
{
if (nominalType == null)
{
@@ -165,7 +202,7 @@ public static BsonDocument ToBsonDocument(
return convertibleToBsonDocument.ToBsonDocument(); // use the provided ToBsonDocument method
}
- serializer = BsonSerializer.LookupSerializer(nominalType);
+ serializer = serializationDomain.LookupSerializer(nominalType);
}
if (serializer.ValueType != nominalType)
{
@@ -226,6 +263,16 @@ public static string ToJson(
JsonWriterSettings writerSettings = null,
IBsonSerializer serializer = null,
Action configurator = null,
+ BsonSerializationArgs args = default)
+ => ToJson(obj, nominalType, BsonSerializer.DefaultSerializationDomain, writerSettings, serializer, configurator, args);
+
+ internal static string ToJson(
+ this object obj,
+ Type nominalType,
+ IBsonSerializationDomain domain,
+ JsonWriterSettings writerSettings = null,
+ IBsonSerializer serializer = null,
+ Action configurator = null,
BsonSerializationArgs args = default(BsonSerializationArgs))
{
if (nominalType == null)
@@ -236,7 +283,7 @@ public static string ToJson(
if (serializer == null)
{
- serializer = BsonSerializer.LookupSerializer(nominalType);
+ serializer = domain.LookupSerializer(nominalType);
}
if (serializer.ValueType != nominalType)
{
diff --git a/src/MongoDB.Bson/IBsonDefaults.cs b/src/MongoDB.Bson/IBsonDefaults.cs
new file mode 100644
index 00000000000..e843c8eb4a4
--- /dev/null
+++ b/src/MongoDB.Bson/IBsonDefaults.cs
@@ -0,0 +1,39 @@
+/* Copyright 2010-present MongoDB Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using MongoDB.Bson.Serialization;
+
+namespace MongoDB.Bson
+{
+ internal interface IBsonDefaults
+ {
+ ///
+ ///
+ ///
+ IBsonSerializer DynamicArraySerializer { get; set; }
+ ///
+ ///
+ ///
+ IBsonSerializer DynamicDocumentSerializer { get; set; }
+ ///
+ ///
+ ///
+ int MaxDocumentSize { get; set; }
+ ///
+ ///
+ ///
+ int MaxSerializationDepth { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs b/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs
index 1c510ed71e3..99d9ccb5d87 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs
@@ -136,7 +136,8 @@ protected override BsonReaderSettings CloneImplementation()
Encoding = _encoding,
FixOldBinarySubTypeOnInput = _fixOldBinarySubTypeOnInput,
FixOldDateTimeMaxValueOnInput = _fixOldDateTimeMaxValueOnInput,
- MaxDocumentSize = _maxDocumentSize
+ MaxDocumentSize = _maxDocumentSize,
+ SerializationDomain = SerializationDomain
};
return clone;
diff --git a/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs b/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs
index 96c8f3168de..93da7f95a2d 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs
@@ -122,7 +122,8 @@ protected override BsonWriterSettings CloneImplementation()
Encoding = _encoding,
FixOldBinarySubTypeOnOutput = _fixOldBinarySubTypeOnOutput,
MaxDocumentSize = _maxDocumentSize,
- MaxSerializationDepth = MaxSerializationDepth
+ MaxSerializationDepth = MaxSerializationDepth,
+ SerializationDomain = SerializationDomain,
};
return clone;
}
diff --git a/src/MongoDB.Bson/IO/BsonDocumentReaderSettings.cs b/src/MongoDB.Bson/IO/BsonDocumentReaderSettings.cs
index 3b87c603ffd..b1d78974a3a 100644
--- a/src/MongoDB.Bson/IO/BsonDocumentReaderSettings.cs
+++ b/src/MongoDB.Bson/IO/BsonDocumentReaderSettings.cs
@@ -67,7 +67,7 @@ public static BsonDocumentReaderSettings Defaults
/// A clone of the settings.
protected override BsonReaderSettings CloneImplementation()
{
- var clone = new BsonDocumentReaderSettings();
+ var clone = new BsonDocumentReaderSettings { SerializationDomain = SerializationDomain }; //TODO This can be improved
return clone;
}
}
diff --git a/src/MongoDB.Bson/IO/BsonReader.cs b/src/MongoDB.Bson/IO/BsonReader.cs
index 25724b855e7..a34aed6502e 100644
--- a/src/MongoDB.Bson/IO/BsonReader.cs
+++ b/src/MongoDB.Bson/IO/BsonReader.cs
@@ -25,7 +25,7 @@ namespace MongoDB.Bson.IO
///
/// Represents a BSON reader for some external format (see subclasses).
///
- public abstract class BsonReader : IBsonReader
+ public abstract class BsonReader : IBsonReaderInternal
{
// private fields
private bool _disposed = false;
diff --git a/src/MongoDB.Bson/IO/BsonReaderSettings.cs b/src/MongoDB.Bson/IO/BsonReaderSettings.cs
index 649c02ff59c..5693c4774e9 100644
--- a/src/MongoDB.Bson/IO/BsonReaderSettings.cs
+++ b/src/MongoDB.Bson/IO/BsonReaderSettings.cs
@@ -14,6 +14,7 @@
*/
using System;
+using MongoDB.Bson.Serialization;
namespace MongoDB.Bson.IO
{
@@ -24,6 +25,7 @@ public abstract class BsonReaderSettings
{
// private fields
private bool _isFrozen;
+ private IBsonSerializationDomain _serializationDomain;
// constructors
///
@@ -77,6 +79,16 @@ public BsonReaderSettings FrozenCopy()
}
}
+ internal IBsonSerializationDomain SerializationDomain
+ {
+ get => _serializationDomain;
+ set
+ {
+ if (_isFrozen) { ThrowFrozenException(); }
+ _serializationDomain = value;
+ }
+ }
+
// protected methods
///
/// Creates a clone of the settings.
diff --git a/src/MongoDB.Bson/IO/BsonWriterSettings.cs b/src/MongoDB.Bson/IO/BsonWriterSettings.cs
index 06957993d70..076a336d07c 100644
--- a/src/MongoDB.Bson/IO/BsonWriterSettings.cs
+++ b/src/MongoDB.Bson/IO/BsonWriterSettings.cs
@@ -14,6 +14,7 @@
*/
using System;
+using MongoDB.Bson.Serialization;
namespace MongoDB.Bson.IO
{
@@ -25,6 +26,7 @@ public abstract class BsonWriterSettings
// private fields
private bool _isFrozen;
private int _maxSerializationDepth = BsonDefaults.MaxSerializationDepth;
+ private IBsonSerializationDomain _serializationDomain = BsonSerializer.DefaultSerializationDomain;
// constructors
///
@@ -92,6 +94,19 @@ public BsonWriterSettings FrozenCopy()
}
}
+ ///
+ /// //TODO
+ ///
+ internal IBsonSerializationDomain SerializationDomain
+ {
+ get => _serializationDomain;
+ set
+ {
+ if (_isFrozen) { ThrowFrozenException(); }
+ _serializationDomain = value;
+ }
+ }
+
// protected methods
///
/// Creates a clone of the settings.
diff --git a/src/MongoDB.Bson/IO/IBsonReader.cs b/src/MongoDB.Bson/IO/IBsonReader.cs
index 14af4722a33..4bc6991b36d 100644
--- a/src/MongoDB.Bson/IO/IBsonReader.cs
+++ b/src/MongoDB.Bson/IO/IBsonReader.cs
@@ -256,4 +256,13 @@ public interface IBsonReader : IDisposable
///
void SkipValue();
}
+
+ internal interface IBsonReaderInternal : IBsonReader
+ {
+ //TODO I'm not sure why this was not already present, there is already an equivalent in IBsonWriter.
+ ///
+ /// Gets the settings of the reader.
+ ///
+ BsonReaderSettings Settings { get; }
+ }
}
diff --git a/src/MongoDB.Bson/IO/JsonReaderSettings.cs b/src/MongoDB.Bson/IO/JsonReaderSettings.cs
index 383d4f7271f..f44b0e1000e 100644
--- a/src/MongoDB.Bson/IO/JsonReaderSettings.cs
+++ b/src/MongoDB.Bson/IO/JsonReaderSettings.cs
@@ -68,7 +68,7 @@ public static JsonReaderSettings Defaults
/// A clone of the settings.
protected override BsonReaderSettings CloneImplementation()
{
- var clone = new JsonReaderSettings();
+ var clone = new JsonReaderSettings { SerializationDomain = SerializationDomain }; //TODO This can be improved
return clone;
}
}
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/BsonDocumentWrapper.cs b/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs
index 09edc32dbfa..d177d0035ce 100644
--- a/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs
+++ b/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs
@@ -91,9 +91,19 @@ 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);
+
+ ///
+ /// //TODO
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static BsonDocumentWrapper Create(TNominalType value, IBsonSerializationDomain domain)
{
- return Create(typeof(TNominalType), value);
+ return Create(typeof(TNominalType), value, domain);
}
///
@@ -102,9 +112,19 @@ 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);
+
+ ///
+ /// //TODO
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static BsonDocumentWrapper Create(Type nominalType, object value, IBsonSerializationDomain domain)
{
- var serializer = BsonSerializer.LookupSerializer(nominalType);
+ var serializer = domain.LookupSerializer(nominalType);
return new BsonDocumentWrapper(value, serializer);
}
@@ -114,14 +134,25 @@ public static BsonDocumentWrapper Create(Type nominalType, object value)
/// The nominal type of the wrapped objects.
/// A list of wrapped objects.
/// A list of BsonDocumentWrappers.
- public static IEnumerable CreateMultiple(IEnumerable values)
+ public static IEnumerable CreateMultiple(IEnumerable values) =>
+ CreateMultiple(values, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ /// //TODO
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static IEnumerable CreateMultiple(IEnumerable values, IBsonSerializationDomain domain)
{
if (values == null)
{
throw new ArgumentNullException("values");
}
- var serializer = BsonSerializer.LookupSerializer(typeof(TNominalType));
+ var serializer = domain.LookupSerializer(typeof(TNominalType));
return values.Select(v => new BsonDocumentWrapper(v, serializer));
}
@@ -131,7 +162,18 @@ public static IEnumerable CreateMultiple(IEnu
/// The nominal type of the wrapped object.
/// A list of wrapped objects.
/// A list of BsonDocumentWrappers.
- public static IEnumerable CreateMultiple(Type nominalType, IEnumerable values)
+ public static IEnumerable CreateMultiple(Type nominalType, IEnumerable values) =>
+ CreateMultiple(nominalType, values, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ /// //TODO
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static IEnumerable CreateMultiple(Type nominalType, IEnumerable values, IBsonSerializationDomain domain)
{
if (nominalType == null)
{
@@ -142,7 +184,7 @@ public static IEnumerable CreateMultiple(Type nominalType,
throw new ArgumentNullException("values");
}
- var serializer = BsonSerializer.LookupSerializer(nominalType);
+ var serializer = domain.LookupSerializer(nominalType);
return values.Cast
public class BsonClassMap
{
- // private static fields
- private readonly static Dictionary __classMaps = new Dictionary();
- private readonly static Queue __knownTypesQueue = new Queue();
- private static int __freezeNestingLevel = 0;
-
// private fields
private readonly Type _classType;
private readonly List _creatorMaps;
- private readonly IConventionPack _conventionPack;
private readonly bool _isAnonymous;
private readonly List _allMemberMaps; // includes inherited member maps
private readonly ReadOnlyCollection _allMemberMapsReadonly;
@@ -70,7 +64,6 @@ public BsonClassMap(Type classType)
{
_classType = classType;
_creatorMaps = new List();
- _conventionPack = ConventionRegistry.Lookup(classType);
_isAnonymous = classType.IsAnonymousType();
_allMemberMaps = new List();
_allMemberMapsReadonly = _allMemberMaps.AsReadOnly();
@@ -124,12 +117,13 @@ public IEnumerable CreatorMaps
get { return _creatorMaps; }
}
+ //DOMAIN-API This one should be removed, or become a method to get the convention registry/domain as input
///
/// Gets the conventions used for auto mapping.
///
public IConventionPack ConventionPack
{
- get { return _conventionPack; }
+ get { return BsonSerializer.DefaultSerializationDomain.ConventionRegistry.Lookup(_classType); }
}
///
@@ -253,6 +247,7 @@ internal int ExtraElementsMemberMapIndex
get { return _extraElementsMemberIndex; }
}
+ //DOMAIN-API This is a utility method, it should not be public.
// public static methods
///
/// Gets the type of a member.
@@ -282,103 +277,32 @@ public static Type GetMemberInfoType(MemberInfo memberInfo)
/// Gets all registered class maps.
///
/// All registered class maps.
- public static IEnumerable GetRegisteredClassMaps()
- {
- BsonSerializer.ConfigLock.EnterReadLock();
- try
- {
- return __classMaps.Values.ToList(); // return a copy for thread safety
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitReadLock();
- }
- }
+ public static IEnumerable GetRegisteredClassMaps() =>
+ BsonSerializer.DefaultSerializationDomain.BsonClassMap.GetRegisteredClassMaps();
///
/// Checks whether a class map is registered for a type.
///
/// The type to check.
/// True if there is a class map registered for the type.
- public static bool IsClassMapRegistered(Type type)
- {
- if (type == null)
- {
- throw new ArgumentNullException("type");
- }
-
- BsonSerializer.ConfigLock.EnterReadLock();
- try
- {
- return __classMaps.ContainsKey(type);
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitReadLock();
- }
- }
+ public static bool IsClassMapRegistered(Type type) =>
+ BsonSerializer.DefaultSerializationDomain.BsonClassMap.IsClassMapRegistered(type);
///
/// Looks up a class map (will AutoMap the class if no class map is registered).
///
/// The class type.
/// The class map.
- public static BsonClassMap LookupClassMap(Type classType)
- {
- if (classType == null)
- {
- throw new ArgumentNullException("classType");
- }
-
- BsonSerializer.ConfigLock.EnterReadLock();
- try
- {
- if (__classMaps.TryGetValue(classType, out var classMap))
- {
- if (classMap.IsFrozen)
- {
- return classMap;
- }
- }
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitReadLock();
- }
-
- // automatically create a new classMap for classType and register it (unless another thread does first)
- // do the work of speculatively creating a new class map outside of holding any lock
- var classMapDefinition = typeof(BsonClassMap<>);
- var classMapType = classMapDefinition.MakeGenericType(classType);
- var newClassMap = (BsonClassMap)Activator.CreateInstance(classMapType);
- newClassMap.AutoMap();
-
- BsonSerializer.ConfigLock.EnterWriteLock();
- try
- {
- if (!__classMaps.TryGetValue(classType, out var classMap))
- {
- RegisterClassMap(newClassMap);
- classMap = newClassMap;
- }
-
- return classMap.Freeze();
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitWriteLock();
- }
- }
+ public static BsonClassMap LookupClassMap(Type classType) =>
+ BsonSerializer.DefaultSerializationDomain.BsonClassMap.LookupClassMap(classType);
///
/// Creates and registers a class map.
///
/// The class.
/// The class map.
- public static BsonClassMap RegisterClassMap()
- {
- return RegisterClassMap(cm => { cm.AutoMap(); });
- }
+ public static BsonClassMap RegisterClassMap()=>
+ BsonSerializer.DefaultSerializationDomain.BsonClassMap.RegisterClassMap();
///
/// Creates and registers a class map.
@@ -387,35 +311,14 @@ public static BsonClassMap RegisterClassMap()
/// The class map initializer.
/// The class map.
public static BsonClassMap RegisterClassMap(Action> classMapInitializer)
- {
- var classMap = new BsonClassMap(classMapInitializer);
- RegisterClassMap(classMap);
- return classMap;
- }
+ => BsonSerializer.DefaultSerializationDomain.BsonClassMap.RegisterClassMap(classMapInitializer);
///
/// Registers a class map.
///
/// The class map.
public static void RegisterClassMap(BsonClassMap classMap)
- {
- if (classMap == null)
- {
- throw new ArgumentNullException("classMap");
- }
-
- BsonSerializer.ConfigLock.EnterWriteLock();
- try
- {
- // note: class maps can NOT be replaced (because derived classes refer to existing instance)
- __classMaps.Add(classMap.ClassType, classMap);
- BsonSerializer.RegisterDiscriminator(classMap.ClassType, classMap.Discriminator);
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitWriteLock();
- }
- }
+ => BsonSerializer.DefaultSerializationDomain.BsonClassMap.RegisterClassMap(classMap);
///
/// Registers a class map if it is not already registered.
@@ -423,16 +326,7 @@ public static void RegisterClassMap(BsonClassMap classMap)
/// The class.
/// True if this call registered the class map, false if the class map was already registered.
public static bool TryRegisterClassMap()
- {
- return TryRegisterClassMap(ClassMapFactory);
-
- static BsonClassMap ClassMapFactory()
- {
- var classMap = new BsonClassMap();
- classMap.AutoMap();
- return classMap;
- }
- }
+ => BsonSerializer.DefaultSerializationDomain.BsonClassMap.TryRegisterClassMap();
///
/// Registers a class map if it is not already registered.
@@ -441,19 +335,7 @@ static BsonClassMap ClassMapFactory()
/// The class map.
/// True if this call registered the class map, false if the class map was already registered.
public static bool TryRegisterClassMap(BsonClassMap classMap)
- {
- if (classMap == null)
- {
- throw new ArgumentNullException(nameof(classMap));
- }
-
- return TryRegisterClassMap(ClassMapFactory);
-
- BsonClassMap ClassMapFactory()
- {
- return classMap;
- }
- }
+ => BsonSerializer.DefaultSerializationDomain.BsonClassMap.TryRegisterClassMap(classMap);
///
/// Registers a class map if it is not already registered.
@@ -462,19 +344,7 @@ BsonClassMap ClassMapFactory()
/// The class map initializer (only called if the class map is not already registered).
/// True if this call registered the class map, false if the class map was already registered.
public static bool TryRegisterClassMap(Action> classMapInitializer)
- {
- if (classMapInitializer == null)
- {
- throw new ArgumentNullException(nameof(classMapInitializer));
- }
-
- return TryRegisterClassMap(ClassMapFactory);
-
- BsonClassMap ClassMapFactory()
- {
- return new BsonClassMap(classMapInitializer);
- }
- }
+ => BsonSerializer.DefaultSerializationDomain.BsonClassMap.TryRegisterClassMap(classMapInitializer);
///
/// Registers a class map if it is not already registered.
@@ -483,54 +353,22 @@ BsonClassMap ClassMapFactory()
/// The class map factory (only called if the class map is not already registered).
/// True if this call registered the class map, false if the class map was already registered.
public static bool TryRegisterClassMap(Func> classMapFactory)
- {
- if (classMapFactory == null)
- {
- throw new ArgumentNullException(nameof(classMapFactory));
- }
-
- BsonSerializer.ConfigLock.EnterReadLock();
- try
- {
- if (__classMaps.ContainsKey(typeof(TClass)))
- {
- return false;
- }
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitReadLock();
- }
-
- BsonSerializer.ConfigLock.EnterWriteLock();
- try
- {
- if (__classMaps.ContainsKey(typeof(TClass)))
- {
- return false;
- }
- else
- {
- // create a classMap for TClass and register it
- var classMap = classMapFactory();
- RegisterClassMap(classMap);
- return true;
- }
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitWriteLock();
- }
- }
+ => BsonSerializer.DefaultSerializationDomain.BsonClassMap.TryRegisterClassMap(classMapFactory);
// public methods
///
/// Automaps the class.
///
- public void AutoMap()
+ public void AutoMap() => AutoMap(BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ /// //TODO
+ ///
+ ///
+ internal void AutoMap(IBsonSerializationDomain serializationDomain)
{
if (_frozen) { ThrowFrozenException(); }
- AutoMapClass();
+ AutoMapClass(serializationDomain);
}
///
@@ -573,13 +411,29 @@ obj is BsonClassMap other &&
///
public override int GetHashCode() => 0;
+ internal class FreezeContext
+ {
+ public int FreezeNestingLevel { get; set; } = 0;
+ public Queue KnownTypesQueue { get; set; } = new();
+ public IBsonSerializationDomain SerializationDomain { get; set; }
+ }
+
///
/// Freezes the class map.
///
/// The frozen class map.
- public BsonClassMap Freeze()
+ public BsonClassMap Freeze() => Freeze(BsonSerializer.DefaultSerializationDomain);
+
+ internal BsonClassMap Freeze(IBsonSerializationDomain domain)
+ {
+ var freezeContext = new FreezeContext { SerializationDomain = domain };
+ return Freeze(freezeContext);
+ }
+
+ private BsonClassMap Freeze(FreezeContext context)
{
- BsonSerializer.ConfigLock.EnterReadLock();
+ var configLock = context.SerializationDomain!.ConfigLock;
+ configLock.EnterReadLock();
try
{
if (_frozen)
@@ -589,15 +443,15 @@ public BsonClassMap Freeze()
}
finally
{
- BsonSerializer.ConfigLock.ExitReadLock();
+ configLock.ExitReadLock();
}
- BsonSerializer.ConfigLock.EnterWriteLock();
+ configLock.EnterWriteLock();
try
{
if (!_frozen)
{
- __freezeNestingLevel++;
+ context.FreezeNestingLevel++;
try
{
var baseType = _classType.GetTypeInfo().BaseType;
@@ -605,9 +459,9 @@ public BsonClassMap Freeze()
{
if (_baseClassMap == null)
{
- _baseClassMap = LookupClassMap(baseType);
+ _baseClassMap = context.SerializationDomain.BsonClassMap.LookupClassMap(baseType);
}
- _baseClassMap.Freeze();
+ _baseClassMap.Freeze(context);
_discriminatorIsRequired |= _baseClassMap._discriminatorIsRequired;
_hasRootClass |= (_isRootClass || _baseClassMap.HasRootClass);
_allMemberMaps.AddRange(_baseClassMap.AllMemberMaps);
@@ -699,28 +553,28 @@ public BsonClassMap Freeze()
// this avoids infinite recursion when going back down the inheritance tree while processing known types
foreach (var knownType in _knownTypes)
{
- __knownTypesQueue.Enqueue(knownType);
+ context.KnownTypesQueue.Enqueue(knownType);
}
// if we are back to the first level go ahead and process any queued known types
- if (__freezeNestingLevel == 1)
+ if (context.FreezeNestingLevel == 1)
{
- while (__knownTypesQueue.Count != 0)
+ while (context.KnownTypesQueue.Count != 0)
{
- var knownType = __knownTypesQueue.Dequeue();
- LookupClassMap(knownType); // will AutoMap and/or Freeze knownType if necessary
+ var knownType = context.KnownTypesQueue.Dequeue();
+ context.SerializationDomain.BsonClassMap.LookupClassMap(knownType); // will AutoMap and/or Freeze knownType if necessary
}
}
}
finally
{
- __freezeNestingLevel--;
+ context.FreezeNestingLevel--;
}
}
}
finally
{
- BsonSerializer.ConfigLock.ExitWriteLock();
+ configLock.ExitWriteLock();
}
return this;
}
@@ -1317,7 +1171,7 @@ public void UnmapProperty(string propertyName)
/// Gets the discriminator convention for the class.
///
/// The discriminator convention for the class.
- internal IDiscriminatorConvention GetDiscriminatorConvention()
+ internal IDiscriminatorConvention GetDiscriminatorConvention(IBsonSerializationDomain serializationDomain)
{
// return a cached discriminator convention when possible
var discriminatorConvention = _discriminatorConvention;
@@ -1354,7 +1208,7 @@ IDiscriminatorConvention LookupDiscriminatorConvention()
return classMap._discriminatorConvention;
}
- if (BsonSerializer.IsDiscriminatorConventionRegisteredAtThisLevel(classMap._classType))
+ if (serializationDomain.IsDiscriminatorConventionRegisteredAtThisLevel(classMap._classType))
{
// in this case LookupDiscriminatorConvention below will find it
break;
@@ -1363,21 +1217,29 @@ IDiscriminatorConvention LookupDiscriminatorConvention()
if (classMap._isRootClass)
{
// in this case auto-register a hierarchical convention for the root class and look it up as usual below
- BsonSerializer.GetOrRegisterDiscriminatorConvention(classMap._classType, StandardDiscriminatorConvention.Hierarchical);
+ serializationDomain.GetOrRegisterDiscriminatorConvention(classMap._classType, StandardDiscriminatorConvention.Hierarchical);
break;
}
classMap = classMap._baseClassMap;
}
- return BsonSerializer.LookupDiscriminatorConvention(_classType);
+ return serializationDomain.LookupDiscriminatorConvention(_classType);
}
}
+ ///
+ /// Gets the discriminator convention for the class.
+ ///
+ /// The discriminator convention for the class.
+ internal IDiscriminatorConvention GetDiscriminatorConvention()
+ => GetDiscriminatorConvention(BsonSerializer.DefaultSerializationDomain);
+
// private methods
- private void AutoMapClass()
+ private void AutoMapClass(IBsonSerializationDomain serializationDomain)
{
- new ConventionRunner(_conventionPack).Apply(this);
+ var conventionPack = serializationDomain.ConventionRegistry.Lookup(_classType);
+ new ConventionRunner(conventionPack).Apply(this, serializationDomain);
foreach (var memberMap in _declaredMemberMaps)
{
diff --git a/src/MongoDB.Bson/Serialization/BsonClassMapDomain.cs b/src/MongoDB.Bson/Serialization/BsonClassMapDomain.cs
new file mode 100644
index 00000000000..9efe6c84a1d
--- /dev/null
+++ b/src/MongoDB.Bson/Serialization/BsonClassMapDomain.cs
@@ -0,0 +1,263 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace MongoDB.Bson.Serialization;
+
+internal class BsonClassMapDomain : IBsonClassMapDomain
+{
+ // private fields
+ private readonly IBsonSerializationDomain _serializationDomain;
+ private readonly Dictionary _classMaps = new();
+
+ public BsonClassMapDomain(BsonSerializationDomain serializationDomain)
+ {
+ _serializationDomain = serializationDomain;
+ }
+
+ ///
+ /// Gets all registered class maps.
+ ///
+ /// All registered class maps.
+ public IEnumerable GetRegisteredClassMaps()
+ {
+ _serializationDomain.ConfigLock.EnterReadLock();
+ try
+ {
+ return _classMaps.Values.ToList(); // return a copy for thread safety
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitReadLock();
+ }
+ }
+
+ ///
+ /// Checks whether a class map is registered for a type.
+ ///
+ /// The type to check.
+ /// True if there is a class map registered for the type.
+ public bool IsClassMapRegistered(Type type)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException("type");
+ }
+
+ _serializationDomain.ConfigLock.EnterReadLock();
+ try
+ {
+ return _classMaps.ContainsKey(type);
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitReadLock();
+ }
+ }
+
+ ///
+ /// Looks up a class map (will AutoMap the class if no class map is registered).
+ ///
+ /// The class type.
+ /// The class map.
+ public BsonClassMap LookupClassMap(Type classType)
+ {
+ if (classType == null)
+ {
+ throw new ArgumentNullException("classType");
+ }
+
+ _serializationDomain.ConfigLock.EnterReadLock();
+ try
+ {
+ if (_classMaps.TryGetValue(classType, out var classMap))
+ {
+ if (classMap.IsFrozen)
+ {
+ return classMap;
+ }
+ }
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitReadLock();
+ }
+
+ // automatically create a new classMap for classType and register it (unless another thread does first)
+ // do the work of speculatively creating a new class map outside of holding any lock
+ var classMapDefinition = typeof(BsonClassMap<>);
+ var classMapType = classMapDefinition.MakeGenericType(classType);
+ var newClassMap = (BsonClassMap)Activator.CreateInstance(classMapType);
+ newClassMap.AutoMap(_serializationDomain);
+
+ _serializationDomain.ConfigLock.EnterWriteLock();
+ try
+ {
+ if (!_classMaps.TryGetValue(classType, out var classMap))
+ {
+ RegisterClassMap(newClassMap);
+ classMap = newClassMap;
+ }
+
+ return classMap.Freeze(_serializationDomain);
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitWriteLock();
+ }
+ }
+
+ ///
+ /// Creates and registers a class map.
+ ///
+ /// The class.
+ /// The class map.
+ public BsonClassMap RegisterClassMap()
+ {
+ return RegisterClassMap(cm => { cm.AutoMap(_serializationDomain); });
+ }
+
+ ///
+ /// Creates and registers a class map.
+ ///
+ /// The class.
+ /// The class map initializer.
+ /// The class map.
+ public BsonClassMap RegisterClassMap(Action> classMapInitializer)
+ {
+ var classMap = new BsonClassMap(classMapInitializer);
+ RegisterClassMap(classMap);
+ return classMap;
+ }
+
+ ///
+ /// Registers a class map.
+ ///
+ /// The class map.
+ public void RegisterClassMap(BsonClassMap classMap)
+ {
+ if (classMap == null)
+ {
+ throw new ArgumentNullException("classMap");
+ }
+
+ _serializationDomain.ConfigLock.EnterWriteLock();
+ try
+ {
+ // note: class maps can NOT be replaced (because derived classes refer to existing instance)
+ _classMaps.Add(classMap.ClassType, classMap);
+ _serializationDomain.RegisterDiscriminator(classMap.ClassType, classMap.Discriminator);
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitWriteLock();
+ }
+ }
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// True if this call registered the class map, false if the class map was already registered.
+ public bool TryRegisterClassMap()
+ {
+ return TryRegisterClassMap(() => ClassMapFactory(_serializationDomain));
+
+ static BsonClassMap ClassMapFactory(IBsonSerializationDomain serializationDomain)
+ {
+ var classMap = new BsonClassMap();
+ classMap.AutoMap(serializationDomain);
+ return classMap;
+ }
+ }
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// The class map.
+ /// True if this call registered the class map, false if the class map was already registered.
+ public bool TryRegisterClassMap(BsonClassMap classMap)
+ {
+ if (classMap == null)
+ {
+ throw new ArgumentNullException(nameof(classMap));
+ }
+
+ return TryRegisterClassMap(ClassMapFactory);
+
+ BsonClassMap ClassMapFactory()
+ {
+ return classMap;
+ }
+ }
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// The class map initializer (only called if the class map is not already registered).
+ /// True if this call registered the class map, false if the class map was already registered.
+ public bool TryRegisterClassMap(Action> classMapInitializer)
+ {
+ if (classMapInitializer == null)
+ {
+ throw new ArgumentNullException(nameof(classMapInitializer));
+ }
+
+ return TryRegisterClassMap(ClassMapFactory);
+
+ BsonClassMap ClassMapFactory()
+ {
+ return new BsonClassMap(classMapInitializer);
+ }
+ }
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// The class map factory (only called if the class map is not already registered).
+ /// True if this call registered the class map, false if the class map was already registered.
+ public bool TryRegisterClassMap(Func> classMapFactory)
+ {
+ if (classMapFactory == null)
+ {
+ throw new ArgumentNullException(nameof(classMapFactory));
+ }
+
+ _serializationDomain.ConfigLock.EnterReadLock();
+ try
+ {
+ if (_classMaps.ContainsKey(typeof(TClass)))
+ {
+ return false;
+ }
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitReadLock();
+ }
+
+ _serializationDomain.ConfigLock.EnterWriteLock();
+ try
+ {
+ if (_classMaps.ContainsKey(typeof(TClass)))
+ {
+ return false;
+ }
+ else
+ {
+ // create a classMap for TClass and register it
+ var classMap = classMapFactory();
+ RegisterClassMap(classMap);
+ return true;
+ }
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitWriteLock();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/Serialization/BsonClassMapSerializationProvider.cs b/src/MongoDB.Bson/Serialization/BsonClassMapSerializationProvider.cs
index ac088360c2d..950f21590a1 100644
--- a/src/MongoDB.Bson/Serialization/BsonClassMapSerializationProvider.cs
+++ b/src/MongoDB.Bson/Serialization/BsonClassMapSerializationProvider.cs
@@ -41,7 +41,18 @@ public override IBsonSerializer GetSerializer(Type type, IBsonSerializerRegistry
!typeof(Array).GetTypeInfo().IsAssignableFrom(type) &&
!typeof(Enum).GetTypeInfo().IsAssignableFrom(type))
{
- var classMap = BsonClassMap.LookupClassMap(type);
+ IBsonSerializationDomain domain;
+
+ if (serializerRegistry is IBsonSerializerRegistryInternal serializerRegistryInternal)
+ {
+ domain = serializerRegistryInternal.SerializationDomain;
+ }
+ else
+ {
+ domain = BsonSerializer.DefaultSerializationDomain;
+ }
+
+ var classMap = domain.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..d6b0a441da1 100644
--- a/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs
+++ b/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs
@@ -28,6 +28,7 @@ public class BsonDeserializationContext
private readonly IBsonSerializer _dynamicArraySerializer;
private readonly IBsonSerializer _dynamicDocumentSerializer;
private readonly IBsonReader _reader;
+ private readonly IBsonSerializationDomain _serializationDomain;
// constructors
private BsonDeserializationContext(
@@ -40,6 +41,16 @@ private BsonDeserializationContext(
_allowDuplicateElementNames = allowDuplicateElementNames;
_dynamicArraySerializer = dynamicArraySerializer;
_dynamicDocumentSerializer = dynamicDocumentSerializer;
+
+ if (reader is IBsonReaderInternal readerInternal)
+ {
+ _serializationDomain = readerInternal.Settings?.SerializationDomain;
+ }
+
+ _serializationDomain ??= BsonSerializer.DefaultSerializationDomain;
+
+ _dynamicArraySerializer ??= _serializationDomain.BsonDefaults.DynamicArraySerializer;
+ _dynamicDocumentSerializer ??= _serializationDomain.BsonDefaults.DynamicDocumentSerializer;
}
// public properties
@@ -54,6 +65,11 @@ public bool AllowDuplicateElementNames
get { return _allowDuplicateElementNames; }
}
+ ///
+ /// //TODO
+ ///
+ internal IBsonSerializationDomain SerializationDomain => _serializationDomain;
+
///
/// Gets the dynamic array serializer.
///
@@ -154,11 +170,10 @@ internal Builder(BsonDeserializationContext other, IBsonReader reader)
_dynamicArraySerializer = other.DynamicArraySerializer;
_dynamicDocumentSerializer = other.DynamicDocumentSerializer;
}
- else
- {
- _dynamicArraySerializer = BsonDefaults.DynamicArraySerializer;
- _dynamicDocumentSerializer = BsonDefaults.DynamicDocumentSerializer;
- }
+
+ /* QUESTION I removed the part where we set the dynamic serializers from the BsonDefaults, and delay it until we have a serialization domain (when we build the DeserializationContext).
+ * This is technically changing the public behaviour, but it's in a builder, I do not thing it will affect anyone. Same done for the serialization context.
+ */
}
// properties
diff --git a/src/MongoDB.Bson/Serialization/BsonMemberMap.cs b/src/MongoDB.Bson/Serialization/BsonMemberMap.cs
index b10971d5249..1181af3c7a8 100644
--- a/src/MongoDB.Bson/Serialization/BsonMemberMap.cs
+++ b/src/MongoDB.Bson/Serialization/BsonMemberMap.cs
@@ -56,7 +56,7 @@ public BsonMemberMap(BsonClassMap classMap, MemberInfo memberInfo)
{
_classMap = classMap;
_memberInfo = memberInfo;
- _memberType = BsonClassMap.GetMemberInfoType(memberInfo);
+ _memberType = BsonClassMap.GetMemberInfoType(memberInfo); //FP This is more of a utility method, it can stay like this
_memberTypeIsBsonValue = typeof(BsonValue).GetTypeInfo().IsAssignableFrom(_memberType);
Reset();
@@ -294,14 +294,16 @@ obj is BsonMemberMap other &&
/// Gets the serializer.
///
/// The serializer.
- public IBsonSerializer GetSerializer()
+ public IBsonSerializer GetSerializer() => GetSerializer(BsonSerializer.DefaultSerializationDomain);
+
+ internal IBsonSerializer GetSerializer(IBsonSerializationDomain domain)
{
if (_serializer == null)
{
// return special serializer for BsonValue members that handles the _csharpnull representation
if (_memberTypeIsBsonValue)
{
- var wrappedSerializer = BsonSerializer.LookupSerializer(_memberType);
+ var wrappedSerializer = domain.LookupSerializer(_memberType);
var isBsonArraySerializer = wrappedSerializer is IBsonArraySerializer;
var isBsonDocumentSerializer = wrappedSerializer is IBsonDocumentSerializer;
@@ -329,7 +331,7 @@ public IBsonSerializer GetSerializer()
}
else
{
- _serializer = BsonSerializer.LookupSerializer(_memberType);
+ _serializer = domain.LookupSerializer(_memberType);
}
}
return _serializer;
diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs b/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs
index a14a62322a8..40d84700130 100644
--- a/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs
+++ b/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs
@@ -26,6 +26,7 @@ public class BsonSerializationContext
// private fields
private readonly Func _isDynamicType;
private readonly IBsonWriter _writer;
+ private readonly IBsonSerializationDomain _serializationDomain;
// constructors
private BsonSerializationContext(
@@ -34,9 +35,19 @@ private BsonSerializationContext(
{
_writer = writer;
_isDynamicType = isDynamicType;
+ _serializationDomain = writer.Settings?.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.
@@ -119,12 +130,10 @@ internal Builder(BsonSerializationContext other, IBsonWriter writer)
{
_isDynamicType = other._isDynamicType;
}
- else
- {
- _isDynamicType = t =>
- (BsonDefaults.DynamicArraySerializer != null && t == BsonDefaults.DynamicArraySerializer.ValueType) ||
- (BsonDefaults.DynamicDocumentSerializer != null && t == BsonDefaults.DynamicDocumentSerializer.ValueType);
- }
+
+ /* QUESTION I removed the part where we set _isDynamicType from the BsonDefaults, and delay it until we have a serialization domain (when we build the SerializationContext).
+ * This is technically changing the public behaviour, but it's in a builder, I do not thing it will affect anyone. Same done for the deserialization context.
+ */
}
// properties
diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationDomain.cs b/src/MongoDB.Bson/Serialization/BsonSerializationDomain.cs
new file mode 100644
index 00000000000..b637daa6d04
--- /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, 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, 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, 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, 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());
+ _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/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 6602e74dec5..a862d05cb81 100644
--- a/src/MongoDB.Bson/Serialization/BsonSerializer.cs
+++ b/src/MongoDB.Bson/Serialization/BsonSerializer.cs
@@ -14,18 +14,10 @@
*/
using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Reflection;
using System.Threading;
-
-// don't add using statement for MongoDB.Bson.Serialization.Serializers to minimize dependencies on DefaultSerializer
using MongoDB.Bson.IO;
-using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Conventions;
-using MongoDB.Bson.Serialization.IdGenerators;
namespace MongoDB.Bson.Serialization
{
@@ -34,43 +26,29 @@ namespace MongoDB.Bson.Serialization
///
public static class BsonSerializer
{
- // private static fields
- private static ReaderWriterLockSlim __configLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
- private static Dictionary __idGenerators = new Dictionary();
- private static Dictionary __discriminatorConventions = new Dictionary();
- private static Dictionary> __discriminators = new Dictionary>();
- private static HashSet __discriminatedTypes = new HashSet();
- private static BsonSerializerRegistry __serializerRegistry;
- private static TypeMappingSerializationProvider __typeMappingSerializationProvider;
- // ConcurrentDictionary is being used as a concurrent set of Type. The values will always be null.
- private static ConcurrentDictionary __typesWithRegisteredKnownTypes = new ConcurrentDictionary();
-
- private static bool __useNullIdChecker = false;
- private static bool __useZeroIdChecker = false;
+ private static readonly IBsonSerializationDomain _serializationDomain;
// static constructor
static BsonSerializer()
{
- CreateSerializerRegistry();
- RegisterIdGenerators();
+ _serializationDomain = new BsonSerializationDomain("MAIN");
}
+ internal static IBsonSerializationDomain DefaultSerializationDomain => _serializationDomain;
+
// public static properties
///
/// Gets the serializer registry.
///
- public static IBsonSerializerRegistry SerializerRegistry
- {
- get { return __serializerRegistry; }
- }
+ public static IBsonSerializerRegistry SerializerRegistry => _serializationDomain.SerializerRegistry;
///
/// Gets or sets whether to use the NullIdChecker on reference Id types that don't have an IdGenerator registered.
///
public static bool UseNullIdChecker
{
- get { return __useNullIdChecker; }
- set { __useNullIdChecker = value; }
+ get => _serializationDomain.UseNullIdChecker;
+ set => _serializationDomain.UseNullIdChecker = value;
}
///
@@ -78,17 +56,21 @@ public static bool UseNullIdChecker
///
public static bool UseZeroIdChecker
{
- get { return __useZeroIdChecker; }
- set { __useZeroIdChecker = value; }
+ get => _serializationDomain.UseZeroIdChecker;
+ set => _serializationDomain.UseZeroIdChecker = value;
}
// internal static properties
- internal static ReaderWriterLockSlim ConfigLock
- {
- get { return __configLock; }
- }
+ internal static ReaderWriterLockSlim ConfigLock => _serializationDomain.ConfigLock;
// public static methods
+
+ ///
+ /// //TODO
+ ///
+ ///
+ internal static IBsonSerializationDomain CreateSerializationDomain() => new BsonSerializationDomain();
+
///
/// Deserializes an object from a BsonDocument.
///
@@ -97,12 +79,7 @@ internal static ReaderWriterLockSlim ConfigLock
/// The configurator.
/// A deserialized value.
public static TNominalType Deserialize(BsonDocument document, Action configurator = null)
- {
- using (var bsonReader = new BsonDocumentReader(document))
- {
- return Deserialize(bsonReader, configurator);
- }
- }
+ => _serializationDomain.Deserialize(document, configurator);
///
/// Deserializes a value.
@@ -112,11 +89,7 @@ public static TNominalType Deserialize(BsonDocument document, Acti
/// The configurator.
/// A deserialized value.
public static TNominalType Deserialize(IBsonReader bsonReader, Action configurator = null)
- {
- var serializer = LookupSerializer();
- var context = BsonDeserializationContext.CreateRoot(bsonReader, configurator);
- return serializer.Deserialize(context);
- }
+ => _serializationDomain.Deserialize(bsonReader, configurator);
///
/// Deserializes an object from a BSON byte array.
@@ -126,13 +99,7 @@ public static TNominalType Deserialize(IBsonReader bsonReader, Act
/// The configurator.
/// A deserialized value.
public static TNominalType Deserialize(byte[] bytes, Action configurator = null)
- {
- using (var buffer = new ByteArrayBuffer(bytes, isReadOnly: true))
- using (var stream = new ByteBufferStream(buffer))
- {
- return Deserialize(stream, configurator);
- }
- }
+ => _serializationDomain.Deserialize(bytes, configurator);
///
/// Deserializes an object from a BSON Stream.
@@ -142,12 +109,7 @@ public static TNominalType Deserialize(byte[] bytes, ActionThe configurator.
/// A deserialized value.
public static TNominalType Deserialize(Stream stream, Action configurator = null)
- {
- using (var bsonReader = new BsonBinaryReader(stream))
- {
- return Deserialize(bsonReader, configurator);
- }
- }
+ => _serializationDomain.Deserialize(stream, configurator);
///
/// Deserializes an object from a JSON string.
@@ -157,12 +119,7 @@ public static TNominalType Deserialize(Stream stream, ActionThe configurator.
/// A deserialized value.
public static TNominalType Deserialize(string json, Action configurator = null)
- {
- using (var bsonReader = new JsonReader(json))
- {
- return Deserialize(bsonReader, configurator);
- }
- }
+ => _serializationDomain.Deserialize(json, configurator);
///
/// Deserializes an object from a JSON TextReader.
@@ -172,12 +129,7 @@ public static TNominalType Deserialize(string json, ActionThe configurator.
/// A deserialized value.
public static TNominalType Deserialize(TextReader textReader, Action configurator = null)
- {
- using (var bsonReader = new JsonReader(textReader))
- {
- return Deserialize(bsonReader, configurator);
- }
- }
+ => _serializationDomain.Deserialize(textReader, configurator);
///
/// Deserializes an object from a BsonDocument.
@@ -187,12 +139,7 @@ public static TNominalType Deserialize(TextReader textReader, Acti
/// The configurator.
/// A deserialized value.
public static object Deserialize(BsonDocument document, Type nominalType, Action configurator = null)
- {
- using (var bsonReader = new BsonDocumentReader(document))
- {
- return Deserialize(bsonReader, nominalType, configurator);
- }
- }
+ => _serializationDomain.Deserialize(document, nominalType, configurator);
///
/// Deserializes a value.
@@ -202,11 +149,7 @@ public static object Deserialize(BsonDocument document, Type nominalType, Action
/// The configurator.
/// A deserialized value.
public static object Deserialize(IBsonReader bsonReader, Type nominalType, Action configurator = null)
- {
- var serializer = LookupSerializer(nominalType);
- var context = BsonDeserializationContext.CreateRoot(bsonReader, configurator);
- return serializer.Deserialize(context);
- }
+ => _serializationDomain.Deserialize(bsonReader, nominalType, configurator);
///
/// Deserializes an object from a BSON byte array.
@@ -216,13 +159,7 @@ public static object Deserialize(IBsonReader bsonReader, Type nominalType, Actio
/// The configurator.
/// A deserialized value.
public static object Deserialize(byte[] bytes, Type nominalType, Action configurator = null)
- {
- using (var buffer = new ByteArrayBuffer(bytes, isReadOnly: true))
- using (var stream = new ByteBufferStream(buffer))
- {
- return Deserialize(stream, nominalType, configurator);
- }
- }
+ => _serializationDomain.Deserialize(bytes, nominalType, configurator);
///
/// Deserializes an object from a BSON Stream.
@@ -232,12 +169,7 @@ public static object Deserialize(byte[] bytes, Type nominalType, ActionThe configurator.
/// A deserialized value.
public static object Deserialize(Stream stream, Type nominalType, Action configurator = null)
- {
- using (var bsonReader = new BsonBinaryReader(stream))
- {
- return Deserialize(bsonReader, nominalType, configurator);
- }
- }
+ => _serializationDomain.Deserialize(stream, nominalType, configurator);
///
/// Deserializes an object from a JSON string.
@@ -247,12 +179,7 @@ public static object Deserialize(Stream stream, Type nominalType, ActionThe configurator.
/// A deserialized value.
public static object Deserialize(string json, Type nominalType, Action configurator = null)
- {
- using (var bsonReader = new JsonReader(json))
- {
- return Deserialize(bsonReader, nominalType, configurator);
- }
- }
+ => _serializationDomain.Deserialize(json, nominalType, configurator);
///
/// Deserializes an object from a JSON TextReader.
@@ -262,57 +189,13 @@ public static object Deserialize(string json, Type nominalType, ActionThe configurator.
/// A deserialized value.
public static object Deserialize(TextReader textReader, Type nominalType, Action configurator = null)
- {
- using (var bsonReader = new JsonReader(textReader))
- {
- return Deserialize(bsonReader, nominalType, configurator);
- }
- }
+ => _serializationDomain.Deserialize(textReader, nominalType, configurator);
internal static IDiscriminatorConvention GetOrRegisterDiscriminatorConvention(Type type, IDiscriminatorConvention discriminatorConvention)
- {
- __configLock.EnterReadLock();
- try
- {
- if (__discriminatorConventions.TryGetValue(type, out var registeredDiscriminatorConvention))
- {
- return registeredDiscriminatorConvention;
- }
- }
- finally
- {
- __configLock.ExitReadLock();
- }
-
- __configLock.EnterWriteLock();
- try
- {
- if (__discriminatorConventions.TryGetValue(type, out var registeredDiscrimantorConvention))
- {
- return registeredDiscrimantorConvention;
- }
-
- RegisterDiscriminatorConvention(type, discriminatorConvention);
- return discriminatorConvention;
- }
- finally
- {
- __configLock.ExitWriteLock();
- }
- }
+ => _serializationDomain.GetOrRegisterDiscriminatorConvention(type, discriminatorConvention);
internal static bool IsDiscriminatorConventionRegisteredAtThisLevel(Type type)
- {
- __configLock.EnterReadLock();
- try
- {
- return __discriminatorConventions.ContainsKey(type);
- }
- finally
- {
- __configLock.ExitReadLock();
- }
- }
+ => _serializationDomain.IsDiscriminatorConventionRegisteredAtThisLevel(type);
///
/// Returns whether the given type has any discriminators registered for any of its subclasses.
@@ -320,10 +203,7 @@ internal static bool IsDiscriminatorConventionRegisteredAtThisLevel(Type type)
/// A Type.
/// True if the type is discriminated.
public static bool IsTypeDiscriminated(Type type)
- {
- var typeInfo = type.GetTypeInfo();
- return typeInfo.IsInterface || __discriminatedTypes.Contains(type);
- }
+ => _serializationDomain.IsTypeDiscriminated(type);
///
/// Looks up the actual type of an object to be deserialized.
@@ -332,73 +212,7 @@ public static bool IsTypeDiscriminated(Type type)
/// The discriminator.
/// The actual type of the object.
public static Type LookupActualType(Type nominalType, BsonValue discriminator)
- {
- if (discriminator == null)
- {
- return nominalType;
- }
-
- // note: EnsureKnownTypesAreRegistered handles its own locking so call from outside any lock
- EnsureKnownTypesAreRegistered(nominalType);
-
- __configLock.EnterReadLock();
- try
- {
- Type actualType = null;
-
- HashSet hashSet;
- var nominalTypeInfo = nominalType.GetTypeInfo();
- if (__discriminators.TryGetValue(discriminator, out hashSet))
- {
- foreach (var type in hashSet)
- {
- if (nominalTypeInfo.IsAssignableFrom(type))
- {
- if (actualType == null)
- {
- actualType = type;
- }
- else
- {
- string message = string.Format("Ambiguous discriminator '{0}'.", discriminator);
- throw new BsonSerializationException(message);
- }
- }
- }
-
- // no need for additional checks, we found the right type
- if (actualType != null)
- {
- return actualType;
- }
- }
-
- if (discriminator.IsString)
- {
- actualType = TypeNameDiscriminator.GetActualType(discriminator.AsString); // see if it's a Type name
- }
-
- if (actualType == null)
- {
- string message = string.Format("Unknown discriminator value '{0}'.", discriminator);
- throw new BsonSerializationException(message);
- }
-
- if (!nominalTypeInfo.IsAssignableFrom(actualType))
- {
- string message = string.Format(
- "Actual type {0} is not assignable to expected type {1}.",
- actualType.FullName, nominalType.FullName);
- throw new BsonSerializationException(message);
- }
-
- return actualType;
- }
- finally
- {
- __configLock.ExitReadLock();
- }
- }
+ => _serializationDomain.LookupActualType(nominalType, discriminator);
///
/// Looks up the discriminator convention for a type.
@@ -406,76 +220,7 @@ public static Type LookupActualType(Type nominalType, BsonValue discriminator)
/// The type.
/// A discriminator convention.
public static IDiscriminatorConvention LookupDiscriminatorConvention(Type type)
- {
- __configLock.EnterReadLock();
- try
- {
- IDiscriminatorConvention convention;
- if (__discriminatorConventions.TryGetValue(type, out convention))
- {
- return convention;
- }
- }
- finally
- {
- __configLock.ExitReadLock();
- }
-
- __configLock.EnterWriteLock();
- try
- {
- IDiscriminatorConvention convention;
- if (!__discriminatorConventions.TryGetValue(type, out convention))
- {
- var typeInfo = type.GetTypeInfo();
- if (type == typeof(object))
- {
- // if there is no convention registered for object register the default one
- convention = new ObjectDiscriminatorConvention("_t");
- RegisterDiscriminatorConvention(typeof(object), convention);
- }
- else if (typeInfo.IsInterface)
- {
- // TODO: should convention for interfaces be inherited from parent interfaces?
- convention = LookupDiscriminatorConvention(typeof(object));
- RegisterDiscriminatorConvention(type, convention);
- }
- else
- {
- // inherit the discriminator convention from the closest parent (that isn't object) that has one
- // otherwise default to the standard scalar convention
- Type parentType = typeInfo.BaseType;
- while (true)
- {
- if (parentType == typeof(object))
- {
- convention = StandardDiscriminatorConvention.Scalar;
- break;
- }
- if (__discriminatorConventions.TryGetValue(parentType, out convention))
- {
- break;
- }
- parentType = parentType.GetTypeInfo().BaseType;
- }
-
- // register this convention for all types between this and the parent type where we found the convention
- var unregisteredType = type;
- while (unregisteredType != parentType)
- {
- RegisterDiscriminatorConvention(unregisteredType, convention);
- unregisteredType = unregisteredType.GetTypeInfo().BaseType;
- }
- }
- }
-
- return convention;
- }
- finally
- {
- __configLock.ExitWriteLock();
- }
- }
+ => _serializationDomain.LookupDiscriminatorConvention(type);
///
/// Looks up an IdGenerator.
@@ -483,78 +228,21 @@ public static IDiscriminatorConvention LookupDiscriminatorConvention(Type type)
/// The Id type.
/// An IdGenerator for the Id type.
public static IIdGenerator LookupIdGenerator(Type type)
- {
- __configLock.EnterReadLock();
- try
- {
- IIdGenerator idGenerator;
- if (__idGenerators.TryGetValue(type, out idGenerator))
- {
- return idGenerator;
- }
- }
- finally
- {
- __configLock.ExitReadLock();
- }
-
- __configLock.EnterWriteLock();
- try
- {
- IIdGenerator idGenerator;
- if (!__idGenerators.TryGetValue(type, out idGenerator))
- {
- var typeInfo = type.GetTypeInfo();
- if (typeInfo.IsValueType && __useZeroIdChecker)
- {
- var iEquatableDefinition = typeof(IEquatable<>);
- var iEquatableType = iEquatableDefinition.MakeGenericType(type);
- if (iEquatableType.GetTypeInfo().IsAssignableFrom(type))
- {
- var zeroIdCheckerDefinition = typeof(ZeroIdChecker<>);
- var zeroIdCheckerType = zeroIdCheckerDefinition.MakeGenericType(type);
- idGenerator = (IIdGenerator)Activator.CreateInstance(zeroIdCheckerType);
- }
- }
- else if (__useNullIdChecker)
- {
- idGenerator = NullIdChecker.Instance;
- }
- else
- {
- idGenerator = null;
- }
-
- __idGenerators[type] = idGenerator; // remember it even if it's null
- }
-
- return idGenerator;
- }
- finally
- {
- __configLock.ExitWriteLock();
- }
- }
+ => _serializationDomain.LookupIdGenerator(type);
///
/// Looks up a serializer for a Type.
///
/// The type.
/// A serializer for type T.
- public static IBsonSerializer LookupSerializer()
- {
- return (IBsonSerializer)LookupSerializer(typeof(T));
- }
+ public static IBsonSerializer LookupSerializer() => _serializationDomain.LookupSerializer();
///
/// Looks up a serializer for a Type.
///
/// The Type.
/// A serializer for the Type.
- public static IBsonSerializer LookupSerializer(Type type)
- {
- return __serializerRegistry.GetSerializer(type);
- }
+ public static IBsonSerializer LookupSerializer(Type type) => _serializationDomain.LookupSerializer(type);
///
/// Registers the discriminator for a type.
@@ -562,40 +250,7 @@ public static IBsonSerializer LookupSerializer(Type type)
/// The type.
/// The discriminator.
public static void RegisterDiscriminator(Type type, BsonValue discriminator)
- {
- var typeInfo = type.GetTypeInfo();
- if (typeInfo.IsInterface)
- {
- var message = string.Format("Discriminators can only be registered for classes, not for interface {0}.", type.FullName);
- throw new BsonSerializationException(message);
- }
-
- __configLock.EnterWriteLock();
- try
- {
- HashSet hashSet;
- if (!__discriminators.TryGetValue(discriminator, out hashSet))
- {
- hashSet = new HashSet();
- __discriminators.Add(discriminator, hashSet);
- }
-
- if (!hashSet.Contains(type))
- {
- hashSet.Add(type);
-
- // mark all base types as discriminated (so we know that it's worth reading a discriminator)
- for (var baseType = typeInfo.BaseType; baseType != null; baseType = baseType.GetTypeInfo().BaseType)
- {
- __discriminatedTypes.Add(baseType);
- }
- }
- }
- finally
- {
- __configLock.ExitWriteLock();
- }
- }
+ => _serializationDomain.RegisterDiscriminator(type, discriminator);
///
/// Registers the discriminator convention for a type.
@@ -603,37 +258,15 @@ public static void RegisterDiscriminator(Type type, BsonValue discriminator)
/// Type type.
/// The discriminator convention.
public static void RegisterDiscriminatorConvention(Type type, IDiscriminatorConvention convention)
- {
- __configLock.EnterWriteLock();
- try
- {
- if (!__discriminatorConventions.ContainsKey(type))
- {
- __discriminatorConventions.Add(type, convention);
- }
- else
- {
- var message = string.Format("There is already a discriminator convention registered for type {0}.", type.FullName);
- throw new BsonSerializationException(message);
- }
- }
- finally
- {
- __configLock.ExitWriteLock();
- }
- }
+ => _serializationDomain.RegisterDiscriminatorConvention(type, convention);
///
/// Registers a generic serializer definition for a generic type.
///
/// The generic type.
/// The generic serializer definition.
- public static void RegisterGenericSerializerDefinition(
- Type genericTypeDefinition,
- Type genericSerializerDefinition)
- {
- __typeMappingSerializationProvider.RegisterMapping(genericTypeDefinition, genericSerializerDefinition);
- }
+ public static void RegisterGenericSerializerDefinition(Type genericTypeDefinition, Type genericSerializerDefinition)
+ => _serializationDomain.RegisterGenericSerializerDefinition(genericTypeDefinition, genericSerializerDefinition);
///
/// Registers an IdGenerator for an Id Type.
@@ -641,26 +274,14 @@ public static void RegisterGenericSerializerDefinition(
/// The Id Type.
/// The IdGenerator for the Id Type.
public static void RegisterIdGenerator(Type type, IIdGenerator idGenerator)
- {
- __configLock.EnterWriteLock();
- try
- {
- __idGenerators[type] = idGenerator;
- }
- finally
- {
- __configLock.ExitWriteLock();
- }
- }
+ => _serializationDomain.RegisterIdGenerator(type, idGenerator);
///
/// Registers a serialization provider.
///
/// The serialization provider.
public static void RegisterSerializationProvider(IBsonSerializationProvider provider)
- {
- __serializerRegistry.RegisterSerializationProvider(provider);
- }
+ => _serializationDomain.RegisterSerializationProvider(provider);
///
/// Registers a serializer for a type.
@@ -668,9 +289,7 @@ public static void RegisterSerializationProvider(IBsonSerializationProvider prov
/// The type.
/// The serializer.
public static void RegisterSerializer(IBsonSerializer serializer)
- {
- RegisterSerializer(typeof(T), serializer);
- }
+ => _serializationDomain.RegisterSerializer(serializer);
///
/// Registers a serializer for a type.
@@ -678,9 +297,7 @@ public static void RegisterSerializer(IBsonSerializer serializer)
/// The type.
/// The serializer.
public static void RegisterSerializer(Type type, IBsonSerializer serializer)
- {
- __serializerRegistry.RegisterSerializer(type, serializer);
- }
+ => _serializationDomain.RegisterSerializer(type, serializer);
///
/// Serializes a value.
@@ -694,13 +311,8 @@ public static void Serialize(
IBsonWriter bsonWriter,
TNominalType value,
Action configurator = null,
- BsonSerializationArgs args = default(BsonSerializationArgs))
- {
- args.SetOrValidateNominalType(typeof(TNominalType), "");
- var serializer = LookupSerializer();
- var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator);
- serializer.Serialize(context, args, value);
- }
+ BsonSerializationArgs args = default)
+ => _serializationDomain.Serialize(bsonWriter, value, configurator, args);
///
/// Serializes a value.
@@ -716,12 +328,7 @@ public static void Serialize(
object value,
Action configurator = null,
BsonSerializationArgs args = default(BsonSerializationArgs))
- {
- args.SetOrValidateNominalType(nominalType, "nominalType");
- var serializer = LookupSerializer(nominalType);
- var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator);
- serializer.Serialize(context, args, value);
- }
+ => _serializationDomain.Serialize(bsonWriter, nominalType, value, configurator, args);
///
/// Tries to register a serializer for a type.
@@ -730,9 +337,7 @@ public static void Serialize(
/// The type.
/// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.
public static bool TryRegisterSerializer(Type type, IBsonSerializer serializer)
- {
- return __serializerRegistry.TryRegisterSerializer(type, serializer);
- }
+ => _serializationDomain.TryRegisterSerializer(type, serializer);
///
/// Tries to register a serializer for a type.
@@ -741,95 +346,13 @@ public static bool TryRegisterSerializer(Type type, IBsonSerializer serializer)
/// The serializer.
/// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.
public static bool TryRegisterSerializer(IBsonSerializer serializer)
- {
- return TryRegisterSerializer(typeof(T), serializer);
- }
+ => _serializationDomain.TryRegisterSerializer(serializer);
// internal static methods
internal static void EnsureKnownTypesAreRegistered(Type nominalType)
- {
- if (__typesWithRegisteredKnownTypes.ContainsKey(nominalType))
- {
- return;
- }
-
- __configLock.EnterWriteLock();
- try
- {
- if (!__typesWithRegisteredKnownTypes.ContainsKey(nominalType))
- {
- // only call LookupClassMap for classes with a BsonKnownTypesAttribute
- var hasKnownTypesAttribute = nominalType.GetTypeInfo().GetCustomAttributes(typeof(BsonKnownTypesAttribute), inherit: false).Any();
- if (hasKnownTypesAttribute)
- {
- // try and force a scan of the known types
- LookupSerializer(nominalType);
- }
-
- // NOTE: The nominalType MUST be added to __typesWithRegisteredKnownTypes after all registration
- // work is done to ensure that other threads don't access a partially registered nominalType
- // when performing the initial check above outside the __config lock.
- __typesWithRegisteredKnownTypes[nominalType] = null;
- }
- }
- finally
- {
- __configLock.ExitWriteLock();
- }
- }
+ => _serializationDomain.EnsureKnownTypesAreRegistered(nominalType);
- // internal static methods
internal static BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type)
- {
- // note: EnsureKnownTypesAreRegistered handles its own locking so call from outside any lock
- EnsureKnownTypesAreRegistered(type);
-
- var discriminators = new List();
-
- __configLock.EnterReadLock();
- try
- {
- foreach (var entry in __discriminators)
- {
- var discriminator = entry.Key;
- var actualTypes = entry.Value;
-
- var matchingType = actualTypes.SingleOrDefault(t => t == type || t.IsSubclassOf(type));
- if (matchingType != null)
- {
- discriminators.Add(discriminator);
- }
- }
- }
- finally
- {
- __configLock.ExitReadLock();
- }
-
- return discriminators.OrderBy(x => x).ToArray();
- }
-
- // private static methods
- private static void CreateSerializerRegistry()
- {
- __serializerRegistry = new BsonSerializerRegistry();
- __typeMappingSerializationProvider = new TypeMappingSerializationProvider();
-
- // order matters. It's in reverse order of how they'll get consumed
- __serializerRegistry.RegisterSerializationProvider(new BsonClassMapSerializationProvider());
- __serializerRegistry.RegisterSerializationProvider(new DiscriminatedInterfaceSerializationProvider());
- __serializerRegistry.RegisterSerializationProvider(new CollectionsSerializationProvider());
- __serializerRegistry.RegisterSerializationProvider(new PrimitiveSerializationProvider());
- __serializerRegistry.RegisterSerializationProvider(new AttributedSerializationProvider());
- __serializerRegistry.RegisterSerializationProvider(__typeMappingSerializationProvider);
- __serializerRegistry.RegisterSerializationProvider(new BsonObjectModelSerializationProvider());
- }
-
- private static void RegisterIdGenerators()
- {
- RegisterIdGenerator(typeof(BsonObjectId), BsonObjectIdGenerator.Instance);
- RegisterIdGenerator(typeof(Guid), GuidGenerator.Instance);
- RegisterIdGenerator(typeof(ObjectId), ObjectIdGenerator.Instance);
- }
+ => _serializationDomain.GetDiscriminatorsForTypeAndSubTypes(type);
}
}
diff --git a/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs b/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs
index 429386f6019..8010f647c28 100644
--- a/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs
+++ b/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs
@@ -22,25 +22,41 @@ namespace MongoDB.Bson.Serialization
///
/// Default, global implementation of an .
///
- public sealed class BsonSerializerRegistry : IBsonSerializerRegistry
+ public sealed class BsonSerializerRegistry : IBsonSerializerRegistryInternal
{
// private fields
private readonly ConcurrentDictionary _cache;
private readonly ConcurrentStack _serializationProviders;
private readonly Func _createSerializer;
+ private readonly IBsonSerializationDomain _serializationDomain; //FP Need to investigate if we can remove this from here.
// constructors
///
/// 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;
+ _serializationDomain = serializationDomain;
}
// public methods
+ ///
+ /// //TODO
+ ///
+ IBsonSerializationDomain IBsonSerializerRegistryInternal.SerializationDomain => _serializationDomain;
+
///
/// 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.
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..8334c8ea417 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();
@@ -135,7 +139,7 @@ public Type GetActualType(IBsonReader bsonReader, Type nominalType)
{
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..16ddc7bd29b 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs
@@ -95,17 +95,20 @@ 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();
@@ -118,7 +121,7 @@ public Type GetActualType(IBsonReader bsonReader, Type nominalType)
{
discriminator = discriminator.AsBsonArray.Last(); // last item is leaf class discriminator
}
- actualType = BsonSerializer.LookupActualType(nominalType, discriminator);
+ actualType = domain.LookupActualType(nominalType, discriminator);
}
bsonReader.ReturnToBookmark(bookmark);
return actualType;
diff --git a/src/MongoDB.Bson/Serialization/Conventions/StringIdStoredAsObjectIdConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/StringIdStoredAsObjectIdConvention.cs
index 923936d1508..d757e33b6f4 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/StringIdStoredAsObjectIdConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/StringIdStoredAsObjectIdConvention.cs
@@ -23,10 +23,13 @@ namespace MongoDB.Bson.Serialization.Conventions
/// This convention is only responsible for setting the serializer and idGenerator. It is assumed that this convention runs after
/// other conventions that identify which member is the _id and that the _id has already been added to the class map.
///
- public class StringIdStoredAsObjectIdConvention : ConventionBase, IMemberMapConvention
+ public class StringIdStoredAsObjectIdConvention : ConventionBase, IMemberMapConventionInternal
{
///
- public void Apply(BsonMemberMap memberMap)
+ public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain)
{
if (memberMap != memberMap.ClassMap.IdMemberMap)
{
@@ -38,7 +41,7 @@ public void Apply(BsonMemberMap memberMap)
return;
}
- var defaultStringSerializer = BsonSerializer.LookupSerializer(typeof(string));
+ var defaultStringSerializer = domain.LookupSerializer(typeof(string));
if (memberMap.GetSerializer() != defaultStringSerializer)
{
return;
diff --git a/src/MongoDB.Bson/Serialization/Conventions/StringObjectIdIdGeneratorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/StringObjectIdIdGeneratorConvention.cs
index 618d7213aec..0a8f48cf3db 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/StringObjectIdIdGeneratorConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/StringObjectIdIdGeneratorConvention.cs
@@ -14,7 +14,6 @@
*/
using MongoDB.Bson.Serialization.IdGenerators;
-using MongoDB.Bson.Serialization.Options;
using MongoDB.Bson.Serialization.Serializers;
namespace MongoDB.Bson.Serialization.Conventions
@@ -22,14 +21,17 @@ namespace MongoDB.Bson.Serialization.Conventions
///
/// A convention that sets the id generator for a string member with a BSON representation of ObjectId.
///
- public class StringObjectIdIdGeneratorConvention : ConventionBase, IPostProcessingConvention
+ public class StringObjectIdIdGeneratorConvention : ConventionBase, IPostProcessingConventionInternal
{
// public methods
///
/// Applies a post processing modification to the class map.
///
/// The class map.
- public void PostProcess(BsonClassMap classMap)
+ public void PostProcess(BsonClassMap classMap) => (this as IPostProcessingConventionInternal).PostProcess(classMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IPostProcessingConventionInternal.PostProcess(BsonClassMap classMap, IBsonSerializationDomain domain)
{
var idMemberMap = classMap.IdMemberMap;
if (idMemberMap != null)
diff --git a/src/MongoDB.Bson/Serialization/IBsonClassMapDomain.cs b/src/MongoDB.Bson/Serialization/IBsonClassMapDomain.cs
new file mode 100644
index 00000000000..6a0df68e291
--- /dev/null
+++ b/src/MongoDB.Bson/Serialization/IBsonClassMapDomain.cs
@@ -0,0 +1,96 @@
+/* Copyright 2010-present MongoDB Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace MongoDB.Bson.Serialization
+{
+ internal interface IBsonClassMapDomain
+ {
+ ///
+ /// Gets all registered class maps.
+ ///
+ /// All registered class maps.
+ IEnumerable GetRegisteredClassMaps();
+
+ ///
+ /// Checks whether a class map is registered for a type.
+ ///
+ /// The type to check.
+ /// True if there is a class map registered for the type.
+ bool IsClassMapRegistered(Type type);
+
+ ///
+ /// Looks up a class map (will AutoMap the class if no class map is registered).
+ ///
+ /// The class type.
+ /// The class map.
+ BsonClassMap LookupClassMap(Type classType);
+
+ ///
+ /// Creates and registers a class map.
+ ///
+ /// The class.
+ /// The class map.
+ BsonClassMap RegisterClassMap();
+
+ ///
+ /// Creates and registers a class map.
+ ///
+ /// The class.
+ /// The class map initializer.
+ /// The class map.
+ BsonClassMap RegisterClassMap(Action> classMapInitializer);
+
+ ///
+ /// Registers a class map.
+ ///
+ /// The class map.
+ void RegisterClassMap(BsonClassMap classMap);
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// True if this call registered the class map, false if the class map was already registered.
+ bool TryRegisterClassMap();
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// The class map.
+ /// True if this call registered the class map, false if the class map was already registered.
+ bool TryRegisterClassMap(BsonClassMap classMap);
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// The class map initializer (only called if the class map is not already registered).
+ /// True if this call registered the class map, false if the class map was already registered.
+ bool TryRegisterClassMap(Action> classMapInitializer);
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// The class map factory (only called if the class map is not already registered).
+ /// True if this call registered the class map, false if the class map was already registered.
+ bool TryRegisterClassMap(Func> classMapFactory);
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/Serialization/IBsonIdProvider.cs b/src/MongoDB.Bson/Serialization/IBsonIdProvider.cs
index 6cb9ba4a811..d63d71a0c10 100644
--- a/src/MongoDB.Bson/Serialization/IBsonIdProvider.cs
+++ b/src/MongoDB.Bson/Serialization/IBsonIdProvider.cs
@@ -39,4 +39,9 @@ public interface IBsonIdProvider
/// The Id.
void SetDocumentId(object document, object id);
}
+
+ internal interface IBsonIdProviderInternal : IBsonIdProvider
+ {
+ bool GetDocumentId(object document, IBsonSerializationDomain serializationDomain, out object id, out Type idNominalType, out IIdGenerator idGenerator);
+ }
}
diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs b/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs
new file mode 100644
index 00000000000..34315129a4d
--- /dev/null
+++ b/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs
@@ -0,0 +1,317 @@
+using System;
+using System.IO;
+using System.Threading;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization.Conventions;
+
+namespace MongoDB.Bson.Serialization
+{
+ ///
+ /// //TODO
+ ///
+ internal interface IBsonSerializationDomain
+ {
+ string Name { get; } //FP This is used for debugging purposes, but we could decide to make it public if needed.
+
+ ///
+ /// Returns whether the given type has any discriminators registered for any of its subclasses.
+ ///
+ /// A Type.
+ /// True if the type is discriminated.
+ bool IsTypeDiscriminated(Type type);
+
+ ///
+ /// Looks up the actual type of an object to be deserialized.
+ ///
+ /// The nominal type of the object.
+ /// The discriminator.
+ /// The actual type of the object.
+ Type LookupActualType(Type nominalType, BsonValue discriminator);
+
+ ///
+ /// Looks up the discriminator convention for a type.
+ ///
+ /// The type.
+ /// A discriminator convention.
+ IDiscriminatorConvention LookupDiscriminatorConvention(Type type);
+
+ ///
+ /// Looks up an IdGenerator.
+ ///
+ /// The Id type.
+ /// An IdGenerator for the Id type.
+ IIdGenerator LookupIdGenerator(Type type);
+
+ ///
+ /// Looks up a serializer for a Type.
+ ///
+ /// The type.
+ /// A serializer for type T.
+ IBsonSerializer LookupSerializer();
+
+ ///
+ /// Looks up a serializer for a Type.
+ ///
+ /// The Type.
+ /// A serializer for the Type.
+ IBsonSerializer LookupSerializer(Type type);
+
+ ///
+ /// Gets the serializer registry.
+ ///
+ IBsonSerializerRegistry SerializerRegistry { get; }
+
+ ///
+ /// Registers the discriminator for a type.
+ ///
+ /// The type.
+ /// The discriminator.
+ void RegisterDiscriminator(Type type, BsonValue discriminator);
+
+ ///
+ /// Registers the discriminator convention for a type.
+ ///
+ /// Type type.
+ /// The discriminator convention.
+ void RegisterDiscriminatorConvention(Type type, IDiscriminatorConvention convention);
+
+ ///
+ /// Registers a generic serializer definition for a generic type.
+ ///
+ /// The generic type.
+ /// The generic serializer definition.
+ void RegisterGenericSerializerDefinition(
+ Type genericTypeDefinition,
+ Type genericSerializerDefinition);
+
+ ///
+ /// Registers an IdGenerator for an Id Type.
+ ///
+ /// The Id Type.
+ /// The IdGenerator for the Id Type.
+ void RegisterIdGenerator(Type type, IIdGenerator idGenerator);
+
+ ///
+ /// Registers a serialization provider.
+ ///
+ /// The serialization provider.
+ void RegisterSerializationProvider(IBsonSerializationProvider provider);
+
+ ///
+ /// Registers a serializer for a type.
+ ///
+ /// The type.
+ /// The serializer.
+ void RegisterSerializer(IBsonSerializer serializer);
+
+ ///
+ /// Registers a serializer for a type.
+ ///
+ /// The type.
+ /// The serializer.
+ void RegisterSerializer(Type type, IBsonSerializer serializer);
+
+ ///
+ /// Tries to register a serializer for a type.
+ ///
+ /// The serializer.
+ /// The type.
+ /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.
+ bool TryRegisterSerializer(Type type, IBsonSerializer serializer);
+
+ ///
+ /// Tries to register a serializer for a type.
+ ///
+ /// The type.
+ /// The serializer.
+ /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.
+ bool TryRegisterSerializer(IBsonSerializer serializer);
+
+ ///
+ /// Gets or sets whether to use the NullIdChecker on reference Id types that don't have an IdGenerator registered.
+ ///
+ bool UseNullIdChecker { get; set; }
+
+ ///
+ /// Gets or sets whether to use the ZeroIdChecker on value Id types that don't have an IdGenerator registered.
+ ///
+ bool UseZeroIdChecker { get; set; }
+
+ ///
+ /// Deserializes an object from a BsonDocument.
+ ///
+ /// The nominal type of the object.
+ /// The BsonDocument.
+ /// The configurator.
+ /// A deserialized value.
+ TNominalType Deserialize(BsonDocument document,
+ Action configurator = null);
+
+ ///
+ /// Deserializes a value.
+ ///
+ /// The nominal type of the object.
+ /// The BsonReader.
+ /// The configurator.
+ /// A deserialized value.
+ TNominalType Deserialize(IBsonReader bsonReader,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a BSON byte array.
+ ///
+ /// The nominal type of the object.
+ /// The BSON byte array.
+ /// The configurator.
+ /// A deserialized value.
+ TNominalType Deserialize(byte[] bytes,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a BSON Stream.
+ ///
+ /// The nominal type of the object.
+ /// The BSON Stream.
+ /// The configurator.
+ /// A deserialized value.
+ TNominalType Deserialize(Stream stream,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a JSON string.
+ ///
+ /// The nominal type of the object.
+ /// The JSON string.
+ /// The configurator.
+ /// A deserialized value.
+ TNominalType Deserialize(string json,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a JSON TextReader.
+ ///
+ /// The nominal type of the object.
+ /// The JSON TextReader.
+ /// The configurator.
+ /// A deserialized value.
+ TNominalType Deserialize(TextReader textReader,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a BsonDocument.
+ ///
+ /// The BsonDocument.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ object Deserialize(BsonDocument document, Type nominalType,
+ Action configurator = null);
+
+ ///
+ /// Deserializes a value.
+ ///
+ /// The BsonReader.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ object Deserialize(IBsonReader bsonReader, Type nominalType,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a BSON byte array.
+ ///
+ /// The BSON byte array.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ object Deserialize(byte[] bytes, Type nominalType,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a BSON Stream.
+ ///
+ /// The BSON Stream.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ object Deserialize(Stream stream, Type nominalType,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a JSON string.
+ ///
+ /// The JSON string.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ object Deserialize(string json, Type nominalType,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a JSON TextReader.
+ ///
+ /// The JSON TextReader.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ object Deserialize(TextReader textReader, Type nominalType,
+ Action configurator = null);
+
+ ///
+ /// Serializes a value.
+ ///
+ /// The nominal type of the object.
+ /// The BsonWriter.
+ /// The object.
+ /// The serialization context configurator.
+ /// The serialization args.
+ void Serialize(
+ IBsonWriter bsonWriter,
+ TNominalType value,
+ Action configurator = null,
+ BsonSerializationArgs args = default(BsonSerializationArgs));
+
+ ///
+ /// Serializes a value.
+ ///
+ /// The BsonWriter.
+ /// The nominal type of the object.
+ /// The object.
+ /// The serialization context configurator.
+ /// The serialization args.
+ void Serialize(
+ IBsonWriter bsonWriter,
+ Type nominalType,
+ object value,
+ Action configurator = null,
+ BsonSerializationArgs args = default(BsonSerializationArgs));
+
+ ///
+ /// //TODO
+ ///
+ IBsonClassMapDomain BsonClassMap { get; }
+
+ ///
+ /// //TODO
+ ///
+ IConventionRegistryDomain ConventionRegistry { get; }
+
+ ///
+ /// //TODO
+ ///
+ IBsonDefaults BsonDefaults { get; }
+
+ //DOMAIN-API The following methods and properties were not public on BsonSerializer
+
+ void EnsureKnownTypesAreRegistered(Type nominalType);
+
+ BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type);
+
+ IDiscriminatorConvention GetOrRegisterDiscriminatorConvention(Type type,
+ IDiscriminatorConvention discriminatorConvention);
+
+ bool IsDiscriminatorConventionRegisteredAtThisLevel(Type type);
+
+ ReaderWriterLockSlim ConfigLock { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs b/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs
index cdfca5d0676..f53f767a9a3 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.
///
diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs b/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs
index fd5998c93b3..f2310ebdedd 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.
diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializerRegistry.cs b/src/MongoDB.Bson/Serialization/IBsonSerializerRegistry.cs
index 9a9d5f6b8f9..f68dfaf4294 100644
--- a/src/MongoDB.Bson/Serialization/IBsonSerializerRegistry.cs
+++ b/src/MongoDB.Bson/Serialization/IBsonSerializerRegistry.cs
@@ -36,4 +36,9 @@ public interface IBsonSerializerRegistry
/// The serializer.
IBsonSerializer GetSerializer();
}
+
+ internal interface IBsonSerializerRegistryInternal : IBsonSerializerRegistry
+ {
+ IBsonSerializationDomain SerializationDomain { get; }
+ }
}
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..48d8e07c053 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.
///
@@ -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.
///
diff --git a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs
index eb0035489e0..36719d18b57 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs
@@ -41,14 +41,14 @@ public sealed class DiscriminatedInterfaceSerializer :
// where TInterface is an interface
{
#region static
- private static IBsonSerializer CreateInterfaceSerializer()
+ private static IBsonSerializer CreateInterfaceSerializer(IBsonSerializationDomain serializationDomain)
{
var classMapDefinition = typeof(BsonClassMap<>);
var classMapType = classMapDefinition.MakeGenericType(typeof(TInterface));
var classMap = (BsonClassMap)Activator.CreateInstance(classMapType);
classMap.AutoMap();
- classMap.SetDiscriminatorConvention(BsonSerializer.LookupDiscriminatorConvention(typeof(TInterface)));
- classMap.Freeze();
+ classMap.SetDiscriminatorConvention(serializationDomain.LookupDiscriminatorConvention(typeof(TInterface)));
+ classMap.Freeze(serializationDomain);
return new BsonClassMapSerializer(classMap);
}
#endregion
@@ -75,7 +75,7 @@ public DiscriminatedInterfaceSerializer()
/// interfaceType
/// interfaceType
public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorConvention)
- : this(discriminatorConvention, CreateInterfaceSerializer(), objectSerializer: null)
+ : this(discriminatorConvention, CreateInterfaceSerializer(BsonSerializer.DefaultSerializationDomain), objectSerializer: null) //TODO Is this ok?
{
}
@@ -109,12 +109,12 @@ public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorCo
}
_interfaceType = typeof(TInterface);
- _discriminatorConvention = discriminatorConvention ?? interfaceSerializer.GetDiscriminatorConvention();
+ _discriminatorConvention = discriminatorConvention ?? interfaceSerializer.GetDiscriminatorConvention(); //QUESTION What do we do here? We don't have the domain close by, should we lazy initialize it during serialization/deserialization?
_interfaceSerializer = interfaceSerializer;
if (objectSerializer == null)
{
- objectSerializer = BsonSerializer.LookupSerializer
public TupleSerializer()
- : this(BsonSerializer.SerializerRegistry)
+ : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is
{
}
@@ -743,7 +743,7 @@ public sealed class TupleSerializer : SealedClassSeriali
/// Initializes a new instance of the class.
///
public TupleSerializer()
- : this(BsonSerializer.SerializerRegistry)
+ : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is
{
}
@@ -917,7 +917,7 @@ public sealed class TupleSerializer : SealedClassSer
/// Initializes a new instance of the class.
///
public TupleSerializer()
- : this(BsonSerializer.SerializerRegistry)
+ : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is
{
}
@@ -1107,7 +1107,7 @@ public sealed class TupleSerializer : SealedC
/// Initializes a new instance of the class.
///
public TupleSerializer()
- : this(BsonSerializer.SerializerRegistry)
+ : this(BsonSerializer.SerializerRegistry) //TODO We can keep this as is
{
}
diff --git a/src/MongoDB.Bson/Serialization/Serializers/TwoDimensionalArraySerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/TwoDimensionalArraySerializer.cs
index afe701dd1c3..db1dc30d5e8 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/TwoDimensionalArraySerializer.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/TwoDimensionalArraySerializer.cs
@@ -30,6 +30,7 @@ public sealed class TwoDimensionalArraySerializer :
private readonly Lazy> _lazyItemSerializer;
// constructors
+ //DOMAIN-API This should be removed in the future.
///
/// Initializes a new instance of the class.
///
diff --git a/src/MongoDB.Bson/Serialization/Serializers/UndiscriminatedActualTypeSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/UndiscriminatedActualTypeSerializer.cs
index 1587a979163..240ac575b1b 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/UndiscriminatedActualTypeSerializer.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/UndiscriminatedActualTypeSerializer.cs
@@ -62,7 +62,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati
else
{
var actualType = value.GetType();
- var serializer = BsonSerializer.LookupSerializer(actualType);
+ var serializer = context.SerializationDomain.LookupSerializer(actualType);
args.NominalType = actualType;
serializer.Serialize(context, args, value);
}
diff --git a/src/MongoDB.Bson/Serialization/Serializers/ValueTupleSerializers.cs b/src/MongoDB.Bson/Serialization/Serializers/ValueTupleSerializers.cs
index d0f52484e58..db9cc0ae18f 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/ValueTupleSerializers.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/ValueTupleSerializers.cs
@@ -71,6 +71,7 @@ public sealed class ValueTupleSerializer : StructSerializerBase> _lazyItem1Serializer;
// constructors
+ //DOMAIN-API This should be removed in the future (also for the other versions)
///
/// Initializes a new instance of the class.
///
diff --git a/src/MongoDB.Driver.Authentication.AWS/SaslSteps/AWSLastSaslStep.cs b/src/MongoDB.Driver.Authentication.AWS/SaslSteps/AWSLastSaslStep.cs
index 7d81604edf6..8a73478fd19 100644
--- a/src/MongoDB.Driver.Authentication.AWS/SaslSteps/AWSLastSaslStep.cs
+++ b/src/MongoDB.Driver.Authentication.AWS/SaslSteps/AWSLastSaslStep.cs
@@ -82,7 +82,7 @@ private byte[] PreparePayload(AWSCredentials credentials, byte[] serverNonce, st
private void ParseServerResponse(SaslConversation conversation, byte[] bytesReceivedFromServer, out byte[] serverNonce, out string host)
{
- var serverFirstMessageDocument = BsonSerializer.Deserialize(bytesReceivedFromServer);
+ var serverFirstMessageDocument = BsonSerializer.Deserialize(bytesReceivedFromServer); //FP I think this is fine, as it should be default configuration.
if (serverFirstMessageDocument.Names.Any(n => !__serverResponseExpectedNames.Contains(n)))
{
var unexpectedNames = serverFirstMessageDocument.Names.Except(__serverResponseExpectedNames);
diff --git a/src/MongoDB.Driver.Encryption/ExplicitEncryptionLibMongoCryptController.cs b/src/MongoDB.Driver.Encryption/ExplicitEncryptionLibMongoCryptController.cs
index 657a4cfa87b..cc268c97d4c 100644
--- a/src/MongoDB.Driver.Encryption/ExplicitEncryptionLibMongoCryptController.cs
+++ b/src/MongoDB.Driver.Encryption/ExplicitEncryptionLibMongoCryptController.cs
@@ -102,7 +102,7 @@ public Guid CreateDataKey(
{
var wrappedKeyBytes = ProcessStates(context, _keyVaultNamespace.DatabaseNamespace.DatabaseName, cancellationToken);
- var wrappedKeyDocument = BsonSerializer.Deserialize(wrappedKeyBytes);
+ var wrappedKeyDocument = BsonSerializer.Deserialize(wrappedKeyBytes); //FP I think this is fine, as it should be default configuration.
var keyId = UnwrapKeyId(wrappedKeyDocument);
_keyVaultCollection.Value.InsertOne(wrappedKeyDocument, cancellationToken: cancellationToken);
@@ -131,7 +131,7 @@ public async Task CreateDataKeyAsync(
{
var wrappedKeyBytes = await ProcessStatesAsync(context, _keyVaultNamespace.DatabaseNamespace.DatabaseName, cancellationToken).ConfigureAwait(false);
- var wrappedKeyDocument = BsonSerializer.Deserialize(wrappedKeyBytes);
+ var wrappedKeyDocument = BsonSerializer.Deserialize(wrappedKeyBytes); //FP I think this is fine, as it should be default configuration.
var keyId = UnwrapKeyId(wrappedKeyDocument);
await _keyVaultCollection.Value.InsertOneAsync(wrappedKeyDocument, cancellationToken: cancellationToken).ConfigureAwait(false);
@@ -553,7 +553,7 @@ private byte[] GetWrappedValueBytes(BsonValue value)
private static BsonValue RenderFilter(FilterDefinition filter)
{
- var registry = BsonSerializer.SerializerRegistry;
+ var registry = BsonSerializer.SerializerRegistry; //FP I think this is fine, as it should be default configuration.
var serializer = registry.GetSerializer();
return filter.Render(new(serializer, registry));
}
@@ -570,7 +570,7 @@ private static Guid UnwrapKeyId(BsonDocument wrappedKeyDocument)
private static BsonValue UnwrapValue(byte[] encryptedWrappedBytes)
{
- var bsonDocument = BsonSerializer.Deserialize(encryptedWrappedBytes);
+ var bsonDocument = BsonSerializer.Deserialize(encryptedWrappedBytes); //FP I think this is fine, as it should be default configuration.
return bsonDocument["v"];
}
}
diff --git a/src/MongoDB.Driver/AggregateExpressionDefinition.cs b/src/MongoDB.Driver/AggregateExpressionDefinition.cs
index 85ae3f37e6a..eb898f917f0 100644
--- a/src/MongoDB.Driver/AggregateExpressionDefinition.cs
+++ b/src/MongoDB.Driver/AggregateExpressionDefinition.cs
@@ -140,7 +140,7 @@ internal ExpressionAggregateExpressionDefinition(
public override BsonValue Render(RenderArgs args)
{
var contextData = _contextData?.With("SerializerRegistry", args.SerializerRegistry);
- return LinqProviderAdapter.TranslateExpressionToAggregateExpression(_expression, args.DocumentSerializer, args.SerializerRegistry, args.TranslationOptions, contextData);
+ return LinqProviderAdapter.TranslateExpressionToAggregateExpression(_expression, args.DocumentSerializer, args.SerializationDomain, args.TranslationOptions, contextData);
}
}
diff --git a/src/MongoDB.Driver/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..c3ca717febf 100644
--- a/src/MongoDB.Driver/ChangeStreamHelper.cs
+++ b/src/MongoDB.Driver/ChangeStreamHelper.cs
@@ -32,7 +32,8 @@ public static ChangeStreamOperation CreateChangeStreamOperation(MessageEncoderSettingsName.SerializationDomain, null);
+ var renderedPipeline = RenderPipeline(pipeline, BsonDocumentSerializer.Instance, serializationDomain, translationOptions);
var operation = new ChangeStreamOperation(
renderedPipeline.Documents,
@@ -55,7 +56,8 @@ public static ChangeStreamOperation CreateChangeStreamOperation(MessageEncoderSettingsName.SerializationDomain, null);
+ var renderedPipeline = RenderPipeline(pipeline, BsonDocumentSerializer.Instance, serializationDomain, translationOptions);
var operation = new ChangeStreamOperation(
database.DatabaseNamespace,
@@ -80,7 +82,8 @@ public static ChangeStreamOperation CreateChangeStreamOperation(MessageEncoderSettingsName.SerializationDomain, null);
+ var renderedPipeline = RenderPipeline(pipeline, documentSerializer, serializationDomain, translationOptions);
var operation = new ChangeStreamOperation(
collection.CollectionNamespace,
@@ -99,11 +102,11 @@ public static ChangeStreamOperation CreateChangeStreamOperation RenderPipeline(
PipelineDefinition, TResult> pipeline,
IBsonSerializer documentSerializer,
+ IBsonSerializationDomain serializationDomain,
ExpressionTranslationOptions translationOptions)
{
var changeStreamDocumentSerializer = new ChangeStreamDocumentSerializer(documentSerializer);
- var serializerRegistry = BsonSerializer.SerializerRegistry;
- return pipeline.Render(new(changeStreamDocumentSerializer, serializerRegistry, translationOptions: translationOptions));
+ return pipeline.Render(new(changeStreamDocumentSerializer, serializationDomain, translationOptions: translationOptions));
}
private static void SetOperationOptions(
diff --git a/src/MongoDB.Driver/ClusteredIndexOptions.cs b/src/MongoDB.Driver/ClusteredIndexOptions.cs
index cb3b597ee19..64d886b6e1e 100644
--- a/src/MongoDB.Driver/ClusteredIndexOptions.cs
+++ b/src/MongoDB.Driver/ClusteredIndexOptions.cs
@@ -64,6 +64,7 @@ public bool Unique
set => _unique = value;
}
+ //DOMAIN-API This version will need to go away.
internal BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry, ExpressionTranslationOptions translationOptions)
{
return new BsonDocument {
@@ -72,5 +73,14 @@ internal BsonDocument Render(IBsonSerializer documentSerializer, IBso
{ "name", _name, _name != null }
};
}
+
+ internal BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializationDomain serializationDomain, ExpressionTranslationOptions translationOptions)
+ {
+ return new BsonDocument {
+ { "key", _key.Render(new(documentSerializer, serializationDomain, translationOptions: translationOptions)) },
+ { "unique", _unique },
+ { "name", _name, _name != null }
+ };
+ }
}
}
diff --git a/src/MongoDB.Driver/Core/Operations/CursorBatchDeserializationHelper.cs b/src/MongoDB.Driver/Core/Operations/CursorBatchDeserializationHelper.cs
index 27ff4252dc0..6fa3bd744a3 100644
--- a/src/MongoDB.Driver/Core/Operations/CursorBatchDeserializationHelper.cs
+++ b/src/MongoDB.Driver/Core/Operations/CursorBatchDeserializationHelper.cs
@@ -44,6 +44,8 @@ public static List DeserializeBatch(RawBsonArray batch, IB
if (messageEncoderSettings != null)
{
readerSettings.Encoding = messageEncoderSettings.GetOrDefault(MessageEncoderSettingsName.ReadEncoding, Utf8Encodings.Strict);
+ readerSettings.SerializationDomain =
+ messageEncoderSettings.GetOrDefault(MessageEncoderSettingsName.SerializationDomain, null);
};
using (var stream = new ByteBufferStream(batch.Slice, ownsBuffer: false))
diff --git a/src/MongoDB.Driver/Core/Operations/GroupOperation.cs b/src/MongoDB.Driver/Core/Operations/GroupOperation.cs
index 4c987e09300..f7a4f55e32a 100644
--- a/src/MongoDB.Driver/Core/Operations/GroupOperation.cs
+++ b/src/MongoDB.Driver/Core/Operations/GroupOperation.cs
@@ -165,7 +165,7 @@ public async Task> ExecuteAsync(OperationContext operationC
private ReadCommandOperation CreateOperation()
{
var command = CreateCommand();
- var resultSerializer = _resultSerializer ?? BsonSerializer.LookupSerializer();
+ var resultSerializer = _resultSerializer ?? _messageEncoderSettings.GetOrDefault(MessageEncoderSettingsName.SerializationDomain, BsonSerializer.DefaultSerializationDomain).LookupSerializer();
var resultArraySerializer = new ArraySerializer(resultSerializer);
var commandResultSerializer = new ElementDeserializer("retval", resultArraySerializer);
return new ReadCommandOperation(_collectionNamespace.DatabaseNamespace, command, commandResultSerializer, _messageEncoderSettings)
diff --git a/src/MongoDB.Driver/Core/Operations/RetryableInsertCommandOperation.cs b/src/MongoDB.Driver/Core/Operations/RetryableInsertCommandOperation.cs
index 1952ad2d019..d82c1ec4a22 100644
--- a/src/MongoDB.Driver/Core/Operations/RetryableInsertCommandOperation.cs
+++ b/src/MongoDB.Driver/Core/Operations/RetryableInsertCommandOperation.cs
@@ -139,7 +139,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/WireProtocol/Messages/Encoders/BinaryEncoders/ClientBulkWriteOpsSectionFormatter.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ClientBulkWriteOpsSectionFormatter.cs
index 8fce04fb521..024a8a47b29 100644
--- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ClientBulkWriteOpsSectionFormatter.cs
+++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/ClientBulkWriteOpsSectionFormatter.cs
@@ -63,7 +63,7 @@ public void FormatSection(ClientBulkWriteOpsCommandMessageSection section, IBson
throw new ArgumentException("Writer must be an instance of BsonBinaryWriter.");
}
- _serializerRegistry = BsonSerializer.SerializerRegistry;
+ _serializerRegistry = writer.Settings.SerializationDomain.SerializerRegistry;
var serializationContext = BsonSerializationContext.CreateRoot(binaryWriter);
_idsMap = section.IdsMap;
var stream = binaryWriter.BsonStream;
@@ -149,7 +149,7 @@ public void RenderInsertOne(RenderArgs renderArgs, Bson
{
WriteStartModel(serializationContext, "insert", model);
var documentSerializer = _serializerRegistry.GetSerializer();
- var documentId = documentSerializer.SetDocumentIdIfMissing(null, model.Document);
+ var documentId = documentSerializer.SetDocumentIdIfMissing(null, model.Document, serializationContext.SerializationDomain);
_idsMap[_currentIndex] = BsonValue.Create(documentId);
serializationContext.Writer.WriteName("document");
documentSerializer.Serialize(serializationContext, model.Document);
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..bd1dea93679 100644
--- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs
+++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/BinaryEncoders/MessageBinaryEncoderBase.cs
@@ -17,6 +17,7 @@
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
@@ -102,6 +103,8 @@ public BsonBinaryWriter CreateBinaryWriter()
writerSettings.Encoding = _encoderSettings.GetOrDefault(MessageEncoderSettingsName.WriteEncoding, writerSettings.Encoding);
writerSettings.MaxDocumentSize = _encoderSettings.GetOrDefault(MessageEncoderSettingsName.MaxDocumentSize, writerSettings.MaxDocumentSize);
writerSettings.MaxSerializationDepth = _encoderSettings.GetOrDefault(MessageEncoderSettingsName.MaxSerializationDepth, writerSettings.MaxSerializationDepth);
+ writerSettings.SerializationDomain =
+ _encoderSettings.GetOrDefault(MessageEncoderSettingsName.SerializationDomain, writerSettings.SerializationDomain);
}
return new BsonBinaryWriter(_stream, writerSettings);
}
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..dde00d280c2 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
@@ -65,6 +66,8 @@ public JsonWriter CreateJsonWriter()
writerSettings.NewLineChars = _encoderSettings.GetOrDefault(MessageEncoderSettingsName.NewLineChars, "");
writerSettings.OutputMode = _encoderSettings.GetOrDefault(MessageEncoderSettingsName.OutputMode, JsonOutputMode.Shell);
writerSettings.ShellVersion = _encoderSettings.GetOrDefault(MessageEncoderSettingsName.ShellVersion, new Version(2, 6, 0));
+ writerSettings.SerializationDomain =
+ _encoderSettings.GetOrDefault(MessageEncoderSettingsName.SerializationDomain, null); //FP Using null here to find issues faster
}
return new JsonWriter(_textWriter, writerSettings);
}
diff --git a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs
index 30c2e33e2fd..a3942ce852b 100644
--- a/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs
+++ b/src/MongoDB.Driver/Core/WireProtocol/Messages/Encoders/MessageEncoderSettings.cs
@@ -41,6 +41,7 @@ internal static class MessageEncoderSettingsName
public const string ShellVersion = nameof(ShellVersion);
// other encoders (if any) might use additional settings
+ public const string SerializationDomain = nameof(SerializationDomain); //QUESTION Does this make sense? It was the easiest way to pass the serialization domain.
}
internal sealed class MessageEncoderSettings : IEnumerable>
diff --git a/src/MongoDB.Driver/CreateCollectionOptions.cs b/src/MongoDB.Driver/CreateCollectionOptions.cs
index 9e0e19e5a44..32f9192b6fd 100644
--- a/src/MongoDB.Driver/CreateCollectionOptions.cs
+++ b/src/MongoDB.Driver/CreateCollectionOptions.cs
@@ -38,6 +38,7 @@ public class CreateCollectionOptions
private TimeSeriesOptions _timeSeriesOptions;
private bool? _usePowerOf2Sizes;
private IBsonSerializerRegistry _serializerRegistry;
+ private IBsonSerializationDomain _serializationDomain;
private DocumentValidationAction? _validationAction;
private DocumentValidationLevel? _validationLevel;
@@ -126,6 +127,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.
///
@@ -135,6 +138,12 @@ public IBsonSerializerRegistry SerializerRegistry
set { _serializerRegistry = value; }
}
+ internal IBsonSerializationDomain SerializationDomain
+ {
+ get => _serializationDomain;
+ set => _serializationDomain = value;
+ }
+
///
/// Gets or sets the storage engine options.
///
@@ -203,6 +212,7 @@ public virtual CreateCollectionOptions Clone() =>
_maxSize = _maxSize,
_noPadding = _noPadding,
_serializerRegistry = _serializerRegistry,
+ _serializationDomain = _serializationDomain,
_storageEngine = _storageEngine,
_timeSeriesOptions = _timeSeriesOptions,
_usePowerOf2Sizes = _usePowerOf2Sizes,
@@ -245,6 +255,7 @@ internal static CreateCollectionOptions CoercedFrom(CreateCollectionO
MaxSize = options.MaxSize,
NoPadding = options.NoPadding,
SerializerRegistry = options.SerializerRegistry,
+ SerializationDomain = options.SerializationDomain,
StorageEngine = options.StorageEngine,
TimeSeriesOptions = options.TimeSeriesOptions,
UsePowerOf2Sizes = options.UsePowerOf2Sizes,
diff --git a/src/MongoDB.Driver/CreateViewOptions.cs b/src/MongoDB.Driver/CreateViewOptions.cs
index 1226e714841..0ec4e4ffd3e 100644
--- a/src/MongoDB.Driver/CreateViewOptions.cs
+++ b/src/MongoDB.Driver/CreateViewOptions.cs
@@ -27,6 +27,7 @@ public class CreateViewOptions
private Collation _collation;
private IBsonSerializer _documentSerializer;
private IBsonSerializerRegistry _serializerRegistry;
+ private IBsonSerializationDomain _serializationDomain;
// properties
///
@@ -53,6 +54,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.
///
@@ -64,5 +67,11 @@ public IBsonSerializerRegistry SerializerRegistry
get { return _serializerRegistry; }
set { _serializerRegistry = value; }
}
+
+ internal IBsonSerializationDomain SerializationDomain
+ {
+ get => _serializationDomain;
+ set => _serializationDomain = value;
+ }
}
}
diff --git a/src/MongoDB.Driver/FieldDefinition.cs b/src/MongoDB.Driver/FieldDefinition.cs
index 6a3f1319da6..9b850457aff 100644
--- a/src/MongoDB.Driver/FieldDefinition.cs
+++ b/src/MongoDB.Driver/FieldDefinition.cs
@@ -242,7 +242,7 @@ public LambdaExpression Expression
///
public override RenderedFieldDefinition Render(RenderArgs args)
{
- return LinqProviderAdapter.TranslateExpressionToField(_expression, args.DocumentSerializer, args.SerializerRegistry, args.TranslationOptions);
+ return LinqProviderAdapter.TranslateExpressionToField(_expression, args.DocumentSerializer, args.SerializationDomain, args.TranslationOptions);
}
}
@@ -275,7 +275,7 @@ public Expression> Expression
///
public override RenderedFieldDefinition Render(RenderArgs args)
{
- return LinqProviderAdapter.TranslateExpressionToField(_expression, args.DocumentSerializer, args.SerializerRegistry, args.TranslationOptions, args.PathRenderArgs.AllowScalarValueForArray);
+ return LinqProviderAdapter.TranslateExpressionToField(_expression, args.DocumentSerializer, args.SerializationDomain, args.TranslationOptions, args.PathRenderArgs.AllowScalarValueForArray);
}
}
diff --git a/src/MongoDB.Driver/FieldValueSerializerHelper.cs b/src/MongoDB.Driver/FieldValueSerializerHelper.cs
index 68880f7fe18..26110109b03 100644
--- a/src/MongoDB.Driver/FieldValueSerializerHelper.cs
+++ b/src/MongoDB.Driver/FieldValueSerializerHelper.cs
@@ -20,6 +20,7 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Linq.Linq3Implementation.Serializers;
using MongoDB.Driver.Support;
namespace MongoDB.Driver
@@ -51,7 +52,7 @@ public static IBsonSerializer GetSerializerForValueType(IBsonSerializer fieldSer
// serialize numeric values without converting them
if (fieldType.IsNumeric() && valueType.IsNumeric())
{
- var valueSerializer = BsonSerializer.SerializerRegistry.GetSerializer(valueType);
+ var valueSerializer = StandardSerializers.GetSerializer(valueType);
if (HasStringRepresentation(fieldSerializer))
{
valueSerializer = WithStringRepresentation(valueSerializer);
diff --git a/src/MongoDB.Driver/FilterDefinition.cs b/src/MongoDB.Driver/FilterDefinition.cs
index a7e727110af..12e03969c72 100644
--- a/src/MongoDB.Driver/FilterDefinition.cs
+++ b/src/MongoDB.Driver/FilterDefinition.cs
@@ -205,11 +205,11 @@ public override BsonDocument Render(RenderArgs args)
{
if (args.RenderForElemMatch)
{
- return LinqProviderAdapter.TranslateExpressionToElemMatchFilter(_expression, elementSerializer: args.DocumentSerializer, args.SerializerRegistry, args.TranslationOptions);
+ return LinqProviderAdapter.TranslateExpressionToElemMatchFilter(_expression, elementSerializer: args.DocumentSerializer, args.SerializationDomain, args.TranslationOptions);
}
else
{
- return LinqProviderAdapter.TranslateExpressionToFilter(_expression, args.DocumentSerializer, args.SerializerRegistry, args.TranslationOptions);
+ return LinqProviderAdapter.TranslateExpressionToFilter(_expression, args.DocumentSerializer, args.SerializationDomain, args.TranslationOptions);
}
}
}
diff --git a/src/MongoDB.Driver/FilterDefinitionBuilder.cs b/src/MongoDB.Driver/FilterDefinitionBuilder.cs
index e07d9ac957c..c401e1dba30 100644
--- a/src/MongoDB.Driver/FilterDefinitionBuilder.cs
+++ b/src/MongoDB.Driver/FilterDefinitionBuilder.cs
@@ -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.")
};
}
diff --git a/src/MongoDB.Driver/FindFluent.cs b/src/MongoDB.Driver/FindFluent.cs
index cc25e841b29..e8f5dfd876c 100644
--- a/src/MongoDB.Driver/FindFluent.cs
+++ b/src/MongoDB.Driver/FindFluent.cs
@@ -282,7 +282,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/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 7bd029044b8..e7e8957129a 100644
--- a/src/MongoDB.Driver/GridFS/GridFSBucket.cs
+++ b/src/MongoDB.Driver/GridFS/GridFSBucket.cs
@@ -675,7 +675,7 @@ 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);
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/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/IInheritableMongoClientSettings.cs b/src/MongoDB.Driver/IInheritableMongoClientSettings.cs
index 04eb99990f3..86b5854fee3 100644
--- a/src/MongoDB.Driver/IInheritableMongoClientSettings.cs
+++ b/src/MongoDB.Driver/IInheritableMongoClientSettings.cs
@@ -16,6 +16,7 @@
using System;
using System.Text;
using MongoDB.Bson;
+using MongoDB.Bson.Serialization;
namespace MongoDB.Driver
{
@@ -24,6 +25,7 @@ internal interface IInheritableMongoClientSettings
ReadConcern ReadConcern { get; }
UTF8Encoding ReadEncoding { get; }
ReadPreference ReadPreference { get; }
+ IBsonSerializationDomain SerializationDomain { get; set; }
WriteConcern WriteConcern { get; }
UTF8Encoding WriteEncoding { get; }
}
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/GroupingWithOutputExpressionStageDefinitions.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/GroupingWithOutputExpressionStageDefinitions.cs
index 4d62eaea95c..565cf37e6c9 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/GroupingWithOutputExpressionStageDefinitions.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/GroupingWithOutputExpressionStageDefinitions.cs
@@ -42,9 +42,8 @@ public GroupingWithOutputExpressionStageDefinition(Expression Render(RenderArgs args)
{
var inputSerializer = args.DocumentSerializer;
- var serializerRegistry = args.SerializerRegistry;
- var groupingStage = RenderGroupingStage(inputSerializer, serializerRegistry, args.TranslationOptions, out var groupingSerializer);
- var projectStage = RenderProjectStage(groupingSerializer, serializerRegistry, args.TranslationOptions, out var outputSerializer);
+ var groupingStage = RenderGroupingStage(inputSerializer, args.SerializationDomain, args.TranslationOptions, out var groupingSerializer);
+ var projectStage = RenderProjectStage(groupingSerializer, args.SerializationDomain, args.TranslationOptions, out var outputSerializer);
var optimizedStages = OptimizeGroupingStages(groupingStage, projectStage, inputSerializer, outputSerializer);
var renderedStages = optimizedStages.Select(x => x.Render().AsBsonDocument);
@@ -53,18 +52,18 @@ public override RenderedPipelineStageDefinition Render(RenderArgs inputSerializer,
- IBsonSerializerRegistry serializerRegistry,
+ IBsonSerializationDomain serializationDomain,
ExpressionTranslationOptions translationOptions,
out IBsonSerializer groupingOutputSerializer);
private AstStage RenderProjectStage(
IBsonSerializer inputSerializer,
- IBsonSerializerRegistry serializerRegistry,
+ IBsonSerializationDomain serializationDomain,
ExpressionTranslationOptions translationOptions,
out IBsonSerializer outputSerializer)
{
var partiallyEvaluatedOutput = (Expression>)PartialEvaluator.EvaluatePartially(_output);
- var context = TranslationContext.Create(translationOptions);
+ var context = TranslationContext.Create(translationOptions, serializationDomain);
var outputTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, partiallyEvaluatedOutput, inputSerializer, asRoot: true);
var (projectStage, projectSerializer) = ProjectionHelper.CreateProjectStage(outputTranslation);
outputSerializer = (IBsonSerializer