diff --git a/src/MongoDB.Bson/BsonDefaults.cs b/src/MongoDB.Bson/BsonDefaults.cs
index 9352d3228ff..47c01789356 100644
--- a/src/MongoDB.Bson/BsonDefaults.cs
+++ b/src/MongoDB.Bson/BsonDefaults.cs
@@ -24,33 +24,14 @@ namespace MongoDB.Bson
///
public static class BsonDefaults
{
- // private static fields
- private static bool __dynamicArraySerializerWasSet;
- private static IBsonSerializer __dynamicArraySerializer;
- private static bool __dynamicDocumentSerializerWasSet;
- private static IBsonSerializer __dynamicDocumentSerializer;
- private static int __maxDocumentSize = int.MaxValue;
- private static int __maxSerializationDepth = 100;
-
// public static properties
///
/// Gets or sets the dynamic array serializer.
///
public static IBsonSerializer DynamicArraySerializer
{
- get
- {
- if (!__dynamicArraySerializerWasSet)
- {
- __dynamicArraySerializer = BsonSerializer.LookupSerializer>();
- }
- return __dynamicArraySerializer;
- }
- set
- {
- __dynamicArraySerializerWasSet = true;
- __dynamicArraySerializer = value;
- }
+ get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicArraySerializer;
+ set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicArraySerializer = value;
}
///
@@ -58,28 +39,22 @@ public static IBsonSerializer DynamicArraySerializer
///
public static IBsonSerializer DynamicDocumentSerializer
{
- get
- {
- if (!__dynamicDocumentSerializerWasSet)
- {
- __dynamicDocumentSerializer = BsonSerializer.LookupSerializer();
- }
- return __dynamicDocumentSerializer;
- }
- set
- {
- __dynamicDocumentSerializerWasSet = true;
- __dynamicDocumentSerializer = value;
- }
+ get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicDocumentSerializer;
+ set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.DynamicDocumentSerializer = value;
}
+ /* DOMAIN-API We should modify the API to have those two values (and in the writer/reader settings where they are used) be nullable.
+ * The problem is that we need to now when these values have been set externally or not. If they have not, then they should
+ * be retrieved from the closest domain.
+ */
+
///
/// Gets or sets the default max document size. The default is 4MiB.
///
public static int MaxDocumentSize
{
- get { return __maxDocumentSize; }
- set { __maxDocumentSize = value; }
+ get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxDocumentSize;
+ set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxDocumentSize = value;
}
///
@@ -87,8 +62,8 @@ public static int MaxDocumentSize
///
public static int MaxSerializationDepth
{
- get { return __maxSerializationDepth; }
- set { __maxSerializationDepth = value; }
+ get => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxSerializationDepth;
+ set => BsonSerializer.DefaultSerializationDomain.BsonDefaults.MaxSerializationDepth = value;
}
}
}
diff --git a/src/MongoDB.Bson/BsonDefaultsDomain.cs b/src/MongoDB.Bson/BsonDefaultsDomain.cs
new file mode 100644
index 00000000000..b105e739374
--- /dev/null
+++ b/src/MongoDB.Bson/BsonDefaultsDomain.cs
@@ -0,0 +1,73 @@
+/* Copyright 2010-present MongoDB Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.Collections.Generic;
+using System.Dynamic;
+using MongoDB.Bson.Serialization;
+
+namespace MongoDB.Bson
+{
+ internal class BsonDefaultsDomain : IBsonDefaults
+ {
+ private IBsonSerializationDomain _serializationDomain;
+ private bool _dynamicArraySerializerWasSet;
+ private IBsonSerializer _dynamicArraySerializer;
+ private bool _dynamicDocumentSerializerWasSet;
+ private IBsonSerializer _dynamicDocumentSerializer;
+
+ public BsonDefaultsDomain(IBsonSerializationDomain serializationDomain)
+ {
+ _serializationDomain = serializationDomain;
+ }
+
+ public IBsonSerializer DynamicArraySerializer
+ {
+ get
+ {
+ if (!_dynamicArraySerializerWasSet)
+ {
+ _dynamicArraySerializer = _serializationDomain.LookupSerializer>();
+ }
+ return _dynamicArraySerializer;
+ }
+ set
+ {
+ _dynamicArraySerializerWasSet = true;
+ _dynamicArraySerializer = value;
+ }
+ }
+
+ public IBsonSerializer DynamicDocumentSerializer
+ {
+ get
+ {
+ if (!_dynamicDocumentSerializerWasSet)
+ {
+ _dynamicDocumentSerializer = _serializationDomain.LookupSerializer();
+ }
+ return _dynamicDocumentSerializer;
+ }
+ set
+ {
+ _dynamicDocumentSerializerWasSet = true;
+ _dynamicDocumentSerializer = value;
+ }
+ }
+
+ public int MaxDocumentSize { get; set; } = int.MaxValue;
+
+ public int MaxSerializationDepth { get; set; } = 100;
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/BsonExtensionMethods.cs b/src/MongoDB.Bson/BsonExtensionMethods.cs
index bcb41a8271f..bd52c52e832 100644
--- a/src/MongoDB.Bson/BsonExtensionMethods.cs
+++ b/src/MongoDB.Bson/BsonExtensionMethods.cs
@@ -25,6 +25,8 @@ namespace MongoDB.Bson
///
public static class BsonExtensionMethods
{
+ //DOMAIN-API We should remove this and use the version with the domain.
+ //QUESTION: Do we want to do something now about this...? It's used also internally, but it seems in most cases it's used for "default serialization", so it should be ok.
///
/// Serializes an object to a BSON byte array.
///
@@ -49,6 +51,21 @@ public static byte[] ToBson(
return ToBson(obj, typeof(TNominalType), writerSettings, serializer, configurator, args, estimatedBsonSize);
}
+ internal static byte[] ToBson(
+ this TNominalType obj,
+ IBsonSerializationDomain serializationDomain,
+ IBsonSerializer serializer = null,
+ BsonBinaryWriterSettings writerSettings = null,
+ Action configurator = null,
+ BsonSerializationArgs args = default(BsonSerializationArgs),
+ int estimatedBsonSize = 0)
+ {
+ args.SetOrValidateNominalType(typeof(TNominalType), "");
+
+ return ToBson(obj, typeof(TNominalType), serializationDomain, writerSettings, serializer, configurator, args, estimatedBsonSize);
+ }
+
+ //DOMAIN-API We should remove this and use the version with the domain.
///
/// Serializes an object to a BSON byte array.
///
@@ -68,6 +85,17 @@ public static byte[] ToBson(
BsonBinaryWriterSettings writerSettings = null,
IBsonSerializer serializer = null,
Action configurator = null,
+ BsonSerializationArgs args = default,
+ int estimatedBsonSize = 0) => ToBson(obj, nominalType, BsonSerializer.DefaultSerializationDomain, writerSettings,
+ serializer, configurator, args, estimatedBsonSize);
+
+ internal static byte[] ToBson(
+ this object obj,
+ Type nominalType,
+ IBsonSerializationDomain serializationDomain,
+ BsonBinaryWriterSettings writerSettings = null,
+ IBsonSerializer serializer = null,
+ Action configurator = null,
BsonSerializationArgs args = default(BsonSerializationArgs),
int estimatedBsonSize = 0)
{
@@ -84,7 +112,7 @@ public static byte[] ToBson(
if (serializer == null)
{
- serializer = BsonSerializer.LookupSerializer(nominalType);
+ serializer = serializationDomain.LookupSerializer(nominalType);
}
if (serializer.ValueType != nominalType)
{
@@ -96,7 +124,7 @@ public static byte[] ToBson(
{
using (var bsonWriter = new BsonBinaryWriter(memoryStream, writerSettings ?? BsonBinaryWriterSettings.Defaults))
{
- var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator);
+ var context = BsonSerializationContext.CreateRoot(bsonWriter, serializationDomain, configurator);
serializer.Serialize(context, args, obj);
}
return memoryStream.ToArray();
@@ -138,7 +166,16 @@ public static BsonDocument ToBsonDocument(
Type nominalType,
IBsonSerializer serializer = null,
Action configurator = null,
- BsonSerializationArgs args = default(BsonSerializationArgs))
+ BsonSerializationArgs args = default) => ToBsonDocument(obj, nominalType,
+ BsonSerializer.DefaultSerializationDomain, serializer, configurator, args);
+
+ internal static BsonDocument ToBsonDocument(
+ this object obj,
+ Type nominalType,
+ IBsonSerializationDomain serializationDomain,
+ IBsonSerializer serializer = null,
+ Action configurator = null,
+ BsonSerializationArgs args = default)
{
if (nominalType == null)
{
@@ -165,7 +202,7 @@ public static BsonDocument ToBsonDocument(
return convertibleToBsonDocument.ToBsonDocument(); // use the provided ToBsonDocument method
}
- serializer = BsonSerializer.LookupSerializer(nominalType);
+ serializer = serializationDomain.LookupSerializer(nominalType);
}
if (serializer.ValueType != nominalType)
{
@@ -177,7 +214,7 @@ public static BsonDocument ToBsonDocument(
var document = new BsonDocument();
using (var bsonWriter = new BsonDocumentWriter(document))
{
- var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator);
+ var context = BsonSerializationContext.CreateRoot(bsonWriter, serializationDomain, configurator);
serializer.Serialize(context, args, obj);
}
return document;
@@ -226,6 +263,16 @@ public static string ToJson(
JsonWriterSettings writerSettings = null,
IBsonSerializer serializer = null,
Action configurator = null,
+ BsonSerializationArgs args = default)
+ => ToJson(obj, nominalType, BsonSerializer.DefaultSerializationDomain, writerSettings, serializer, configurator, args);
+
+ internal static string ToJson(
+ this object obj,
+ Type nominalType,
+ IBsonSerializationDomain domain,
+ JsonWriterSettings writerSettings = null,
+ IBsonSerializer serializer = null,
+ Action configurator = null,
BsonSerializationArgs args = default(BsonSerializationArgs))
{
if (nominalType == null)
@@ -236,7 +283,7 @@ public static string ToJson(
if (serializer == null)
{
- serializer = BsonSerializer.LookupSerializer(nominalType);
+ serializer = domain.LookupSerializer(nominalType);
}
if (serializer.ValueType != nominalType)
{
@@ -248,7 +295,7 @@ public static string ToJson(
{
using (var bsonWriter = new JsonWriter(stringWriter, writerSettings ?? JsonWriterSettings.Defaults))
{
- var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator);
+ var context = BsonSerializationContext.CreateRoot(bsonWriter, domain, configurator);
serializer.Serialize(context, args, obj);
}
return stringWriter.ToString();
diff --git a/src/MongoDB.Bson/IBsonDefaults.cs b/src/MongoDB.Bson/IBsonDefaults.cs
new file mode 100644
index 00000000000..e843c8eb4a4
--- /dev/null
+++ b/src/MongoDB.Bson/IBsonDefaults.cs
@@ -0,0 +1,39 @@
+/* Copyright 2010-present MongoDB Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using MongoDB.Bson.Serialization;
+
+namespace MongoDB.Bson
+{
+ internal interface IBsonDefaults
+ {
+ ///
+ ///
+ ///
+ IBsonSerializer DynamicArraySerializer { get; set; }
+ ///
+ ///
+ ///
+ IBsonSerializer DynamicDocumentSerializer { get; set; }
+ ///
+ ///
+ ///
+ int MaxDocumentSize { get; set; }
+ ///
+ ///
+ ///
+ int MaxSerializationDepth { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs b/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs
index 1c510ed71e3..3b1cc9f4a1e 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryReaderSettings.cs
@@ -136,7 +136,7 @@ protected override BsonReaderSettings CloneImplementation()
Encoding = _encoding,
FixOldBinarySubTypeOnInput = _fixOldBinarySubTypeOnInput,
FixOldDateTimeMaxValueOnInput = _fixOldDateTimeMaxValueOnInput,
- MaxDocumentSize = _maxDocumentSize
+ MaxDocumentSize = _maxDocumentSize,
};
return clone;
diff --git a/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs b/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs
index 96c8f3168de..5ee1a8c8676 100644
--- a/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs
+++ b/src/MongoDB.Bson/IO/BsonBinaryWriterSettings.cs
@@ -122,7 +122,7 @@ protected override BsonWriterSettings CloneImplementation()
Encoding = _encoding,
FixOldBinarySubTypeOnOutput = _fixOldBinarySubTypeOnOutput,
MaxDocumentSize = _maxDocumentSize,
- MaxSerializationDepth = MaxSerializationDepth
+ MaxSerializationDepth = MaxSerializationDepth,
};
return clone;
}
diff --git a/src/MongoDB.Bson/IO/BsonReader.cs b/src/MongoDB.Bson/IO/BsonReader.cs
index 25724b855e7..c1e119bccb0 100644
--- a/src/MongoDB.Bson/IO/BsonReader.cs
+++ b/src/MongoDB.Bson/IO/BsonReader.cs
@@ -321,13 +321,15 @@ public virtual IByteBuffer ReadRawBsonArray()
// overridden in BsonBinaryReader to read the raw bytes from the stream
// for all other streams, deserialize the array and reserialize it using a BsonBinaryWriter to get the raw bytes
- var deserializationContext = BsonDeserializationContext.CreateRoot(this);
+ //QUESTION Is it correct we only need a default domain here?
+ var deserializationContext = BsonDeserializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain);
var array = BsonArraySerializer.Instance.Deserialize(deserializationContext);
using (var memoryStream = new MemoryStream())
using (var bsonWriter = new BsonBinaryWriter(memoryStream, BsonBinaryWriterSettings.Defaults))
{
- var serializationContext = BsonSerializationContext.CreateRoot(bsonWriter);
+ //QUESTION Is it correct we only need a default domain here?
+ var serializationContext = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain);
bsonWriter.WriteStartDocument();
var startPosition = memoryStream.Position + 3; // just past BsonType, "x" and null byte
bsonWriter.WriteName("x");
@@ -351,7 +353,8 @@ public virtual IByteBuffer ReadRawBsonDocument()
// overridden in BsonBinaryReader to read the raw bytes from the stream
// for all other streams, deserialize the document and use ToBson to get the raw bytes
- var deserializationContext = BsonDeserializationContext.CreateRoot(this);
+ //QUESTION Is it correct we only need a default domain here?
+ var deserializationContext = BsonDeserializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain);
var document = BsonDocumentSerializer.Instance.Deserialize(deserializationContext);
var bytes = document.ToBson();
return new ByteArrayBuffer(bytes, isReadOnly: true);
diff --git a/src/MongoDB.Bson/IO/BsonReaderSettings.cs b/src/MongoDB.Bson/IO/BsonReaderSettings.cs
index 649c02ff59c..61992ad4c0d 100644
--- a/src/MongoDB.Bson/IO/BsonReaderSettings.cs
+++ b/src/MongoDB.Bson/IO/BsonReaderSettings.cs
@@ -14,6 +14,7 @@
*/
using System;
+using MongoDB.Bson.Serialization;
namespace MongoDB.Bson.IO
{
diff --git a/src/MongoDB.Bson/IO/BsonWriter.cs b/src/MongoDB.Bson/IO/BsonWriter.cs
index 3fd705fa31b..1e88a64b400 100644
--- a/src/MongoDB.Bson/IO/BsonWriter.cs
+++ b/src/MongoDB.Bson/IO/BsonWriter.cs
@@ -326,13 +326,15 @@ public virtual void WriteRawBsonArray(IByteBuffer slice)
stream.Position = 0;
using (var reader = new BsonBinaryReader(stream, BsonBinaryReaderSettings.Defaults))
{
- var deserializationContext = BsonDeserializationContext.CreateRoot(reader);
+ //QUESTION Is it correct we only need a default domain here?
+ var deserializationContext = BsonDeserializationContext.CreateRoot(reader, BsonSerializer.DefaultSerializationDomain);
reader.ReadStartDocument();
reader.ReadName("x");
var array = BsonArraySerializer.Instance.Deserialize(deserializationContext);
reader.ReadEndDocument();
- var serializationContext = BsonSerializationContext.CreateRoot(this);
+ //QUESTION Is it correct we only need a default domain here?
+ var serializationContext = BsonSerializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain);
BsonArraySerializer.Instance.Serialize(serializationContext, array);
}
}
@@ -350,10 +352,12 @@ public virtual void WriteRawBsonDocument(IByteBuffer slice)
using (var stream = new ByteBufferStream(slice, ownsBuffer: false))
using (var bsonReader = new BsonBinaryReader(stream, BsonBinaryReaderSettings.Defaults))
{
- var deserializationContext = BsonDeserializationContext.CreateRoot(bsonReader);
+ //QUESTION Is it correct we only need a default domain here?
+ var deserializationContext = BsonDeserializationContext.CreateRoot(bsonReader, BsonSerializer.DefaultSerializationDomain);
var document = BsonDocumentSerializer.Instance.Deserialize(deserializationContext);
- var serializationContext = BsonSerializationContext.CreateRoot(this);
+ //QUESTION Is it correct we only need a default domain here?
+ var serializationContext = BsonSerializationContext.CreateRoot(this, BsonSerializer.DefaultSerializationDomain);
BsonDocumentSerializer.Instance.Serialize(serializationContext, document);
}
}
diff --git a/src/MongoDB.Bson/IO/BsonWriterSettings.cs b/src/MongoDB.Bson/IO/BsonWriterSettings.cs
index 06957993d70..82b92538605 100644
--- a/src/MongoDB.Bson/IO/BsonWriterSettings.cs
+++ b/src/MongoDB.Bson/IO/BsonWriterSettings.cs
@@ -14,6 +14,7 @@
*/
using System;
+using MongoDB.Bson.Serialization;
namespace MongoDB.Bson.IO
{
diff --git a/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs b/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs
index 0e83adcdb91..67ff2a866c0 100644
--- a/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs
+++ b/src/MongoDB.Bson/IO/ElementAppendingBsonWriter.cs
@@ -60,7 +60,8 @@ public override void WriteEndDocument()
Wrapped.PushSettings(_settingsConfigurator);
try
{
- var context = BsonSerializationContext.CreateRoot(Wrapped);
+ //QUESTION Is it correct we only need a default domain here?
+ var context = BsonSerializationContext.CreateRoot(Wrapped, BsonSerializer.DefaultSerializationDomain);
foreach (var element in _elements)
{
Wrapped.WriteName(element.Name);
diff --git a/src/MongoDB.Bson/IO/IBsonReader.cs b/src/MongoDB.Bson/IO/IBsonReader.cs
index 14af4722a33..89f617fe124 100644
--- a/src/MongoDB.Bson/IO/IBsonReader.cs
+++ b/src/MongoDB.Bson/IO/IBsonReader.cs
@@ -17,6 +17,7 @@
namespace MongoDB.Bson.IO
{
+ //FP This interface should have the settingg property as well, same way it's done for thr writer
///
/// Represents a BSON reader.
///
diff --git a/src/MongoDB.Bson/InternalExtensions.cs b/src/MongoDB.Bson/InternalExtensions.cs
new file mode 100644
index 00000000000..1df207a684d
--- /dev/null
+++ b/src/MongoDB.Bson/InternalExtensions.cs
@@ -0,0 +1,107 @@
+/* Copyright 2010-present MongoDB Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Conventions;
+
+namespace MongoDB.Bson
+{
+ //FP This could be moved somewhere else, and maybe reordered.
+ internal static class InternalExtensions
+ {
+ #region IBsonIdProvider
+
+ public static bool GetDocumentIdInternal(this IBsonIdProvider provider, object document, IBsonSerializationDomain serializationDomain, out object id,
+ out Type idNominalType, out IIdGenerator idGenerator)
+ {
+ if (provider is IBsonIdProviderInternal internalProvider)
+ {
+ return internalProvider.GetDocumentId(document, serializationDomain, out id, out idNominalType, out idGenerator);
+ }
+ return provider.GetDocumentId(document, out id, out idNominalType, out idGenerator);
+ }
+
+ #endregion
+
+ #region IDiscriminatorConvention
+
+ public static Type GetActualTypeInternal(this IDiscriminatorConvention discriminatorConvention, IBsonReader bsonReader, Type nominalType, IBsonSerializationDomain serializationDomain)
+ {
+ if (discriminatorConvention is IDiscriminatorConventionInternal internalConvention)
+ {
+ return internalConvention.GetActualType(bsonReader, nominalType, serializationDomain);
+ }
+ return discriminatorConvention.GetActualType(bsonReader, nominalType);
+ }
+
+ public static BsonValue GetDiscriminatorInternal(this IDiscriminatorConvention discriminatorConvention, Type nominalType, Type actualType, IBsonSerializationDomain serializationDomain)
+ {
+ if (discriminatorConvention is IDiscriminatorConventionInternal internalConvention)
+ {
+ return internalConvention.GetDiscriminator(nominalType, actualType, serializationDomain);
+ }
+ return discriminatorConvention.GetDiscriminator(nominalType, actualType);
+ }
+
+ #endregion
+
+ #region IScalarDiscriminatorConvention
+
+ public static BsonValue[] GetDiscriminatorsForTypeAndSubTypesInternal(this IScalarDiscriminatorConvention discriminatorConvention, Type type, IBsonSerializationDomain serializationDomain)
+ {
+ if (discriminatorConvention is IScalarDiscriminatorConventionInternal internalConvention)
+ {
+ return internalConvention.GetDiscriminatorsForTypeAndSubTypes(type, serializationDomain);
+ }
+ return discriminatorConvention.GetDiscriminatorsForTypeAndSubTypes(type);
+ }
+
+ #endregion
+
+ #region IMemberMapConvention
+
+ public static void ApplyInternal(this IMemberMapConvention memberMapConvention, BsonMemberMap memberMap, IBsonSerializationDomain serializationDomain)
+ {
+ if (memberMapConvention is IMemberMapConventionInternal internalConvention)
+ {
+ internalConvention.Apply(memberMap, serializationDomain);
+ }
+ else
+ {
+ memberMapConvention.Apply(memberMap);
+ }
+ }
+
+ #endregion
+
+ #region IPostProcessingConvention
+
+ public static void PostProcessInternal(this IPostProcessingConvention postProcessingConvention, BsonClassMap classMap, IBsonSerializationDomain serializationDomain)
+ {
+ if (postProcessingConvention is IPostProcessingConventionInternal internalConvention)
+ {
+ internalConvention.PostProcess(classMap, serializationDomain);
+ }
+ else
+ {
+ postProcessingConvention.PostProcess(classMap);
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/ObjectModel/BsonDocument.cs b/src/MongoDB.Bson/ObjectModel/BsonDocument.cs
index 535bb541b62..e6a0a02d74d 100644
--- a/src/MongoDB.Bson/ObjectModel/BsonDocument.cs
+++ b/src/MongoDB.Bson/ObjectModel/BsonDocument.cs
@@ -331,7 +331,8 @@ public static BsonDocument Parse(string json)
{
using (var jsonReader = new JsonReader(json))
{
- var context = BsonDeserializationContext.CreateRoot(jsonReader);
+ //QUESTION Is it correct we only need a default domain here?
+ var context = BsonDeserializationContext.CreateRoot(jsonReader, BsonSerializer.DefaultSerializationDomain);
var document = BsonDocumentSerializer.Instance.Deserialize(context);
if (!jsonReader.IsAtEndOfFile())
{
diff --git a/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs b/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs
index 09edc32dbfa..8965a4d0f8a 100644
--- a/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs
+++ b/src/MongoDB.Bson/ObjectModel/BsonDocumentWrapper.cs
@@ -91,9 +91,12 @@ public object Wrapped
/// The nominal type of the wrapped object.
/// The wrapped object.
/// A BsonDocumentWrapper.
- public static BsonDocumentWrapper Create(TNominalType value)
+ public static BsonDocumentWrapper Create(TNominalType value) =>
+ Create(value, BsonSerializer.DefaultSerializationDomain);
+
+ internal static BsonDocumentWrapper Create(TNominalType value, IBsonSerializationDomain serializationDomain)
{
- return Create(typeof(TNominalType), value);
+ return Create(typeof(TNominalType), value, serializationDomain);
}
///
@@ -102,9 +105,12 @@ public static BsonDocumentWrapper Create(TNominalType value)
/// The nominal type of the wrapped object.
/// The wrapped object.
/// A BsonDocumentWrapper.
- public static BsonDocumentWrapper Create(Type nominalType, object value)
+ public static BsonDocumentWrapper Create(Type nominalType, object value) =>
+ Create(nominalType, value, BsonSerializer.DefaultSerializationDomain);
+
+ internal static BsonDocumentWrapper Create(Type nominalType, object value, IBsonSerializationDomain domain)
{
- var serializer = BsonSerializer.LookupSerializer(nominalType);
+ var serializer = domain.LookupSerializer(nominalType);
return new BsonDocumentWrapper(value, serializer);
}
@@ -114,14 +120,25 @@ public static BsonDocumentWrapper Create(Type nominalType, object value)
/// The nominal type of the wrapped objects.
/// A list of wrapped objects.
/// A list of BsonDocumentWrappers.
- public static IEnumerable CreateMultiple(IEnumerable values)
+ public static IEnumerable CreateMultiple(IEnumerable values) =>
+ CreateMultiple(values, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ /// //TODO
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static IEnumerable CreateMultiple(IEnumerable values, IBsonSerializationDomain domain)
{
if (values == null)
{
throw new ArgumentNullException("values");
}
- var serializer = BsonSerializer.LookupSerializer(typeof(TNominalType));
+ var serializer = domain.LookupSerializer(typeof(TNominalType));
return values.Select(v => new BsonDocumentWrapper(v, serializer));
}
@@ -131,7 +148,18 @@ public static IEnumerable CreateMultiple(IEnu
/// The nominal type of the wrapped object.
/// A list of wrapped objects.
/// A list of BsonDocumentWrappers.
- public static IEnumerable CreateMultiple(Type nominalType, IEnumerable values)
+ public static IEnumerable CreateMultiple(Type nominalType, IEnumerable values) =>
+ CreateMultiple(nominalType, values, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ /// //TODO
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static IEnumerable CreateMultiple(Type nominalType, IEnumerable values, IBsonSerializationDomain domain)
{
if (nominalType == null)
{
@@ -142,7 +170,7 @@ public static IEnumerable CreateMultiple(Type nominalType,
throw new ArgumentNullException("values");
}
- var serializer = BsonSerializer.LookupSerializer(nominalType);
+ var serializer = domain.LookupSerializer(nominalType);
return values.Cast
public class BsonClassMap
{
- // private static fields
- private readonly static Dictionary __classMaps = new Dictionary();
- private readonly static Queue __knownTypesQueue = new Queue();
- private static int __freezeNestingLevel = 0;
-
// private fields
private readonly Type _classType;
private readonly List _creatorMaps;
- private readonly IConventionPack _conventionPack;
private readonly bool _isAnonymous;
private readonly List _allMemberMaps; // includes inherited member maps
private readonly ReadOnlyCollection _allMemberMapsReadonly;
@@ -70,7 +64,6 @@ public BsonClassMap(Type classType)
{
_classType = classType;
_creatorMaps = new List();
- _conventionPack = ConventionRegistry.Lookup(classType);
_isAnonymous = classType.IsAnonymousType();
_allMemberMaps = new List();
_allMemberMapsReadonly = _allMemberMaps.AsReadOnly();
@@ -124,12 +117,13 @@ public IEnumerable CreatorMaps
get { return _creatorMaps; }
}
+ //DOMAIN-API This one should be removed, or become a method to get the convention registry/domain as input
///
/// Gets the conventions used for auto mapping.
///
public IConventionPack ConventionPack
{
- get { return _conventionPack; }
+ get { return BsonSerializer.DefaultSerializationDomain.ConventionRegistry.Lookup(_classType); }
}
///
@@ -253,6 +247,7 @@ internal int ExtraElementsMemberMapIndex
get { return _extraElementsMemberIndex; }
}
+ //DOMAIN-API This is a utility method, it should not be public.
// public static methods
///
/// Gets the type of a member.
@@ -282,103 +277,32 @@ public static Type GetMemberInfoType(MemberInfo memberInfo)
/// Gets all registered class maps.
///
/// All registered class maps.
- public static IEnumerable GetRegisteredClassMaps()
- {
- BsonSerializer.ConfigLock.EnterReadLock();
- try
- {
- return __classMaps.Values.ToList(); // return a copy for thread safety
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitReadLock();
- }
- }
+ public static IEnumerable GetRegisteredClassMaps() =>
+ BsonSerializer.DefaultSerializationDomain.BsonClassMap.GetRegisteredClassMaps();
///
/// Checks whether a class map is registered for a type.
///
/// The type to check.
/// True if there is a class map registered for the type.
- public static bool IsClassMapRegistered(Type type)
- {
- if (type == null)
- {
- throw new ArgumentNullException("type");
- }
-
- BsonSerializer.ConfigLock.EnterReadLock();
- try
- {
- return __classMaps.ContainsKey(type);
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitReadLock();
- }
- }
+ public static bool IsClassMapRegistered(Type type) =>
+ BsonSerializer.DefaultSerializationDomain.BsonClassMap.IsClassMapRegistered(type);
///
/// Looks up a class map (will AutoMap the class if no class map is registered).
///
/// The class type.
/// The class map.
- public static BsonClassMap LookupClassMap(Type classType)
- {
- if (classType == null)
- {
- throw new ArgumentNullException("classType");
- }
-
- BsonSerializer.ConfigLock.EnterReadLock();
- try
- {
- if (__classMaps.TryGetValue(classType, out var classMap))
- {
- if (classMap.IsFrozen)
- {
- return classMap;
- }
- }
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitReadLock();
- }
-
- // automatically create a new classMap for classType and register it (unless another thread does first)
- // do the work of speculatively creating a new class map outside of holding any lock
- var classMapDefinition = typeof(BsonClassMap<>);
- var classMapType = classMapDefinition.MakeGenericType(classType);
- var newClassMap = (BsonClassMap)Activator.CreateInstance(classMapType);
- newClassMap.AutoMap();
-
- BsonSerializer.ConfigLock.EnterWriteLock();
- try
- {
- if (!__classMaps.TryGetValue(classType, out var classMap))
- {
- RegisterClassMap(newClassMap);
- classMap = newClassMap;
- }
-
- return classMap.Freeze();
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitWriteLock();
- }
- }
+ public static BsonClassMap LookupClassMap(Type classType) =>
+ BsonSerializer.DefaultSerializationDomain.BsonClassMap.LookupClassMap(classType);
///
/// Creates and registers a class map.
///
/// The class.
/// The class map.
- public static BsonClassMap RegisterClassMap()
- {
- return RegisterClassMap(cm => { cm.AutoMap(); });
- }
+ public static BsonClassMap RegisterClassMap()=>
+ BsonSerializer.DefaultSerializationDomain.BsonClassMap.RegisterClassMap();
///
/// Creates and registers a class map.
@@ -387,35 +311,14 @@ public static BsonClassMap RegisterClassMap()
/// The class map initializer.
/// The class map.
public static BsonClassMap RegisterClassMap(Action> classMapInitializer)
- {
- var classMap = new BsonClassMap(classMapInitializer);
- RegisterClassMap(classMap);
- return classMap;
- }
+ => BsonSerializer.DefaultSerializationDomain.BsonClassMap.RegisterClassMap(classMapInitializer);
///
/// Registers a class map.
///
/// The class map.
public static void RegisterClassMap(BsonClassMap classMap)
- {
- if (classMap == null)
- {
- throw new ArgumentNullException("classMap");
- }
-
- BsonSerializer.ConfigLock.EnterWriteLock();
- try
- {
- // note: class maps can NOT be replaced (because derived classes refer to existing instance)
- __classMaps.Add(classMap.ClassType, classMap);
- BsonSerializer.RegisterDiscriminator(classMap.ClassType, classMap.Discriminator);
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitWriteLock();
- }
- }
+ => BsonSerializer.DefaultSerializationDomain.BsonClassMap.RegisterClassMap(classMap);
///
/// Registers a class map if it is not already registered.
@@ -423,16 +326,7 @@ public static void RegisterClassMap(BsonClassMap classMap)
/// The class.
/// True if this call registered the class map, false if the class map was already registered.
public static bool TryRegisterClassMap()
- {
- return TryRegisterClassMap(ClassMapFactory);
-
- static BsonClassMap ClassMapFactory()
- {
- var classMap = new BsonClassMap();
- classMap.AutoMap();
- return classMap;
- }
- }
+ => BsonSerializer.DefaultSerializationDomain.BsonClassMap.TryRegisterClassMap();
///
/// Registers a class map if it is not already registered.
@@ -441,19 +335,7 @@ static BsonClassMap ClassMapFactory()
/// The class map.
/// True if this call registered the class map, false if the class map was already registered.
public static bool TryRegisterClassMap(BsonClassMap classMap)
- {
- if (classMap == null)
- {
- throw new ArgumentNullException(nameof(classMap));
- }
-
- return TryRegisterClassMap(ClassMapFactory);
-
- BsonClassMap ClassMapFactory()
- {
- return classMap;
- }
- }
+ => BsonSerializer.DefaultSerializationDomain.BsonClassMap.TryRegisterClassMap(classMap);
///
/// Registers a class map if it is not already registered.
@@ -462,19 +344,7 @@ BsonClassMap ClassMapFactory()
/// The class map initializer (only called if the class map is not already registered).
/// True if this call registered the class map, false if the class map was already registered.
public static bool TryRegisterClassMap(Action> classMapInitializer)
- {
- if (classMapInitializer == null)
- {
- throw new ArgumentNullException(nameof(classMapInitializer));
- }
-
- return TryRegisterClassMap(ClassMapFactory);
-
- BsonClassMap ClassMapFactory()
- {
- return new BsonClassMap(classMapInitializer);
- }
- }
+ => BsonSerializer.DefaultSerializationDomain.BsonClassMap.TryRegisterClassMap(classMapInitializer);
///
/// Registers a class map if it is not already registered.
@@ -483,54 +353,22 @@ BsonClassMap ClassMapFactory()
/// The class map factory (only called if the class map is not already registered).
/// True if this call registered the class map, false if the class map was already registered.
public static bool TryRegisterClassMap(Func> classMapFactory)
- {
- if (classMapFactory == null)
- {
- throw new ArgumentNullException(nameof(classMapFactory));
- }
-
- BsonSerializer.ConfigLock.EnterReadLock();
- try
- {
- if (__classMaps.ContainsKey(typeof(TClass)))
- {
- return false;
- }
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitReadLock();
- }
-
- BsonSerializer.ConfigLock.EnterWriteLock();
- try
- {
- if (__classMaps.ContainsKey(typeof(TClass)))
- {
- return false;
- }
- else
- {
- // create a classMap for TClass and register it
- var classMap = classMapFactory();
- RegisterClassMap(classMap);
- return true;
- }
- }
- finally
- {
- BsonSerializer.ConfigLock.ExitWriteLock();
- }
- }
+ => BsonSerializer.DefaultSerializationDomain.BsonClassMap.TryRegisterClassMap(classMapFactory);
// public methods
///
/// Automaps the class.
///
- public void AutoMap()
+ public void AutoMap() => AutoMap(BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ /// //TODO
+ ///
+ ///
+ internal void AutoMap(IBsonSerializationDomain serializationDomain)
{
if (_frozen) { ThrowFrozenException(); }
- AutoMapClass();
+ AutoMapClass(serializationDomain);
}
///
@@ -573,13 +411,29 @@ obj is BsonClassMap other &&
///
public override int GetHashCode() => 0;
+ internal class FreezeContext
+ {
+ public int FreezeNestingLevel { get; set; } = 0;
+ public Queue KnownTypesQueue { get; set; } = new();
+ public IBsonSerializationDomain SerializationDomain { get; set; }
+ }
+
///
/// Freezes the class map.
///
/// The frozen class map.
- public BsonClassMap Freeze()
+ public BsonClassMap Freeze() => Freeze(BsonSerializer.DefaultSerializationDomain);
+
+ internal BsonClassMap Freeze(IBsonSerializationDomain domain)
+ {
+ var freezeContext = new FreezeContext { SerializationDomain = domain };
+ return Freeze(freezeContext);
+ }
+
+ private BsonClassMap Freeze(FreezeContext context)
{
- BsonSerializer.ConfigLock.EnterReadLock();
+ var configLock = context.SerializationDomain!.ConfigLock;
+ configLock.EnterReadLock();
try
{
if (_frozen)
@@ -589,15 +443,15 @@ public BsonClassMap Freeze()
}
finally
{
- BsonSerializer.ConfigLock.ExitReadLock();
+ configLock.ExitReadLock();
}
- BsonSerializer.ConfigLock.EnterWriteLock();
+ configLock.EnterWriteLock();
try
{
if (!_frozen)
{
- __freezeNestingLevel++;
+ context.FreezeNestingLevel++;
try
{
var baseType = _classType.GetTypeInfo().BaseType;
@@ -605,9 +459,9 @@ public BsonClassMap Freeze()
{
if (_baseClassMap == null)
{
- _baseClassMap = LookupClassMap(baseType);
+ _baseClassMap = context.SerializationDomain.BsonClassMap.LookupClassMap(baseType);
}
- _baseClassMap.Freeze();
+ _baseClassMap.Freeze(context);
_discriminatorIsRequired |= _baseClassMap._discriminatorIsRequired;
_hasRootClass |= (_isRootClass || _baseClassMap.HasRootClass);
_allMemberMaps.AddRange(_baseClassMap.AllMemberMaps);
@@ -699,28 +553,28 @@ public BsonClassMap Freeze()
// this avoids infinite recursion when going back down the inheritance tree while processing known types
foreach (var knownType in _knownTypes)
{
- __knownTypesQueue.Enqueue(knownType);
+ context.KnownTypesQueue.Enqueue(knownType);
}
// if we are back to the first level go ahead and process any queued known types
- if (__freezeNestingLevel == 1)
+ if (context.FreezeNestingLevel == 1)
{
- while (__knownTypesQueue.Count != 0)
+ while (context.KnownTypesQueue.Count != 0)
{
- var knownType = __knownTypesQueue.Dequeue();
- LookupClassMap(knownType); // will AutoMap and/or Freeze knownType if necessary
+ var knownType = context.KnownTypesQueue.Dequeue();
+ context.SerializationDomain.BsonClassMap.LookupClassMap(knownType); // will AutoMap and/or Freeze knownType if necessary
}
}
}
finally
{
- __freezeNestingLevel--;
+ context.FreezeNestingLevel--;
}
}
}
finally
{
- BsonSerializer.ConfigLock.ExitWriteLock();
+ configLock.ExitWriteLock();
}
return this;
}
@@ -1317,7 +1171,7 @@ public void UnmapProperty(string propertyName)
/// Gets the discriminator convention for the class.
///
/// The discriminator convention for the class.
- internal IDiscriminatorConvention GetDiscriminatorConvention()
+ internal IDiscriminatorConvention GetDiscriminatorConvention(IBsonSerializationDomain serializationDomain)
{
// return a cached discriminator convention when possible
var discriminatorConvention = _discriminatorConvention;
@@ -1354,7 +1208,7 @@ IDiscriminatorConvention LookupDiscriminatorConvention()
return classMap._discriminatorConvention;
}
- if (BsonSerializer.IsDiscriminatorConventionRegisteredAtThisLevel(classMap._classType))
+ if (serializationDomain.IsDiscriminatorConventionRegisteredAtThisLevel(classMap._classType))
{
// in this case LookupDiscriminatorConvention below will find it
break;
@@ -1363,21 +1217,29 @@ IDiscriminatorConvention LookupDiscriminatorConvention()
if (classMap._isRootClass)
{
// in this case auto-register a hierarchical convention for the root class and look it up as usual below
- BsonSerializer.GetOrRegisterDiscriminatorConvention(classMap._classType, StandardDiscriminatorConvention.Hierarchical);
+ serializationDomain.GetOrRegisterDiscriminatorConvention(classMap._classType, StandardDiscriminatorConvention.Hierarchical);
break;
}
classMap = classMap._baseClassMap;
}
- return BsonSerializer.LookupDiscriminatorConvention(_classType);
+ return serializationDomain.LookupDiscriminatorConvention(_classType);
}
}
+ ///
+ /// Gets the discriminator convention for the class.
+ ///
+ /// The discriminator convention for the class.
+ internal IDiscriminatorConvention GetDiscriminatorConvention()
+ => GetDiscriminatorConvention(BsonSerializer.DefaultSerializationDomain);
+
// private methods
- private void AutoMapClass()
+ private void AutoMapClass(IBsonSerializationDomain serializationDomain)
{
- new ConventionRunner(_conventionPack).Apply(this);
+ var conventionPack = serializationDomain.ConventionRegistry.Lookup(_classType);
+ new ConventionRunner(conventionPack).Apply(this, serializationDomain);
foreach (var memberMap in _declaredMemberMaps)
{
diff --git a/src/MongoDB.Bson/Serialization/BsonClassMapDomain.cs b/src/MongoDB.Bson/Serialization/BsonClassMapDomain.cs
new file mode 100644
index 00000000000..9efe6c84a1d
--- /dev/null
+++ b/src/MongoDB.Bson/Serialization/BsonClassMapDomain.cs
@@ -0,0 +1,263 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace MongoDB.Bson.Serialization;
+
+internal class BsonClassMapDomain : IBsonClassMapDomain
+{
+ // private fields
+ private readonly IBsonSerializationDomain _serializationDomain;
+ private readonly Dictionary _classMaps = new();
+
+ public BsonClassMapDomain(BsonSerializationDomain serializationDomain)
+ {
+ _serializationDomain = serializationDomain;
+ }
+
+ ///
+ /// Gets all registered class maps.
+ ///
+ /// All registered class maps.
+ public IEnumerable GetRegisteredClassMaps()
+ {
+ _serializationDomain.ConfigLock.EnterReadLock();
+ try
+ {
+ return _classMaps.Values.ToList(); // return a copy for thread safety
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitReadLock();
+ }
+ }
+
+ ///
+ /// Checks whether a class map is registered for a type.
+ ///
+ /// The type to check.
+ /// True if there is a class map registered for the type.
+ public bool IsClassMapRegistered(Type type)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException("type");
+ }
+
+ _serializationDomain.ConfigLock.EnterReadLock();
+ try
+ {
+ return _classMaps.ContainsKey(type);
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitReadLock();
+ }
+ }
+
+ ///
+ /// Looks up a class map (will AutoMap the class if no class map is registered).
+ ///
+ /// The class type.
+ /// The class map.
+ public BsonClassMap LookupClassMap(Type classType)
+ {
+ if (classType == null)
+ {
+ throw new ArgumentNullException("classType");
+ }
+
+ _serializationDomain.ConfigLock.EnterReadLock();
+ try
+ {
+ if (_classMaps.TryGetValue(classType, out var classMap))
+ {
+ if (classMap.IsFrozen)
+ {
+ return classMap;
+ }
+ }
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitReadLock();
+ }
+
+ // automatically create a new classMap for classType and register it (unless another thread does first)
+ // do the work of speculatively creating a new class map outside of holding any lock
+ var classMapDefinition = typeof(BsonClassMap<>);
+ var classMapType = classMapDefinition.MakeGenericType(classType);
+ var newClassMap = (BsonClassMap)Activator.CreateInstance(classMapType);
+ newClassMap.AutoMap(_serializationDomain);
+
+ _serializationDomain.ConfigLock.EnterWriteLock();
+ try
+ {
+ if (!_classMaps.TryGetValue(classType, out var classMap))
+ {
+ RegisterClassMap(newClassMap);
+ classMap = newClassMap;
+ }
+
+ return classMap.Freeze(_serializationDomain);
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitWriteLock();
+ }
+ }
+
+ ///
+ /// Creates and registers a class map.
+ ///
+ /// The class.
+ /// The class map.
+ public BsonClassMap RegisterClassMap()
+ {
+ return RegisterClassMap(cm => { cm.AutoMap(_serializationDomain); });
+ }
+
+ ///
+ /// Creates and registers a class map.
+ ///
+ /// The class.
+ /// The class map initializer.
+ /// The class map.
+ public BsonClassMap RegisterClassMap(Action> classMapInitializer)
+ {
+ var classMap = new BsonClassMap(classMapInitializer);
+ RegisterClassMap(classMap);
+ return classMap;
+ }
+
+ ///
+ /// Registers a class map.
+ ///
+ /// The class map.
+ public void RegisterClassMap(BsonClassMap classMap)
+ {
+ if (classMap == null)
+ {
+ throw new ArgumentNullException("classMap");
+ }
+
+ _serializationDomain.ConfigLock.EnterWriteLock();
+ try
+ {
+ // note: class maps can NOT be replaced (because derived classes refer to existing instance)
+ _classMaps.Add(classMap.ClassType, classMap);
+ _serializationDomain.RegisterDiscriminator(classMap.ClassType, classMap.Discriminator);
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitWriteLock();
+ }
+ }
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// True if this call registered the class map, false if the class map was already registered.
+ public bool TryRegisterClassMap()
+ {
+ return TryRegisterClassMap(() => ClassMapFactory(_serializationDomain));
+
+ static BsonClassMap ClassMapFactory(IBsonSerializationDomain serializationDomain)
+ {
+ var classMap = new BsonClassMap();
+ classMap.AutoMap(serializationDomain);
+ return classMap;
+ }
+ }
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// The class map.
+ /// True if this call registered the class map, false if the class map was already registered.
+ public bool TryRegisterClassMap(BsonClassMap classMap)
+ {
+ if (classMap == null)
+ {
+ throw new ArgumentNullException(nameof(classMap));
+ }
+
+ return TryRegisterClassMap(ClassMapFactory);
+
+ BsonClassMap ClassMapFactory()
+ {
+ return classMap;
+ }
+ }
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// The class map initializer (only called if the class map is not already registered).
+ /// True if this call registered the class map, false if the class map was already registered.
+ public bool TryRegisterClassMap(Action> classMapInitializer)
+ {
+ if (classMapInitializer == null)
+ {
+ throw new ArgumentNullException(nameof(classMapInitializer));
+ }
+
+ return TryRegisterClassMap(ClassMapFactory);
+
+ BsonClassMap ClassMapFactory()
+ {
+ return new BsonClassMap(classMapInitializer);
+ }
+ }
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// The class map factory (only called if the class map is not already registered).
+ /// True if this call registered the class map, false if the class map was already registered.
+ public bool TryRegisterClassMap(Func> classMapFactory)
+ {
+ if (classMapFactory == null)
+ {
+ throw new ArgumentNullException(nameof(classMapFactory));
+ }
+
+ _serializationDomain.ConfigLock.EnterReadLock();
+ try
+ {
+ if (_classMaps.ContainsKey(typeof(TClass)))
+ {
+ return false;
+ }
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitReadLock();
+ }
+
+ _serializationDomain.ConfigLock.EnterWriteLock();
+ try
+ {
+ if (_classMaps.ContainsKey(typeof(TClass)))
+ {
+ return false;
+ }
+ else
+ {
+ // create a classMap for TClass and register it
+ var classMap = classMapFactory();
+ RegisterClassMap(classMap);
+ return true;
+ }
+ }
+ finally
+ {
+ _serializationDomain.ConfigLock.ExitWriteLock();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/Serialization/BsonClassMapSerializationProvider.cs b/src/MongoDB.Bson/Serialization/BsonClassMapSerializationProvider.cs
index ac088360c2d..563c0871780 100644
--- a/src/MongoDB.Bson/Serialization/BsonClassMapSerializationProvider.cs
+++ b/src/MongoDB.Bson/Serialization/BsonClassMapSerializationProvider.cs
@@ -21,10 +21,21 @@ namespace MongoDB.Bson.Serialization
///
/// Represents the class map serialization provider.
///
- internal class BsonClassMapSerializationProvider : BsonSerializationProviderBase
+ internal class BsonClassMapSerializationProvider : BsonSerializationProviderBase, IDomainAwareBsonSerializationProvider
{
+ public IBsonSerializationDomain SerializationDomain { get; }
+
+ public BsonClassMapSerializationProvider(IBsonSerializationDomain serializationDomain)
+ {
+ SerializationDomain = serializationDomain;
+ }
+
+ //DOMAIN-API This method should be removed.
///
public override IBsonSerializer GetSerializer(Type type, IBsonSerializerRegistry serializerRegistry)
+ => GetSerializerWithDomain(type);
+
+ public IBsonSerializer GetSerializerWithDomain(Type type)
{
if (type == null)
{
@@ -41,7 +52,7 @@ public override IBsonSerializer GetSerializer(Type type, IBsonSerializerRegistry
!typeof(Array).GetTypeInfo().IsAssignableFrom(type) &&
!typeof(Enum).GetTypeInfo().IsAssignableFrom(type))
{
- var classMap = BsonClassMap.LookupClassMap(type);
+ var classMap = SerializationDomain.BsonClassMap.LookupClassMap(type);
var classMapSerializerDefinition = typeof(BsonClassMapSerializer<>);
var classMapSerializerType = classMapSerializerDefinition.MakeGenericType(type);
return (IBsonSerializer)Activator.CreateInstance(classMapSerializerType, classMap);
diff --git a/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs b/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs
index 03ab3137326..696e2f9c39b 100644
--- a/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs
+++ b/src/MongoDB.Bson/Serialization/BsonDeserializationContext.cs
@@ -14,6 +14,7 @@
*/
using System;
+using System.Net;
using MongoDB.Bson.IO;
namespace MongoDB.Bson.Serialization
@@ -28,10 +29,12 @@ public class BsonDeserializationContext
private readonly IBsonSerializer _dynamicArraySerializer;
private readonly IBsonSerializer _dynamicDocumentSerializer;
private readonly IBsonReader _reader;
+ private readonly IBsonSerializationDomain _serializationDomain;
// constructors
private BsonDeserializationContext(
IBsonReader reader,
+ IBsonSerializationDomain serializationDomain,
bool allowDuplicateElementNames,
IBsonSerializer dynamicArraySerializer,
IBsonSerializer dynamicDocumentSerializer)
@@ -40,6 +43,12 @@ private BsonDeserializationContext(
_allowDuplicateElementNames = allowDuplicateElementNames;
_dynamicArraySerializer = dynamicArraySerializer;
_dynamicDocumentSerializer = dynamicDocumentSerializer;
+
+ _serializationDomain = serializationDomain; //FP Using this version to find error in an easier way for now
+ //_serializationDomain = serializationDomain ?? BsonSerializer.DefaultSerializationDomain;
+
+ _dynamicArraySerializer ??= _serializationDomain.BsonDefaults.DynamicArraySerializer;
+ _dynamicDocumentSerializer ??= _serializationDomain.BsonDefaults.DynamicDocumentSerializer;
}
// public properties
@@ -54,6 +63,11 @@ public bool AllowDuplicateElementNames
get { return _allowDuplicateElementNames; }
}
+ ///
+ /// //TODO
+ ///
+ internal IBsonSerializationDomain SerializationDomain => _serializationDomain;
+
///
/// Gets the dynamic array serializer.
///
@@ -87,6 +101,7 @@ public IBsonReader Reader
get { return _reader; }
}
+ // //DOMAIN-API We should remove this version of the CreateRoot method, and use the one that takes a serialization domain.
// public static methods
///
/// Creates a root context.
@@ -99,8 +114,14 @@ public IBsonReader Reader
public static BsonDeserializationContext CreateRoot(
IBsonReader reader,
Action configurator = null)
+ => CreateRoot(reader, BsonSerializer.DefaultSerializationDomain, configurator);
+
+ internal static BsonDeserializationContext CreateRoot(
+ IBsonReader reader,
+ IBsonSerializationDomain serializationDomain,
+ Action configurator = null)
{
- var builder = new Builder(null, reader);
+ var builder = new Builder(null, reader, serializationDomain);
if (configurator != null)
{
configurator(builder);
@@ -119,7 +140,7 @@ public static BsonDeserializationContext CreateRoot(
public BsonDeserializationContext With(
Action configurator = null)
{
- var builder = new Builder(this, _reader);
+ var builder = new Builder(this, _reader, _serializationDomain);
if (configurator != null)
{
configurator(builder);
@@ -138,9 +159,10 @@ public class Builder
private IBsonSerializer _dynamicArraySerializer;
private IBsonSerializer _dynamicDocumentSerializer;
private IBsonReader _reader;
+ private IBsonSerializationDomain _serializationDomain;
// constructors
- internal Builder(BsonDeserializationContext other, IBsonReader reader)
+ internal Builder(BsonDeserializationContext other, IBsonReader reader, IBsonSerializationDomain serializationDomain)
{
if (reader == null)
{
@@ -148,17 +170,17 @@ internal Builder(BsonDeserializationContext other, IBsonReader reader)
}
_reader = reader;
+ _serializationDomain = serializationDomain;
if (other != null)
{
_allowDuplicateElementNames = other.AllowDuplicateElementNames;
_dynamicArraySerializer = other.DynamicArraySerializer;
_dynamicDocumentSerializer = other.DynamicDocumentSerializer;
}
- else
- {
- _dynamicArraySerializer = BsonDefaults.DynamicArraySerializer;
- _dynamicDocumentSerializer = BsonDefaults.DynamicDocumentSerializer;
- }
+
+ /* QUESTION I removed the part where we set the dynamic serializers from the BsonDefaults, and delay it until we have a serialization domain (when we build the DeserializationContext).
+ * This is technically changing the public behaviour, but it's in a builder, I do not thing it will affect anyone. Same done for the serialization context.
+ */
}
// properties
@@ -209,6 +231,8 @@ public IBsonReader Reader
get { return _reader; }
}
+ internal IBsonSerializationDomain SerializationDomain => _serializationDomain;
+
// public methods
///
/// Builds the BsonDeserializationContext instance.
@@ -216,7 +240,7 @@ public IBsonReader Reader
/// A BsonDeserializationContext.
internal BsonDeserializationContext Build()
{
- return new BsonDeserializationContext(_reader, _allowDuplicateElementNames, _dynamicArraySerializer, _dynamicDocumentSerializer);
+ return new BsonDeserializationContext(_reader, _serializationDomain, _allowDuplicateElementNames, _dynamicArraySerializer, _dynamicDocumentSerializer);
}
}
}
diff --git a/src/MongoDB.Bson/Serialization/BsonMemberMap.cs b/src/MongoDB.Bson/Serialization/BsonMemberMap.cs
index b10971d5249..1181af3c7a8 100644
--- a/src/MongoDB.Bson/Serialization/BsonMemberMap.cs
+++ b/src/MongoDB.Bson/Serialization/BsonMemberMap.cs
@@ -56,7 +56,7 @@ public BsonMemberMap(BsonClassMap classMap, MemberInfo memberInfo)
{
_classMap = classMap;
_memberInfo = memberInfo;
- _memberType = BsonClassMap.GetMemberInfoType(memberInfo);
+ _memberType = BsonClassMap.GetMemberInfoType(memberInfo); //FP This is more of a utility method, it can stay like this
_memberTypeIsBsonValue = typeof(BsonValue).GetTypeInfo().IsAssignableFrom(_memberType);
Reset();
@@ -294,14 +294,16 @@ obj is BsonMemberMap other &&
/// Gets the serializer.
///
/// The serializer.
- public IBsonSerializer GetSerializer()
+ public IBsonSerializer GetSerializer() => GetSerializer(BsonSerializer.DefaultSerializationDomain);
+
+ internal IBsonSerializer GetSerializer(IBsonSerializationDomain domain)
{
if (_serializer == null)
{
// return special serializer for BsonValue members that handles the _csharpnull representation
if (_memberTypeIsBsonValue)
{
- var wrappedSerializer = BsonSerializer.LookupSerializer(_memberType);
+ var wrappedSerializer = domain.LookupSerializer(_memberType);
var isBsonArraySerializer = wrappedSerializer is IBsonArraySerializer;
var isBsonDocumentSerializer = wrappedSerializer is IBsonDocumentSerializer;
@@ -329,7 +331,7 @@ public IBsonSerializer GetSerializer()
}
else
{
- _serializer = BsonSerializer.LookupSerializer(_memberType);
+ _serializer = domain.LookupSerializer(_memberType);
}
}
return _serializer;
diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs b/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs
index a14a62322a8..8c046d91911 100644
--- a/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs
+++ b/src/MongoDB.Bson/Serialization/BsonSerializationContext.cs
@@ -26,17 +26,31 @@ public class BsonSerializationContext
// private fields
private readonly Func _isDynamicType;
private readonly IBsonWriter _writer;
+ private readonly IBsonSerializationDomain _serializationDomain;
// constructors
private BsonSerializationContext(
IBsonWriter writer,
+ IBsonSerializationDomain serializationDomain,
Func isDynamicType)
{
_writer = writer;
_isDynamicType = isDynamicType;
+
+ _serializationDomain = serializationDomain; //FP Using this version to find error in an easier way for now
+ //_serializationDomain = serializationDomain ?? BsonSerializer.DefaultSerializationDomain;
+
+ _isDynamicType??= t =>
+ (_serializationDomain.BsonDefaults.DynamicArraySerializer != null && t == _serializationDomain.BsonDefaults.DynamicArraySerializer.ValueType) ||
+ (_serializationDomain.BsonDefaults.DynamicDocumentSerializer != null && t == _serializationDomain.BsonDefaults.DynamicDocumentSerializer.ValueType);
}
// public properties
+ ///
+ /// //TODO
+ ///
+ internal IBsonSerializationDomain SerializationDomain => _serializationDomain;
+
///
/// Gets a function that, when executed, will indicate whether the type
/// is a dynamic type.
@@ -57,6 +71,7 @@ public IBsonWriter Writer
get { return _writer; }
}
+ //DOMAIN-API This method should be probably removed.
// public static methods
///
/// Creates a root context.
@@ -69,8 +84,14 @@ public IBsonWriter Writer
public static BsonSerializationContext CreateRoot(
IBsonWriter writer,
Action configurator = null)
+ => CreateRoot(writer, BsonSerializer.DefaultSerializationDomain, configurator);
+
+ internal static BsonSerializationContext CreateRoot(
+ IBsonWriter writer,
+ IBsonSerializationDomain serializationDomain,
+ Action configurator = null)
{
- var builder = new Builder(null, writer);
+ var builder = new Builder(null, writer, serializationDomain);
if (configurator != null)
{
configurator(builder);
@@ -88,7 +109,7 @@ public static BsonSerializationContext CreateRoot(
public BsonSerializationContext With(
Action configurator = null)
{
- var builder = new Builder(this, _writer);
+ var builder = new Builder(this, _writer, _serializationDomain);
if (configurator != null)
{
configurator(builder);
@@ -105,9 +126,10 @@ public class Builder
// private fields
private Func _isDynamicType;
private IBsonWriter _writer;
+ private IBsonSerializationDomain _serializationDomain;
// constructors
- internal Builder(BsonSerializationContext other, IBsonWriter writer)
+ internal Builder(BsonSerializationContext other, IBsonWriter writer, IBsonSerializationDomain serializationDomain)
{
if (writer == null)
{
@@ -115,16 +137,15 @@ internal Builder(BsonSerializationContext other, IBsonWriter writer)
}
_writer = writer;
+ _serializationDomain = serializationDomain;
if (other != null)
{
_isDynamicType = other._isDynamicType;
}
- else
- {
- _isDynamicType = t =>
- (BsonDefaults.DynamicArraySerializer != null && t == BsonDefaults.DynamicArraySerializer.ValueType) ||
- (BsonDefaults.DynamicDocumentSerializer != null && t == BsonDefaults.DynamicDocumentSerializer.ValueType);
- }
+
+ /* QUESTION I removed the part where we set _isDynamicType from the BsonDefaults, and delay it until we have a serialization domain (when we build the SerializationContext).
+ * This is technically changing the public behaviour, but it's in a builder, I do not thing it will affect anyone. Same done for the deserialization context.
+ */
}
// properties
@@ -155,7 +176,7 @@ public IBsonWriter Writer
/// A BsonSerializationContext.
internal BsonSerializationContext Build()
{
- return new BsonSerializationContext(_writer, _isDynamicType);
+ return new BsonSerializationContext(_writer, _serializationDomain, _isDynamicType);
}
}
}
diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationDomain.cs b/src/MongoDB.Bson/Serialization/BsonSerializationDomain.cs
new file mode 100644
index 00000000000..8ffebd8b08d
--- /dev/null
+++ b/src/MongoDB.Bson/Serialization/BsonSerializationDomain.cs
@@ -0,0 +1,878 @@
+/* Copyright 2010-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Threading;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Bson.Serialization.Conventions;
+using MongoDB.Bson.Serialization.IdGenerators;
+
+namespace MongoDB.Bson.Serialization
+{
+ ///
+ /// A class that represents the BSON serialization functionality.
+ ///
+ internal class BsonSerializationDomain : IBsonSerializationDomain, IDisposable
+ {
+ // private fields
+ private IBsonDefaults _bsonDefaults;
+ private ReaderWriterLockSlim _configLock = new(LockRecursionPolicy.SupportsRecursion);
+ private IBsonClassMapDomain _classMapDomain;
+ private IConventionRegistryDomain _conventionRegistryDomain;
+ private Dictionary _idGenerators = new();
+ private Dictionary _discriminatorConventions = new();
+ private Dictionary> _discriminators = new();
+ private HashSet _discriminatedTypes = new();
+ private BsonSerializerRegistry _serializerRegistry;
+ private TypeMappingSerializationProvider _typeMappingSerializationProvider;
+ // ConcurrentDictionary is being used as a concurrent set of Type. The values will always be null.
+ private ConcurrentDictionary _typesWithRegisteredKnownTypes = new();
+
+ private bool _useNullIdChecker;
+ private bool _useZeroIdChecker;
+
+ // constructor
+ public BsonSerializationDomain(string name = null)
+ {
+ CreateSerializerRegistry();
+ CreateSubDomains();
+ RegisterIdGenerators();
+ Name = name ?? "CUSTOM";
+ }
+
+ public string Name { get; }
+
+ // public properties
+ ///
+ /// Gets the serializer registry.
+ ///
+ public IBsonSerializerRegistry SerializerRegistry
+ {
+ get { return _serializerRegistry; }
+ }
+
+ ///
+ /// Gets or sets whether to use the NullIdChecker on reference Id types that don't have an IdGenerator registered.
+ ///
+ public bool UseNullIdChecker
+ {
+ get { return _useNullIdChecker; }
+ set { _useNullIdChecker = value; }
+ }
+
+ public bool UseNullIdCheckerEnabled => UseNullIdChecker;
+
+ ///
+ /// Gets or sets whether to use the ZeroIdChecker on value Id types that don't have an IdGenerator registered.
+ ///
+ public bool UseZeroIdChecker
+ {
+ get { return _useZeroIdChecker; }
+ set { _useZeroIdChecker = value; }
+ }
+
+ public bool UseZeroIdCheckerEnabled => UseZeroIdChecker;
+
+ // internal properties
+ public ReaderWriterLockSlim ConfigLock
+ {
+ get { return _configLock; }
+ }
+
+ ///
+ /// Deserializes an object from a BsonDocument.
+ ///
+ /// The nominal type of the object.
+ /// The BsonDocument.
+ /// The configurator.
+ /// A deserialized value.
+ public TNominalType Deserialize(BsonDocument document,
+ Action configurator = null)
+ {
+ using (var bsonReader = new BsonDocumentReader(document))
+ {
+ return Deserialize(bsonReader, configurator);
+ }
+ }
+
+ ///
+ /// Deserializes a value.
+ ///
+ /// The nominal type of the object.
+ /// The BsonReader.
+ /// The configurator.
+ /// A deserialized value.
+ public TNominalType Deserialize(IBsonReader bsonReader,
+ Action configurator = null)
+ {
+ var serializer = LookupSerializer();
+ var context = BsonDeserializationContext.CreateRoot(bsonReader, this, configurator);
+ return serializer.Deserialize(context);
+ }
+
+ ///
+ /// Deserializes an object from a BSON byte array.
+ ///
+ /// The nominal type of the object.
+ /// The BSON byte array.
+ /// The configurator.
+ /// A deserialized value.
+ public TNominalType Deserialize(byte[] bytes,
+ Action configurator = null)
+ {
+ using (var buffer = new ByteArrayBuffer(bytes, isReadOnly: true))
+ using (var stream = new ByteBufferStream(buffer))
+ {
+ return Deserialize(stream, configurator);
+ }
+ }
+
+ ///
+ /// Deserializes an object from a BSON Stream.
+ ///
+ /// The nominal type of the object.
+ /// The BSON Stream.
+ /// The configurator.
+ /// A deserialized value.
+ public TNominalType Deserialize(Stream stream,
+ Action configurator = null)
+ {
+ using (var bsonReader = new BsonBinaryReader(stream))
+ {
+ return Deserialize(bsonReader, configurator);
+ }
+ }
+
+ ///
+ /// Deserializes an object from a JSON string.
+ ///
+ /// The nominal type of the object.
+ /// The JSON string.
+ /// The configurator.
+ /// A deserialized value.
+ public TNominalType Deserialize(string json,
+ Action configurator = null)
+ {
+ using (var bsonReader = new JsonReader(json))
+ {
+ return Deserialize(bsonReader, configurator);
+ }
+ }
+
+ ///
+ /// Deserializes an object from a JSON TextReader.
+ ///
+ /// The nominal type of the object.
+ /// The JSON TextReader.
+ /// The configurator.
+ /// A deserialized value.
+ public TNominalType Deserialize(TextReader textReader,
+ Action configurator = null)
+ {
+ using (var bsonReader = new JsonReader(textReader))
+ {
+ return Deserialize(bsonReader, configurator);
+ }
+ }
+
+ ///
+ /// Deserializes an object from a BsonDocument.
+ ///
+ /// The BsonDocument.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ public object Deserialize(BsonDocument document, Type nominalType,
+ Action configurator = null)
+ {
+ using (var bsonReader = new BsonDocumentReader(document))
+ {
+ return Deserialize(bsonReader, nominalType, configurator);
+ }
+ }
+
+ ///
+ /// Deserializes a value.
+ ///
+ /// The BsonReader.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ public object Deserialize(IBsonReader bsonReader, Type nominalType,
+ Action configurator = null)
+ {
+ var serializer = LookupSerializer(nominalType);
+ var context = BsonDeserializationContext.CreateRoot(bsonReader, this, configurator);
+ return serializer.Deserialize(context);
+ }
+
+ ///
+ /// Deserializes an object from a BSON byte array.
+ ///
+ /// The BSON byte array.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ public object Deserialize(byte[] bytes, Type nominalType,
+ Action configurator = null)
+ {
+ using (var buffer = new ByteArrayBuffer(bytes, isReadOnly: true))
+ using (var stream = new ByteBufferStream(buffer))
+ {
+ return Deserialize(stream, nominalType, configurator);
+ }
+ }
+
+ ///
+ /// Deserializes an object from a BSON Stream.
+ ///
+ /// The BSON Stream.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ public object Deserialize(Stream stream, Type nominalType,
+ Action configurator = null)
+ {
+ using (var bsonReader = new BsonBinaryReader(stream))
+ {
+ return Deserialize(bsonReader, nominalType, configurator);
+ }
+ }
+
+ ///
+ /// Deserializes an object from a JSON string.
+ ///
+ /// The JSON string.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ public object Deserialize(string json, Type nominalType,
+ Action configurator = null)
+ {
+ using (var bsonReader = new JsonReader(json))
+ {
+ return Deserialize(bsonReader, nominalType, configurator);
+ }
+ }
+
+ ///
+ /// Deserializes an object from a JSON TextReader.
+ ///
+ /// The JSON TextReader.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ public object Deserialize(TextReader textReader, Type nominalType,
+ Action configurator = null)
+ {
+ using (var bsonReader = new JsonReader(textReader))
+ {
+ return Deserialize(bsonReader, nominalType, configurator);
+ }
+ }
+
+ public BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type)
+ {
+ // note: EnsureKnownTypesAreRegistered handles its own locking so call from outside any lock
+ EnsureKnownTypesAreRegistered(type);
+
+ var discriminators = new List();
+
+ _configLock.EnterReadLock();
+ try
+ {
+ foreach (var entry in _discriminators)
+ {
+ var discriminator = entry.Key;
+ var actualTypes = entry.Value;
+
+ var matchingType = actualTypes.SingleOrDefault(t => t == type || t.IsSubclassOf(type));
+ if (matchingType != null)
+ {
+ discriminators.Add(discriminator);
+ }
+ }
+ }
+ finally
+ {
+ _configLock.ExitReadLock();
+ }
+
+ return discriminators.OrderBy(x => x).ToArray();
+ }
+
+ public IDiscriminatorConvention GetOrRegisterDiscriminatorConvention(Type type,
+ IDiscriminatorConvention discriminatorConvention)
+ {
+ _configLock.EnterReadLock();
+ try
+ {
+ if (_discriminatorConventions.TryGetValue(type, out var registeredDiscriminatorConvention))
+ {
+ return registeredDiscriminatorConvention;
+ }
+ }
+ finally
+ {
+ _configLock.ExitReadLock();
+ }
+
+ _configLock.EnterWriteLock();
+ try
+ {
+ if (_discriminatorConventions.TryGetValue(type, out var registeredDiscrimantorConvention))
+ {
+ return registeredDiscrimantorConvention;
+ }
+
+ RegisterDiscriminatorConvention(type, discriminatorConvention);
+ return discriminatorConvention;
+ }
+ finally
+ {
+ _configLock.ExitWriteLock();
+ }
+ }
+
+ public bool IsDiscriminatorConventionRegisteredAtThisLevel(Type type)
+ {
+ _configLock.EnterReadLock();
+ try
+ {
+ return _discriminatorConventions.ContainsKey(type);
+ }
+ finally
+ {
+ _configLock.ExitReadLock();
+ }
+ }
+
+ ///
+ /// Returns whether the given type has any discriminators registered for any of its subclasses.
+ ///
+ /// A Type.
+ /// True if the type is discriminated.
+ public bool IsTypeDiscriminated(Type type)
+ {
+ var typeInfo = type.GetTypeInfo();
+ return typeInfo.IsInterface || _discriminatedTypes.Contains(type);
+ }
+
+ ///
+ /// Looks up the actual type of an object to be deserialized.
+ ///
+ /// The nominal type of the object.
+ /// The discriminator.
+ /// The actual type of the object.
+ public Type LookupActualType(Type nominalType, BsonValue discriminator)
+ {
+ if (discriminator == null)
+ {
+ return nominalType;
+ }
+
+ // note: EnsureKnownTypesAreRegistered handles its own locking so call from outside any lock
+ EnsureKnownTypesAreRegistered(nominalType);
+
+ _configLock.EnterReadLock();
+ try
+ {
+ Type actualType = null;
+
+ HashSet hashSet;
+ var nominalTypeInfo = nominalType.GetTypeInfo();
+ if (_discriminators.TryGetValue(discriminator, out hashSet))
+ {
+ foreach (var type in hashSet)
+ {
+ if (nominalTypeInfo.IsAssignableFrom(type))
+ {
+ if (actualType == null)
+ {
+ actualType = type;
+ }
+ else
+ {
+ string message = string.Format("Ambiguous discriminator '{0}'.", discriminator);
+ throw new BsonSerializationException(message);
+ }
+ }
+ }
+
+ // no need for additional checks, we found the right type
+ if (actualType != null)
+ {
+ return actualType;
+ }
+ }
+
+ if (discriminator.IsString)
+ {
+ actualType = TypeNameDiscriminator.GetActualType(discriminator.AsString); // see if it's a Type name
+ }
+
+ if (actualType == null)
+ {
+ string message = string.Format("Unknown discriminator value '{0}'.", discriminator);
+ throw new BsonSerializationException(message);
+ }
+
+ if (!nominalTypeInfo.IsAssignableFrom(actualType))
+ {
+ string message = string.Format(
+ "Actual type {0} is not assignable to expected type {1}.",
+ actualType.FullName, nominalType.FullName);
+ throw new BsonSerializationException(message);
+ }
+
+ return actualType;
+ }
+ finally
+ {
+ _configLock.ExitReadLock();
+ }
+ }
+
+ ///
+ /// Looks up the discriminator convention for a type.
+ ///
+ /// The type.
+ /// A discriminator convention.
+ public IDiscriminatorConvention LookupDiscriminatorConvention(Type type)
+ {
+ _configLock.EnterReadLock();
+ try
+ {
+ IDiscriminatorConvention convention;
+ if (_discriminatorConventions.TryGetValue(type, out convention))
+ {
+ return convention;
+ }
+ }
+ finally
+ {
+ _configLock.ExitReadLock();
+ }
+
+ _configLock.EnterWriteLock();
+ try
+ {
+ IDiscriminatorConvention convention;
+ if (!_discriminatorConventions.TryGetValue(type, out convention))
+ {
+ var typeInfo = type.GetTypeInfo();
+ if (type == typeof(object))
+ {
+ // if there is no convention registered for object register the default one
+ convention = new ObjectDiscriminatorConvention("_t");
+ RegisterDiscriminatorConvention(typeof(object), convention);
+ }
+ else if (typeInfo.IsInterface)
+ {
+ // TODO: should convention for interfaces be inherited from parent interfaces?
+ convention = LookupDiscriminatorConvention(typeof(object));
+ RegisterDiscriminatorConvention(type, convention);
+ }
+ else
+ {
+ // inherit the discriminator convention from the closest parent (that isn't object) that has one
+ // otherwise default to the standard scalar convention
+ Type parentType = typeInfo.BaseType;
+ while (true)
+ {
+ if (parentType == typeof(object))
+ {
+ convention = StandardDiscriminatorConvention.Scalar;
+ break;
+ }
+
+ if (_discriminatorConventions.TryGetValue(parentType, out convention))
+ {
+ break;
+ }
+
+ parentType = parentType.GetTypeInfo().BaseType;
+ }
+
+ // register this convention for all types between this and the parent type where we found the convention
+ var unregisteredType = type;
+ while (unregisteredType != parentType)
+ {
+ RegisterDiscriminatorConvention(unregisteredType, convention);
+ unregisteredType = unregisteredType.GetTypeInfo().BaseType;
+ }
+ }
+ }
+
+ return convention;
+ }
+ finally
+ {
+ _configLock.ExitWriteLock();
+ }
+ }
+
+ ///
+ /// Looks up an IdGenerator.
+ ///
+ /// The Id type.
+ /// An IdGenerator for the Id type.
+ public IIdGenerator LookupIdGenerator(Type type)
+ {
+ _configLock.EnterReadLock();
+ try
+ {
+ IIdGenerator idGenerator;
+ if (_idGenerators.TryGetValue(type, out idGenerator))
+ {
+ return idGenerator;
+ }
+ }
+ finally
+ {
+ _configLock.ExitReadLock();
+ }
+
+ _configLock.EnterWriteLock();
+ try
+ {
+ IIdGenerator idGenerator;
+ if (!_idGenerators.TryGetValue(type, out idGenerator))
+ {
+ var typeInfo = type.GetTypeInfo();
+ if (typeInfo.IsValueType && _useZeroIdChecker)
+ {
+ var iEquatableDefinition = typeof(IEquatable<>);
+ var iEquatableType = iEquatableDefinition.MakeGenericType(type);
+ if (iEquatableType.GetTypeInfo().IsAssignableFrom(type))
+ {
+ var zeroIdCheckerDefinition = typeof(ZeroIdChecker<>);
+ var zeroIdCheckerType = zeroIdCheckerDefinition.MakeGenericType(type);
+ idGenerator = (IIdGenerator)Activator.CreateInstance(zeroIdCheckerType);
+ }
+ }
+ else if (_useNullIdChecker)
+ {
+ idGenerator = NullIdChecker.Instance;
+ }
+ else
+ {
+ idGenerator = null;
+ }
+
+ _idGenerators[type] = idGenerator; // remember it even if it's null
+ }
+
+ return idGenerator;
+ }
+ finally
+ {
+ _configLock.ExitWriteLock();
+ }
+ }
+
+ ///
+ /// Looks up a serializer for a Type.
+ ///
+ /// The type.
+ /// A serializer for type T.
+ public IBsonSerializer LookupSerializer()
+ {
+ return (IBsonSerializer)LookupSerializer(typeof(T));
+ }
+
+ ///
+ /// Looks up a serializer for a Type.
+ ///
+ /// The Type.
+ /// A serializer for the Type.
+ public IBsonSerializer LookupSerializer(Type type)
+ {
+ return _serializerRegistry.GetSerializer(type);
+ }
+
+ ///
+ /// Registers the discriminator for a type.
+ ///
+ /// The type.
+ /// The discriminator.
+ public void RegisterDiscriminator(Type type, BsonValue discriminator)
+ {
+ var typeInfo = type.GetTypeInfo();
+ if (typeInfo.IsInterface)
+ {
+ var message = string.Format("Discriminators can only be registered for classes, not for interface {0}.",
+ type.FullName);
+ throw new BsonSerializationException(message);
+ }
+
+ _configLock.EnterWriteLock();
+ try
+ {
+ HashSet hashSet;
+ if (!_discriminators.TryGetValue(discriminator, out hashSet))
+ {
+ hashSet = new HashSet();
+ _discriminators.Add(discriminator, hashSet);
+ }
+
+ if (!hashSet.Contains(type))
+ {
+ hashSet.Add(type);
+
+ // mark all base types as discriminated (so we know that it's worth reading a discriminator)
+ for (var baseType = typeInfo.BaseType; baseType != null; baseType = baseType.GetTypeInfo().BaseType)
+ {
+ _discriminatedTypes.Add(baseType);
+ }
+ }
+ }
+ finally
+ {
+ _configLock.ExitWriteLock();
+ }
+ }
+
+ ///
+ /// Registers the discriminator convention for a type.
+ ///
+ /// Type type.
+ /// The discriminator convention.
+ public void RegisterDiscriminatorConvention(Type type, IDiscriminatorConvention convention)
+ {
+ _configLock.EnterWriteLock();
+ try
+ {
+ if (!_discriminatorConventions.ContainsKey(type))
+ {
+ _discriminatorConventions.Add(type, convention);
+ }
+ else
+ {
+ var message = string.Format("There is already a discriminator convention registered for type {0}.",
+ type.FullName);
+ throw new BsonSerializationException(message);
+ }
+ }
+ finally
+ {
+ _configLock.ExitWriteLock();
+ }
+ }
+
+ ///
+ /// Registers a generic serializer definition for a generic type.
+ ///
+ /// The generic type.
+ /// The generic serializer definition.
+ public void RegisterGenericSerializerDefinition(
+ Type genericTypeDefinition,
+ Type genericSerializerDefinition)
+ {
+ _typeMappingSerializationProvider.RegisterMapping(genericTypeDefinition, genericSerializerDefinition);
+ }
+
+ ///
+ /// Registers an IdGenerator for an Id Type.
+ ///
+ /// The Id Type.
+ /// The IdGenerator for the Id Type.
+ public void RegisterIdGenerator(Type type, IIdGenerator idGenerator)
+ {
+ _configLock.EnterWriteLock();
+ try
+ {
+ _idGenerators[type] = idGenerator;
+ }
+ finally
+ {
+ _configLock.ExitWriteLock();
+ }
+ }
+
+ ///
+ /// Registers a serialization provider.
+ ///
+ /// The serialization provider.
+ public void RegisterSerializationProvider(IBsonSerializationProvider provider)
+ {
+ _serializerRegistry.RegisterSerializationProvider(provider);
+ }
+
+ ///
+ /// Registers a serializer for a type.
+ ///
+ /// The type.
+ /// The serializer.
+ public void RegisterSerializer(IBsonSerializer serializer)
+ {
+ RegisterSerializer(typeof(T), serializer);
+ }
+
+ ///
+ /// Registers a serializer for a type.
+ ///
+ /// The type.
+ /// The serializer.
+ public void RegisterSerializer(Type type, IBsonSerializer serializer)
+ {
+ _serializerRegistry.RegisterSerializer(type, serializer);
+ }
+
+ ///
+ /// Serializes a value.
+ ///
+ /// The nominal type of the object.
+ /// The BsonWriter.
+ /// The object.
+ /// The serialization context configurator.
+ /// The serialization args.
+ public void Serialize(
+ IBsonWriter bsonWriter,
+ TNominalType value,
+ Action configurator = null,
+ BsonSerializationArgs args = default(BsonSerializationArgs))
+ {
+ args.SetOrValidateNominalType(typeof(TNominalType), "");
+ var serializer = LookupSerializer();
+ var context = BsonSerializationContext.CreateRoot(bsonWriter, this, configurator);
+ serializer.Serialize(context, args, value);
+ }
+
+ ///
+ /// Serializes a value.
+ ///
+ /// The BsonWriter.
+ /// The nominal type of the object.
+ /// The object.
+ /// The serialization context configurator.
+ /// The serialization args.
+ public void Serialize(
+ IBsonWriter bsonWriter,
+ Type nominalType,
+ object value,
+ Action configurator = null,
+ BsonSerializationArgs args = default(BsonSerializationArgs))
+ {
+ args.SetOrValidateNominalType(nominalType, "nominalType");
+ var serializer = LookupSerializer(nominalType);
+ var context = BsonSerializationContext.CreateRoot(bsonWriter, this, configurator);
+ serializer.Serialize(context, args, value);
+ }
+
+ public IBsonClassMapDomain BsonClassMap => _classMapDomain;
+
+ public IConventionRegistryDomain ConventionRegistry => _conventionRegistryDomain;
+
+ public IBsonDefaults BsonDefaults => _bsonDefaults;
+
+ ///
+ /// Tries to register a serializer for a type.
+ ///
+ /// The serializer.
+ /// The type.
+ /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.
+ public bool TryRegisterSerializer(Type type, IBsonSerializer serializer)
+ {
+ return _serializerRegistry.TryRegisterSerializer(type, serializer);
+ }
+
+ ///
+ /// Tries to register a serializer for a type.
+ ///
+ /// The type.
+ /// The serializer.
+ /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.
+ public bool TryRegisterSerializer(IBsonSerializer serializer)
+ {
+ return TryRegisterSerializer(typeof(T), serializer);
+ }
+
+ // internal methods
+ public void EnsureKnownTypesAreRegistered(Type nominalType)
+ {
+ if (_typesWithRegisteredKnownTypes.ContainsKey(nominalType))
+ {
+ return;
+ }
+
+ _configLock.EnterWriteLock();
+ try
+ {
+ if (!_typesWithRegisteredKnownTypes.ContainsKey(nominalType))
+ {
+ // only call LookupClassMap for classes with a BsonKnownTypesAttribute
+ var hasKnownTypesAttribute = nominalType.GetTypeInfo()
+ .GetCustomAttributes(typeof(BsonKnownTypesAttribute), inherit: false).Any();
+ if (hasKnownTypesAttribute)
+ {
+ // try and force a scan of the known types
+ LookupSerializer(nominalType);
+ }
+
+ // NOTE: The nominalType MUST be added to __typesWithRegisteredKnownTypes after all registration
+ // work is done to ensure that other threads don't access a partially registered nominalType
+ // when performing the initial check above outside the __config lock.
+ _typesWithRegisteredKnownTypes[nominalType] = null;
+ }
+ }
+ finally
+ {
+ _configLock.ExitWriteLock();
+ }
+ }
+
+ public void Dispose()
+ {
+ _configLock.Dispose();
+ }
+
+ // private methods
+ private void CreateSerializerRegistry()
+ {
+ _serializerRegistry = new BsonSerializerRegistry(this);
+ _typeMappingSerializationProvider = new TypeMappingSerializationProvider();
+
+ // order matters. It's in reverse order of how they'll get consumed
+ _serializerRegistry.RegisterSerializationProvider(new BsonClassMapSerializationProvider(this));
+ _serializerRegistry.RegisterSerializationProvider(new DiscriminatedInterfaceSerializationProvider());
+ _serializerRegistry.RegisterSerializationProvider(new CollectionsSerializationProvider());
+ _serializerRegistry.RegisterSerializationProvider(new PrimitiveSerializationProvider());
+ _serializerRegistry.RegisterSerializationProvider(new AttributedSerializationProvider());
+ _serializerRegistry.RegisterSerializationProvider(_typeMappingSerializationProvider);
+ _serializerRegistry.RegisterSerializationProvider(new BsonObjectModelSerializationProvider());
+ }
+
+ private void CreateSubDomains()
+ {
+ _classMapDomain = new BsonClassMapDomain(this);
+ _conventionRegistryDomain = new ConventionRegistryDomain();
+ _bsonDefaults = new BsonDefaultsDomain(this);
+ }
+
+ private void RegisterIdGenerators()
+ {
+ RegisterIdGenerator(typeof(BsonObjectId), BsonObjectIdGenerator.Instance);
+ RegisterIdGenerator(typeof(Guid), GuidGenerator.Instance);
+ RegisterIdGenerator(typeof(ObjectId), ObjectIdGenerator.Instance);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs b/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs
index 01a5b9315de..f91a52ea4e2 100644
--- a/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs
+++ b/src/MongoDB.Bson/Serialization/BsonSerializationInfo.cs
@@ -118,7 +118,8 @@ public object DeserializeValue(BsonValue value)
var tempDocument = new BsonDocument("value", value);
using (var reader = new BsonDocumentReader(tempDocument))
{
- var context = BsonDeserializationContext.CreateRoot(reader);
+ //QUESTION Is it correct we only need a default domain here?
+ var context = BsonDeserializationContext.CreateRoot(reader, BsonSerializer.DefaultSerializationDomain);
reader.ReadStartDocument();
reader.ReadName("value");
var deserializedValue = _serializer.Deserialize(context);
@@ -154,7 +155,8 @@ public BsonValue SerializeValue(object value)
var tempDocument = new BsonDocument();
using (var bsonWriter = new BsonDocumentWriter(tempDocument))
{
- var context = BsonSerializationContext.CreateRoot(bsonWriter);
+ //QUESTION Is it correct we only need a default domain here?
+ var context = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain);
bsonWriter.WriteStartDocument();
bsonWriter.WriteName("value");
_serializer.Serialize(context, value);
@@ -173,7 +175,8 @@ public BsonArray SerializeValues(IEnumerable values)
var tempDocument = new BsonDocument();
using (var bsonWriter = new BsonDocumentWriter(tempDocument))
{
- var context = BsonSerializationContext.CreateRoot(bsonWriter);
+ //QUESTION Is it correct we only need a default domain here?
+ var context = BsonSerializationContext.CreateRoot(bsonWriter, BsonSerializer.DefaultSerializationDomain);
bsonWriter.WriteStartDocument();
bsonWriter.WriteName("values");
bsonWriter.WriteStartArray();
diff --git a/src/MongoDB.Bson/Serialization/BsonSerializationProviderBase.cs b/src/MongoDB.Bson/Serialization/BsonSerializationProviderBase.cs
index b2ffb587183..de65cd9ad1d 100644
--- a/src/MongoDB.Bson/Serialization/BsonSerializationProviderBase.cs
+++ b/src/MongoDB.Bson/Serialization/BsonSerializationProviderBase.cs
@@ -23,15 +23,17 @@ namespace MongoDB.Bson.Serialization
///
public abstract class BsonSerializationProviderBase : IRegistryAwareBsonSerializationProvider
{
+ //DOMAIN-API We should remove this and use the overload that takes a serializer registry instead.
///
public virtual IBsonSerializer GetSerializer(Type type)
{
- return GetSerializer(type, BsonSerializer.SerializerRegistry);
+ return GetSerializer(type, BsonSerializer.DefaultSerializationDomain.SerializerRegistry);
}
///
public abstract IBsonSerializer GetSerializer(Type type, IBsonSerializerRegistry serializerRegistry);
+ //DOMAIN-API We should remove this and use the overload that takes a serializer registry instead.
///
/// Creates the serializer from a serializer type definition and type arguments.
///
@@ -40,7 +42,7 @@ public virtual IBsonSerializer GetSerializer(Type type)
/// A serializer.
protected virtual IBsonSerializer CreateGenericSerializer(Type serializerTypeDefinition, params Type[] typeArguments)
{
- return CreateGenericSerializer(serializerTypeDefinition, typeArguments, BsonSerializer.SerializerRegistry);
+ return CreateGenericSerializer(serializerTypeDefinition, typeArguments, BsonSerializer.DefaultSerializationDomain.SerializerRegistry);
}
///
@@ -58,6 +60,7 @@ protected virtual IBsonSerializer CreateGenericSerializer(Type serializerTypeDef
return CreateSerializer(serializerType, serializerRegistry);
}
+ //DOMAIN-API We should remove this and use the overload that takes a serializer registry instead.
///
/// Creates the serializer.
///
diff --git a/src/MongoDB.Bson/Serialization/BsonSerializer.cs b/src/MongoDB.Bson/Serialization/BsonSerializer.cs
index 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..e5b9aad1caa 100644
--- a/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs
+++ b/src/MongoDB.Bson/Serialization/BsonSerializerRegistry.cs
@@ -33,14 +33,22 @@ public sealed class BsonSerializerRegistry : IBsonSerializerRegistry
///
/// Initializes a new instance of the class.
///
- public BsonSerializerRegistry()
+ public BsonSerializerRegistry():
+ this(BsonSerializer.DefaultSerializationDomain)
+ {
+ }
+
+ ///
+ /// //TODO
+ ///
+ ///
+ internal BsonSerializerRegistry(IBsonSerializationDomain serializationDomain)
{
_cache = new ConcurrentDictionary();
_serializationProviders = new ConcurrentStack();
_createSerializer = CreateSerializer;
}
- // public methods
///
/// Gets the serializer for the specified .
/// If none is already registered, the serialization providers will be used to create a serializer and it will be automatically registered.
@@ -156,17 +164,14 @@ private IBsonSerializer CreateSerializer(Type type)
{
foreach (var serializationProvider in _serializationProviders)
{
- IBsonSerializer serializer;
-
- var registryAwareSerializationProvider = serializationProvider as IRegistryAwareBsonSerializationProvider;
- if (registryAwareSerializationProvider != null)
- {
- serializer = registryAwareSerializationProvider.GetSerializer(type, this);
- }
- else
+ var serializer = serializationProvider switch
{
- serializer = serializationProvider.GetSerializer(type);
- }
+ IDomainAwareBsonSerializationProvider domainAwareBsonSerializationProvider =>
+ domainAwareBsonSerializationProvider.GetSerializerWithDomain(type),
+ IRegistryAwareBsonSerializationProvider registryAwareSerializationProvider =>
+ registryAwareSerializationProvider.GetSerializer(type, this),
+ _ => serializationProvider.GetSerializer(type)
+ };
if (serializer != null)
{
diff --git a/src/MongoDB.Bson/Serialization/Conventions/AttributeConventionPack.cs b/src/MongoDB.Bson/Serialization/Conventions/AttributeConventionPack.cs
index 77f0bc0cb78..b5646e41489 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/AttributeConventionPack.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/AttributeConventionPack.cs
@@ -60,7 +60,7 @@ public IEnumerable Conventions
}
// nested classes
- private class AttributeConvention : ConventionBase, IClassMapConvention, ICreatorMapConvention, IMemberMapConvention, IPostProcessingConvention
+ private class AttributeConvention : ConventionBase, IClassMapConvention, ICreatorMapConvention, IMemberMapConventionInternal, IPostProcessingConventionInternal
{
// public methods
public void Apply(BsonClassMap classMap)
@@ -87,7 +87,9 @@ public void Apply(BsonCreatorMap creatorMap)
}
}
- public void Apply(BsonMemberMap memberMap)
+ public void Apply(BsonMemberMap memberMap) => Apply(memberMap, BsonSerializer.DefaultSerializationDomain);
+
+ public void Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain)
{
var attributes = memberMap.MemberInfo.GetCustomAttributes(inherit: false).OfType();
var groupings = attributes.GroupBy(a => (a is BsonSerializerAttribute) ? 1 : 2);
@@ -100,7 +102,9 @@ public void Apply(BsonMemberMap memberMap)
}
}
- public void PostProcess(BsonClassMap classMap)
+ public void PostProcess(BsonClassMap classMap) => PostProcess(classMap, BsonSerializer.DefaultSerializationDomain);
+
+ public void PostProcess(BsonClassMap classMap, IBsonSerializationDomain domain)
{
foreach (var attribute in classMap.ClassType.GetTypeInfo().GetCustomAttributes(inherit: false).OfType())
{
diff --git a/src/MongoDB.Bson/Serialization/Conventions/CamelCaseElementNameConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/CamelCaseElementNameConvention.cs
index dd249c11359..9154e353deb 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/CamelCaseElementNameConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/CamelCaseElementNameConvention.cs
@@ -14,21 +14,20 @@
*/
using System;
-using System.Reflection;
namespace MongoDB.Bson.Serialization.Conventions
{
///
/// A convention that sets the element name the same as the member name with the first character lower cased.
///
- public class CamelCaseElementNameConvention : ConventionBase, IMemberMapConvention
+ public class CamelCaseElementNameConvention : ConventionBase, IMemberMapConventionInternal
{
// public methods
- ///
- /// Applies a modification to the member map.
- ///
- /// The member map.
- public void Apply(BsonMemberMap memberMap)
+ ///
+ public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain)
{
string name = memberMap.MemberName;
name = GetElementName(name);
diff --git a/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistry.cs b/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistry.cs
index 217a7b69d86..d389df271ef 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistry.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistry.cs
@@ -14,7 +14,6 @@
*/
using System;
-using System.Collections.Generic;
namespace MongoDB.Bson.Serialization.Conventions
{
@@ -23,60 +22,14 @@ namespace MongoDB.Bson.Serialization.Conventions
///
public static class ConventionRegistry
{
- // private static fields
- private readonly static List __conventionPacks = new List();
- private readonly static object __lock = new object();
-
- // static constructors
- static ConventionRegistry()
- {
- Register("__defaults__", DefaultConventionPack.Instance, t => true);
- Register("__attributes__", AttributeConventionPack.Instance, t => true);
- }
-
// public static methods
///
/// Looks up the effective set of conventions that apply to a type.
///
/// The type.
/// The conventions for that type.
- public static IConventionPack Lookup(Type type)
- {
- if (type == null)
- {
- throw new ArgumentNullException("type");
- }
-
- lock (__lock)
- {
- var pack = new ConventionPack();
-
- // append any attribute packs (usually just one) at the end so attributes are processed last
- var attributePacks = new List();
- foreach (var container in __conventionPacks)
- {
- if (container.Filter(type))
- {
-
- if (container.Name == "__attributes__")
- {
- attributePacks.Add(container.Pack);
- }
- else
- {
- pack.Append(container.Pack);
- }
- }
- }
-
- foreach (var attributePack in attributePacks)
- {
- pack.Append(attributePack);
- }
-
- return pack;
- }
- }
+ public static IConventionPack Lookup(Type type) =>
+ BsonSerializer.DefaultSerializationDomain.ConventionRegistry.Lookup(type);
///
/// Registers the conventions.
@@ -84,33 +37,8 @@ public static IConventionPack Lookup(Type type)
/// The name.
/// The conventions.
/// The filter.
- public static void Register(string name, IConventionPack conventions, Func filter)
- {
- if (name == null)
- {
- throw new ArgumentNullException("name");
- }
- if (conventions == null)
- {
- throw new ArgumentNullException("conventions");
- }
- if (filter == null)
- {
- throw new ArgumentNullException("filter");
- }
-
- lock (__lock)
- {
- var container = new ConventionPackContainer
- {
- Filter = filter,
- Name = name,
- Pack = conventions
- };
-
- __conventionPacks.Add(container);
- }
- }
+ public static void Register(string name, IConventionPack conventions, Func filter) =>
+ BsonSerializer.DefaultSerializationDomain.ConventionRegistry.Register(name, conventions, filter);
///
/// Removes the conventions specified by the given name.
@@ -119,25 +47,7 @@ public static void Register(string name, IConventionPack conventions, FuncRemoving a convention allows the removal of the special __defaults__ conventions
/// and the __attributes__ conventions for those who want to completely customize the
/// experience.
- public static void Remove(string name)
- {
- if (name == null)
- {
- throw new ArgumentNullException("name");
- }
-
- lock (__lock)
- {
- __conventionPacks.RemoveAll(x => x.Name == name);
- }
- }
-
- // private class
- private class ConventionPackContainer
- {
- public Func Filter;
- public string Name;
- public IConventionPack Pack;
- }
+ public static void Remove(string name) =>
+ BsonSerializer.DefaultSerializationDomain.ConventionRegistry.Remove(name);
}
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistryDomain.cs b/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistryDomain.cs
new file mode 100644
index 00000000000..fec96b02e31
--- /dev/null
+++ b/src/MongoDB.Bson/Serialization/Conventions/ConventionRegistryDomain.cs
@@ -0,0 +1,141 @@
+/* Copyright 2010-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+
+namespace MongoDB.Bson.Serialization.Conventions
+{
+ internal class ConventionRegistryDomain : IConventionRegistryDomain
+ {
+ private readonly List _conventionPacks = [];
+ private readonly object _lock = new();
+
+ // constructors
+ internal ConventionRegistryDomain()
+ {
+ Register("__defaults__", DefaultConventionPack.Instance, t => true);
+ Register("__attributes__", AttributeConventionPack.Instance, t => true);
+ }
+
+ // public static methods
+ ///
+ /// Looks up the effective set of conventions that apply to a type.
+ ///
+ /// The type.
+ /// The conventions for that type.
+ public IConventionPack Lookup(Type type)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException("type");
+ }
+
+ lock (_lock)
+ {
+ var pack = new ConventionPack();
+
+ // append any attribute packs (usually just one) at the end so attributes are processed last
+ var attributePacks = new List();
+ foreach (var container in _conventionPacks)
+ {
+ if (container.Filter(type))
+ {
+
+ if (container.Name == "__attributes__")
+ {
+ attributePacks.Add(container.Pack);
+ }
+ else
+ {
+ pack.Append(container.Pack);
+ }
+ }
+ }
+
+ foreach (var attributePack in attributePacks)
+ {
+ pack.Append(attributePack);
+ }
+
+ return pack;
+ }
+ }
+
+ ///
+ /// Registers the conventions.
+ ///
+ /// The name.
+ /// The conventions.
+ /// The filter.
+ public void Register(string name, IConventionPack conventions, Func filter)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+
+ if (conventions == null)
+ {
+ throw new ArgumentNullException("conventions");
+ }
+
+ if (filter == null)
+ {
+ throw new ArgumentNullException("filter");
+ }
+
+ lock (_lock)
+ {
+ var container = new ConventionPackContainer
+ {
+ Filter = filter,
+ Name = name,
+ Pack = conventions
+ };
+
+ _conventionPacks.Add(container);
+ }
+ }
+
+ ///
+ /// Removes the conventions specified by the given name.
+ ///
+ /// The name.
+ /// Removing a convention allows the removal of the special __defaults__ conventions
+ /// and the __attributes__ conventions for those who want to completely customize the
+ /// experience.
+ public void Remove(string name)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException("name");
+ }
+
+ lock (_lock)
+ {
+ _conventionPacks.RemoveAll(x => x.Name == name);
+ }
+ }
+
+ // private class
+ private class ConventionPackContainer
+ {
+ public Func Filter;
+ public string Name;
+ public IConventionPack Pack;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/Serialization/Conventions/ConventionRunner.cs b/src/MongoDB.Bson/Serialization/Conventions/ConventionRunner.cs
index 091be418810..8b8431bae16 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/ConventionRunner.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/ConventionRunner.cs
@@ -47,7 +47,9 @@ public ConventionRunner(IConventionPack conventions)
/// Applies a modification to the class map.
///
/// The class map.
- public void Apply(BsonClassMap classMap)
+ public void Apply(BsonClassMap classMap) => Apply(classMap, BsonSerializer.DefaultSerializationDomain);
+
+ internal void Apply(BsonClassMap classMap, IBsonSerializationDomain serializationDomain)
{
foreach (var convention in _conventions.OfType())
{
@@ -58,7 +60,7 @@ public void Apply(BsonClassMap classMap)
{
foreach (var memberMap in classMap.DeclaredMemberMaps)
{
- convention.Apply(memberMap);
+ convention.ApplyInternal(memberMap, serializationDomain);
}
}
@@ -72,7 +74,7 @@ public void Apply(BsonClassMap classMap)
foreach (var convention in _conventions.OfType())
{
- convention.PostProcess(classMap);
+ convention.PostProcessInternal(classMap, serializationDomain);
}
}
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/DelegateMemberMapConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/DelegateMemberMapConvention.cs
index 80cafe70046..f2c90e32fe5 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/DelegateMemberMapConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/DelegateMemberMapConvention.cs
@@ -20,7 +20,7 @@ namespace MongoDB.Bson.Serialization.Conventions
///
/// A member map convention that wraps a delegate.
///
- public class DelegateMemberMapConvention : ConventionBase, IMemberMapConvention
+ public class DelegateMemberMapConvention : ConventionBase, IMemberMapConventionInternal
{
// private fields
private readonly Action _action;
@@ -46,7 +46,10 @@ public DelegateMemberMapConvention(string name, Action action)
/// Applies a modification to the member map.
///
/// The member map.
- public void Apply(BsonMemberMap memberMap)
+ public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain)
{
_action(memberMap);
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/DelegatePostProcessingConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/DelegatePostProcessingConvention.cs
index 8c535f842f0..d8e6c1408f8 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/DelegatePostProcessingConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/DelegatePostProcessingConvention.cs
@@ -20,7 +20,7 @@ namespace MongoDB.Bson.Serialization.Conventions
///
/// A post processing convention that wraps a delegate.
///
- public class DelegatePostProcessingConvention : ConventionBase, IPostProcessingConvention
+ public class DelegatePostProcessingConvention : ConventionBase, IPostProcessingConventionInternal
{
// private fields
private readonly Action _action;
@@ -46,7 +46,10 @@ public DelegatePostProcessingConvention(string name, Action action
/// Applies a post processing modification to the class map.
///
/// The class map.
- public void PostProcess(BsonClassMap classMap)
+ public void PostProcess(BsonClassMap classMap) => (this as IPostProcessingConventionInternal).PostProcess(classMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IPostProcessingConventionInternal.PostProcess(BsonClassMap classMap, IBsonSerializationDomain domain)
{
_action(classMap);
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/EnumRepresentationConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/EnumRepresentationConvention.cs
index 4f5274a0664..b0c6bfabd5a 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/EnumRepresentationConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/EnumRepresentationConvention.cs
@@ -21,7 +21,7 @@ namespace MongoDB.Bson.Serialization.Conventions
///
/// A convention that allows you to set the Enum serialization representation
///
- public class EnumRepresentationConvention : ConventionBase, IMemberMapConvention
+ public class EnumRepresentationConvention : ConventionBase, IMemberMapConventionInternal
{
// private fields
private readonly BsonType _representation;
@@ -66,7 +66,10 @@ public EnumRepresentationConvention(BsonType representation, bool topLevelOnly)
/// Applies a modification to the member map.
///
/// The member map.
- public void Apply(BsonMemberMap memberMap)
+ public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain)
{
var memberType = memberMap.MemberType;
diff --git a/src/MongoDB.Bson/Serialization/Conventions/HierarchicalDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/HierarchicalDiscriminatorConvention.cs
index beebf06230e..85751240e74 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/HierarchicalDiscriminatorConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/HierarchicalDiscriminatorConvention.cs
@@ -16,13 +16,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using MongoDB.Bson.IO;
namespace MongoDB.Bson.Serialization.Conventions
{
///
/// Represents a discriminator convention where the discriminator is an array of all the discriminators provided by the class maps of the root class down to the actual type.
///
- public class HierarchicalDiscriminatorConvention : StandardDiscriminatorConvention, IHierarchicalDiscriminatorConvention
+ public class HierarchicalDiscriminatorConvention : StandardDiscriminatorConvention, IHierarchicalDiscriminatorConvention, IDiscriminatorConventionInternal
{
// constructors
///
@@ -34,6 +35,11 @@ public HierarchicalDiscriminatorConvention(string elementName)
{
}
+ Type IDiscriminatorConventionInternal.GetActualType(IBsonReader bsonReader, Type nominalType, IBsonSerializationDomain domain)
+ {
+ return base.GetActualType(bsonReader, nominalType, domain);
+ }
+
// public methods
///
/// Gets the discriminator value for an actual type.
@@ -41,10 +47,14 @@ public HierarchicalDiscriminatorConvention(string elementName)
/// The nominal type.
/// The actual type.
/// The discriminator value.
- public override BsonValue GetDiscriminator(Type nominalType, Type actualType)
+ public override BsonValue GetDiscriminator(Type nominalType, Type actualType) =>
+ (this as IDiscriminatorConventionInternal).GetDiscriminator(nominalType, actualType, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ BsonValue IDiscriminatorConventionInternal.GetDiscriminator(Type nominalType, Type actualType, IBsonSerializationDomain domain)
{
// TODO: this isn't quite right, not all classes are serialized using a class map serializer
- var classMap = BsonClassMap.LookupClassMap(actualType);
+ var classMap = domain.BsonClassMap.LookupClassMap(actualType);
if (actualType != nominalType || classMap.DiscriminatorIsRequired || classMap.HasRootClass)
{
if (classMap.HasRootClass && !classMap.IsRootClass)
diff --git a/src/MongoDB.Bson/Serialization/Conventions/IConventionRegistryDomain.cs b/src/MongoDB.Bson/Serialization/Conventions/IConventionRegistryDomain.cs
new file mode 100644
index 00000000000..b2720052419
--- /dev/null
+++ b/src/MongoDB.Bson/Serialization/Conventions/IConventionRegistryDomain.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace MongoDB.Bson.Serialization.Conventions
+{
+ internal interface IConventionRegistryDomain
+ {
+ ///
+ /// //TODO
+ ///
+ ///
+ ///
+ IConventionPack Lookup(Type type);
+
+ ///
+ /// //TODO
+ ///
+ ///
+ ///
+ ///
+ void Register(string name, IConventionPack conventions, Func filter);
+
+ ///
+ /// //TODO
+ ///
+ ///
+ void Remove(string name);
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/Serialization/Conventions/IDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/IDiscriminatorConvention.cs
index 242d0b557b2..cfd44ef8936 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/IDiscriminatorConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/IDiscriminatorConvention.cs
@@ -44,4 +44,26 @@ public interface IDiscriminatorConvention
/// The discriminator value.
BsonValue GetDiscriminator(Type nominalType, Type actualType);
}
+
+ //DOMAIN-API These methods should be substitute the above methods in the interface
+ internal interface IDiscriminatorConventionInternal : IDiscriminatorConvention
+ {
+ ///
+ /// //TODO
+ ///
+ ///
+ ///
+ ///
+ ///
+ Type GetActualType(IBsonReader bsonReader, Type nominalType, IBsonSerializationDomain domain);
+
+ ///
+ /// //TODO
+ ///
+ ///
+ ///
+ ///
+ ///
+ BsonValue GetDiscriminator(Type nominalType, Type actualType, IBsonSerializationDomain domain);
+ }
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/IMemberMapConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/IMemberMapConvention.cs
index b05f40d64ad..dfb138ea4d2 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/IMemberMapConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/IMemberMapConvention.cs
@@ -26,4 +26,14 @@ public interface IMemberMapConvention : IConvention
/// The member map.
void Apply(BsonMemberMap memberMap);
}
+
+ internal interface IMemberMapConventionInternal : IMemberMapConvention
+ {
+ ///
+ /// //TODO
+ ///
+ ///
+ ///
+ void Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain);
+ }
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/IPostProcessingConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/IPostProcessingConvention.cs
index ddb7a095df5..ea43f926c4a 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/IPostProcessingConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/IPostProcessingConvention.cs
@@ -26,4 +26,14 @@ public interface IPostProcessingConvention : IConvention
/// The class map.
void PostProcess(BsonClassMap classMap);
}
+
+ internal interface IPostProcessingConventionInternal : IPostProcessingConvention
+ {
+ ///
+ /// //TODO
+ ///
+ ///
+ ///
+ void PostProcess(BsonClassMap classMap, IBsonSerializationDomain domain);
+ }
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/IScalarDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/IScalarDiscriminatorConvention.cs
index 82c2e794626..4d09b977b01 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/IScalarDiscriminatorConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/IScalarDiscriminatorConvention.cs
@@ -29,4 +29,9 @@ public interface IScalarDiscriminatorConvention : IDiscriminatorConvention
/// The discriminators.
BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type);
}
+
+ internal interface IScalarDiscriminatorConventionInternal : IScalarDiscriminatorConvention
+ {
+ BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type, IBsonSerializationDomain serializationDomain);
+ }
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfDefaultConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfDefaultConvention.cs
index aede146fe8c..a7d855cf2e0 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfDefaultConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfDefaultConvention.cs
@@ -18,7 +18,7 @@ namespace MongoDB.Bson.Serialization.Conventions
///
/// A convention that sets whether to ignore default values during serialization.
///
- public class IgnoreIfDefaultConvention : ConventionBase, IMemberMapConvention
+ public class IgnoreIfDefaultConvention : ConventionBase, IMemberMapConventionInternal
{
// private fields
private bool _ignoreIfDefault;
@@ -37,7 +37,10 @@ public IgnoreIfDefaultConvention(bool ignoreIfDefault)
/// Applies a modification to the member map.
///
/// The member map.
- public void Apply(BsonMemberMap memberMap)
+ public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain)
{
memberMap.SetIgnoreIfDefault(_ignoreIfDefault);
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfNullConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfNullConvention.cs
index c99f694fe81..cebcd8dc86d 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfNullConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/IgnoreIfNullConvention.cs
@@ -18,7 +18,7 @@ namespace MongoDB.Bson.Serialization.Conventions
///
/// A convention that sets whether to ignore nulls during serialization.
///
- public class IgnoreIfNullConvention : ConventionBase, IMemberMapConvention
+ public class IgnoreIfNullConvention : ConventionBase, IMemberMapConventionInternal
{
// private fields
private bool _ignoreIfNull;
@@ -37,7 +37,10 @@ public IgnoreIfNullConvention(bool ignoreIfNull)
/// Applies a modification to the member map.
///
/// The member map.
- public void Apply(BsonMemberMap memberMap)
+ public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain)
{
memberMap.SetIgnoreIfNull(_ignoreIfNull);
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/LookupIdGeneratorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/LookupIdGeneratorConvention.cs
index 81f31d14444..19eb4ee2058 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/LookupIdGeneratorConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/LookupIdGeneratorConvention.cs
@@ -13,29 +13,26 @@
* limitations under the License.
*/
-using System;
-using System.Reflection;
-
namespace MongoDB.Bson.Serialization.Conventions
{
///
/// A convention that looks up an id generator for the id member.
///
- public class LookupIdGeneratorConvention : ConventionBase, IPostProcessingConvention
+ public class LookupIdGeneratorConvention : ConventionBase, IPostProcessingConventionInternal
{
- // public methods
- ///
- /// Applies a post processing modification to the class map.
- ///
- /// The class map.
- public void PostProcess(BsonClassMap classMap)
+ ///
+ public void PostProcess(BsonClassMap classMap) => (this as IPostProcessingConventionInternal).PostProcess(classMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IPostProcessingConventionInternal.PostProcess(BsonClassMap classMap, IBsonSerializationDomain domain)
{
var idMemberMap = classMap.IdMemberMap;
if (idMemberMap != null)
{
if (idMemberMap.IdGenerator == null)
{
- var idGenerator = BsonSerializer.LookupIdGenerator(idMemberMap.MemberType);
+ //or we pass the domain to the BsonClassMap. The first probably makes more sense, but it's messier.
+ var idGenerator = domain.LookupIdGenerator(idMemberMap.MemberType);
if (idGenerator != null)
{
idMemberMap.SetIdGenerator(idGenerator);
diff --git a/src/MongoDB.Bson/Serialization/Conventions/MemberDefaultValueConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/MemberDefaultValueConvention.cs
index 51ff212c300..29076be1b2c 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/MemberDefaultValueConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/MemberDefaultValueConvention.cs
@@ -20,7 +20,7 @@ namespace MongoDB.Bson.Serialization.Conventions
///
/// A convention that sets the default value for members of a given type.
///
- public class MemberDefaultValueConvention : ConventionBase, IMemberMapConvention
+ public class MemberDefaultValueConvention : ConventionBase, IMemberMapConventionInternal
{
// private fields
private readonly Type _type;
@@ -43,7 +43,10 @@ public MemberDefaultValueConvention(Type type, object defaultValue)
/// Applies a modification to the member map.
///
/// The member map.
- public void Apply(BsonMemberMap memberMap)
+ public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain)
{
if (memberMap.MemberType == _type)
{
diff --git a/src/MongoDB.Bson/Serialization/Conventions/MemberNameElementNameConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/MemberNameElementNameConvention.cs
index bdee9118a15..daa0a1314a9 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/MemberNameElementNameConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/MemberNameElementNameConvention.cs
@@ -13,22 +13,22 @@
* limitations under the License.
*/
-using System;
-using System.Reflection;
-
namespace MongoDB.Bson.Serialization.Conventions
{
///
/// A convention that sets the element name the same as the member name.
///
- public class MemberNameElementNameConvention : ConventionBase, IMemberMapConvention
+ public class MemberNameElementNameConvention : ConventionBase, IMemberMapConventionInternal
{
// public methods
///
/// Applies a modification to the member map.
///
/// The member map.
- public void Apply(BsonMemberMap memberMap)
+ public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain)
{
memberMap.SetElementName(memberMap.MemberName);
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/NoIdMemberConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/NoIdMemberConvention.cs
index 82d295cb42f..4a4b4a829ff 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/NoIdMemberConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/NoIdMemberConvention.cs
@@ -13,24 +13,22 @@
* limitations under the License.
*/
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-
namespace MongoDB.Bson.Serialization.Conventions
{
///
/// A convention that sets a class's IdMember to null.
///
- public class NoIdMemberConvention : ConventionBase, IPostProcessingConvention
+ public class NoIdMemberConvention : ConventionBase, IPostProcessingConventionInternal
{
// public methods
///
/// Applies a post processing modification to the class map.
///
/// The class map.
- public void PostProcess(BsonClassMap classMap)
+ public void PostProcess(BsonClassMap classMap) => (this as IPostProcessingConventionInternal).PostProcess(classMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IPostProcessingConventionInternal.PostProcess(BsonClassMap classMap, IBsonSerializationDomain domain)
{
classMap.SetIdMember(null);
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/ObjectDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/ObjectDiscriminatorConvention.cs
index 9a0a7683368..f732a04ea3f 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/ObjectDiscriminatorConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/ObjectDiscriminatorConvention.cs
@@ -86,7 +86,11 @@ obj is ObjectDiscriminatorConvention other &&
/// The reader.
/// The nominal type.
/// The actual type.
- public Type GetActualType(IBsonReader bsonReader, Type nominalType)
+ public Type GetActualType(IBsonReader bsonReader, Type nominalType) =>
+ GetActualType(bsonReader, nominalType, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ internal Type GetActualType(IBsonReader bsonReader, Type nominalType, IBsonSerializationDomain domain)
{
// the BsonReader is sitting at the value whose actual type needs to be found
var bsonType = bsonReader.GetCurrentBsonType();
@@ -129,13 +133,13 @@ public Type GetActualType(IBsonReader bsonReader, Type nominalType)
var actualType = nominalType;
if (bsonReader.FindElement(_elementName))
{
- var context = BsonDeserializationContext.CreateRoot(bsonReader);
+ var context = BsonDeserializationContext.CreateRoot(bsonReader, domain);
var discriminator = BsonValueSerializer.Instance.Deserialize(context);
if (discriminator.IsBsonArray)
{
discriminator = discriminator.AsBsonArray.Last(); // last item is leaf class discriminator
}
- actualType = BsonSerializer.LookupActualType(nominalType, discriminator);
+ actualType = domain.LookupActualType(nominalType, discriminator);
}
bsonReader.ReturnToBookmark(bookmark);
return actualType;
diff --git a/src/MongoDB.Bson/Serialization/Conventions/ObjectSerializerAllowedTypesConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/ObjectSerializerAllowedTypesConvention.cs
index f4860f81c9f..5da3436d025 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/ObjectSerializerAllowedTypesConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/ObjectSerializerAllowedTypesConvention.cs
@@ -25,7 +25,7 @@ namespace MongoDB.Bson.Serialization.Conventions
///
/// A convention that allows to set the types that can be safely serialized and deserialized with the .
///
- public sealed class ObjectSerializerAllowedTypesConvention : ConventionBase, IMemberMapConvention
+ public sealed class ObjectSerializerAllowedTypesConvention : ConventionBase, IMemberMapConventionInternal
{
// static properties
@@ -151,7 +151,10 @@ public bool AllowDefaultFrameworkTypes
/// Applies a modification to the member map.
///
/// The member map.
- public void Apply(BsonMemberMap memberMap)
+ public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain)
{
var memberType = memberMap.MemberType;
diff --git a/src/MongoDB.Bson/Serialization/Conventions/ResetMemberMapsConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/ResetMemberMapsConvention.cs
index ef21036c3e3..959aecc0900 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/ResetMemberMapsConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/ResetMemberMapsConvention.cs
@@ -18,14 +18,17 @@ namespace MongoDB.Bson.Serialization.Conventions
///
/// A convention that resets class members (resetting any changes that earlier conventions may have applied).
///
- public class ResetMemberMapsConvention : ConventionBase, IMemberMapConvention
+ public class ResetMemberMapsConvention : ConventionBase, IMemberMapConventionInternal
{
// public methods
///
/// Applies a modification to the member map.
///
/// The member map.
- public void Apply(BsonMemberMap memberMap)
+ public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain)
{
memberMap.Reset();
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/ScalarDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/ScalarDiscriminatorConvention.cs
index 521aff9b1f7..d9259824a24 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/ScalarDiscriminatorConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/ScalarDiscriminatorConvention.cs
@@ -15,13 +15,14 @@
using System;
using System.Collections.Concurrent;
+using MongoDB.Bson.IO;
namespace MongoDB.Bson.Serialization.Conventions
{
///
/// Represents a discriminator convention where the discriminator is provided by the class map of the actual type.
///
- public class ScalarDiscriminatorConvention : StandardDiscriminatorConvention, IScalarDiscriminatorConvention
+ public class ScalarDiscriminatorConvention : StandardDiscriminatorConvention, IScalarDiscriminatorConventionInternal, IDiscriminatorConventionInternal
{
private readonly ConcurrentDictionary _cachedTypeAndSubTypeDiscriminators = new();
@@ -35,6 +36,11 @@ public ScalarDiscriminatorConvention(string elementName)
{
}
+ Type IDiscriminatorConventionInternal.GetActualType(IBsonReader bsonReader, Type nominalType, IBsonSerializationDomain domain)
+ {
+ return base.GetActualType(bsonReader, nominalType, domain);
+ }
+
// public methods
///
/// Gets the discriminator value for an actual type.
@@ -42,10 +48,14 @@ public ScalarDiscriminatorConvention(string elementName)
/// The nominal type.
/// The actual type.
/// The discriminator value.
- public override BsonValue GetDiscriminator(Type nominalType, Type actualType)
+ public override BsonValue GetDiscriminator(Type nominalType, Type actualType) =>
+ (this as IDiscriminatorConventionInternal).GetDiscriminator(nominalType, actualType, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ BsonValue IDiscriminatorConventionInternal.GetDiscriminator(Type nominalType, Type actualType, IBsonSerializationDomain domain)
{
// TODO: this isn't quite right, not all classes are serialized using a class map serializer
- var classMap = BsonClassMap.LookupClassMap(actualType);
+ var classMap = domain.BsonClassMap.LookupClassMap(actualType);
if (actualType != nominalType || classMap.DiscriminatorIsRequired)
{
return classMap.Discriminator;
@@ -57,9 +67,12 @@ public override BsonValue GetDiscriminator(Type nominalType, Type actualType)
}
///
- public BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type)
+ public BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type) =>
+ (this as IScalarDiscriminatorConventionInternal).GetDiscriminatorsForTypeAndSubTypes(type, BsonSerializer.DefaultSerializationDomain);
+
+ BsonValue[] IScalarDiscriminatorConventionInternal.GetDiscriminatorsForTypeAndSubTypes(Type type, IBsonSerializationDomain serializationDomain)
{
- return _cachedTypeAndSubTypeDiscriminators.GetOrAdd(type, BsonSerializer.GetDiscriminatorsForTypeAndSubTypes);
+ return _cachedTypeAndSubTypeDiscriminators.GetOrAdd(type, serializationDomain.GetDiscriminatorsForTypeAndSubTypes);
}
}
}
diff --git a/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs
index d2b042d1fc0..e215da6d68c 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/StandardDiscriminatorConvention.cs
@@ -95,30 +95,33 @@ obj is StandardDiscriminatorConvention other &&
/// The reader.
/// The nominal type.
/// The actual type.
- public Type GetActualType(IBsonReader bsonReader, Type nominalType)
+ public Type GetActualType(IBsonReader bsonReader, Type nominalType) => //TODO This one should not be used
+ GetActualType(bsonReader, nominalType, BsonSerializer.DefaultSerializationDomain);
+
+ internal Type GetActualType(IBsonReader bsonReader, Type nominalType, IBsonSerializationDomain domain)
{
// the BsonReader is sitting at the value whose actual type needs to be found
var bsonType = bsonReader.GetCurrentBsonType();
if (bsonType == BsonType.Document)
{
// ensure KnownTypes of nominalType are registered (so IsTypeDiscriminated returns correct answer)
- BsonSerializer.EnsureKnownTypesAreRegistered(nominalType);
+ domain.EnsureKnownTypesAreRegistered(nominalType);
// we can skip looking for a discriminator if nominalType has no discriminated sub types
- if (BsonSerializer.IsTypeDiscriminated(nominalType))
+ if (domain.IsTypeDiscriminated(nominalType))
{
var bookmark = bsonReader.GetBookmark();
bsonReader.ReadStartDocument();
var actualType = nominalType;
if (bsonReader.FindElement(_elementName))
{
- var context = BsonDeserializationContext.CreateRoot(bsonReader);
+ var context = BsonDeserializationContext.CreateRoot(bsonReader, domain);
var discriminator = BsonValueSerializer.Instance.Deserialize(context);
if (discriminator.IsBsonArray)
{
discriminator = discriminator.AsBsonArray.Last(); // last item is leaf class discriminator
}
- actualType = BsonSerializer.LookupActualType(nominalType, discriminator);
+ actualType = domain.LookupActualType(nominalType, discriminator);
}
bsonReader.ReturnToBookmark(bookmark);
return actualType;
diff --git a/src/MongoDB.Bson/Serialization/Conventions/StringIdStoredAsObjectIdConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/StringIdStoredAsObjectIdConvention.cs
index 923936d1508..d757e33b6f4 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/StringIdStoredAsObjectIdConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/StringIdStoredAsObjectIdConvention.cs
@@ -23,10 +23,13 @@ namespace MongoDB.Bson.Serialization.Conventions
/// This convention is only responsible for setting the serializer and idGenerator. It is assumed that this convention runs after
/// other conventions that identify which member is the _id and that the _id has already been added to the class map.
///
- public class StringIdStoredAsObjectIdConvention : ConventionBase, IMemberMapConvention
+ public class StringIdStoredAsObjectIdConvention : ConventionBase, IMemberMapConventionInternal
{
///
- public void Apply(BsonMemberMap memberMap)
+ public void Apply(BsonMemberMap memberMap) => (this as IMemberMapConventionInternal).Apply(memberMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IMemberMapConventionInternal.Apply(BsonMemberMap memberMap, IBsonSerializationDomain domain)
{
if (memberMap != memberMap.ClassMap.IdMemberMap)
{
@@ -38,7 +41,7 @@ public void Apply(BsonMemberMap memberMap)
return;
}
- var defaultStringSerializer = BsonSerializer.LookupSerializer(typeof(string));
+ var defaultStringSerializer = domain.LookupSerializer(typeof(string));
if (memberMap.GetSerializer() != defaultStringSerializer)
{
return;
diff --git a/src/MongoDB.Bson/Serialization/Conventions/StringObjectIdIdGeneratorConvention.cs b/src/MongoDB.Bson/Serialization/Conventions/StringObjectIdIdGeneratorConvention.cs
index 618d7213aec..0a8f48cf3db 100644
--- a/src/MongoDB.Bson/Serialization/Conventions/StringObjectIdIdGeneratorConvention.cs
+++ b/src/MongoDB.Bson/Serialization/Conventions/StringObjectIdIdGeneratorConvention.cs
@@ -14,7 +14,6 @@
*/
using MongoDB.Bson.Serialization.IdGenerators;
-using MongoDB.Bson.Serialization.Options;
using MongoDB.Bson.Serialization.Serializers;
namespace MongoDB.Bson.Serialization.Conventions
@@ -22,14 +21,17 @@ namespace MongoDB.Bson.Serialization.Conventions
///
/// A convention that sets the id generator for a string member with a BSON representation of ObjectId.
///
- public class StringObjectIdIdGeneratorConvention : ConventionBase, IPostProcessingConvention
+ public class StringObjectIdIdGeneratorConvention : ConventionBase, IPostProcessingConventionInternal
{
// public methods
///
/// Applies a post processing modification to the class map.
///
/// The class map.
- public void PostProcess(BsonClassMap classMap)
+ public void PostProcess(BsonClassMap classMap) => (this as IPostProcessingConventionInternal).PostProcess(classMap, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ void IPostProcessingConventionInternal.PostProcess(BsonClassMap classMap, IBsonSerializationDomain domain)
{
var idMemberMap = classMap.IdMemberMap;
if (idMemberMap != null)
diff --git a/src/MongoDB.Bson/Serialization/IBsonClassMapDomain.cs b/src/MongoDB.Bson/Serialization/IBsonClassMapDomain.cs
new file mode 100644
index 00000000000..6a0df68e291
--- /dev/null
+++ b/src/MongoDB.Bson/Serialization/IBsonClassMapDomain.cs
@@ -0,0 +1,96 @@
+/* Copyright 2010-present MongoDB Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace MongoDB.Bson.Serialization
+{
+ internal interface IBsonClassMapDomain
+ {
+ ///
+ /// Gets all registered class maps.
+ ///
+ /// All registered class maps.
+ IEnumerable GetRegisteredClassMaps();
+
+ ///
+ /// Checks whether a class map is registered for a type.
+ ///
+ /// The type to check.
+ /// True if there is a class map registered for the type.
+ bool IsClassMapRegistered(Type type);
+
+ ///
+ /// Looks up a class map (will AutoMap the class if no class map is registered).
+ ///
+ /// The class type.
+ /// The class map.
+ BsonClassMap LookupClassMap(Type classType);
+
+ ///
+ /// Creates and registers a class map.
+ ///
+ /// The class.
+ /// The class map.
+ BsonClassMap RegisterClassMap();
+
+ ///
+ /// Creates and registers a class map.
+ ///
+ /// The class.
+ /// The class map initializer.
+ /// The class map.
+ BsonClassMap RegisterClassMap(Action> classMapInitializer);
+
+ ///
+ /// Registers a class map.
+ ///
+ /// The class map.
+ void RegisterClassMap(BsonClassMap classMap);
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// True if this call registered the class map, false if the class map was already registered.
+ bool TryRegisterClassMap();
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// The class map.
+ /// True if this call registered the class map, false if the class map was already registered.
+ bool TryRegisterClassMap(BsonClassMap classMap);
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// The class map initializer (only called if the class map is not already registered).
+ /// True if this call registered the class map, false if the class map was already registered.
+ bool TryRegisterClassMap(Action> classMapInitializer);
+
+ ///
+ /// Registers a class map if it is not already registered.
+ ///
+ /// The class.
+ /// The class map factory (only called if the class map is not already registered).
+ /// True if this call registered the class map, false if the class map was already registered.
+ bool TryRegisterClassMap(Func> classMapFactory);
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/Serialization/IBsonIdProvider.cs b/src/MongoDB.Bson/Serialization/IBsonIdProvider.cs
index 6cb9ba4a811..d63d71a0c10 100644
--- a/src/MongoDB.Bson/Serialization/IBsonIdProvider.cs
+++ b/src/MongoDB.Bson/Serialization/IBsonIdProvider.cs
@@ -39,4 +39,9 @@ public interface IBsonIdProvider
/// The Id.
void SetDocumentId(object document, object id);
}
+
+ internal interface IBsonIdProviderInternal : IBsonIdProvider
+ {
+ bool GetDocumentId(object document, IBsonSerializationDomain serializationDomain, out object id, out Type idNominalType, out IIdGenerator idGenerator);
+ }
}
diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs b/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs
new file mode 100644
index 00000000000..34315129a4d
--- /dev/null
+++ b/src/MongoDB.Bson/Serialization/IBsonSerializationDomain.cs
@@ -0,0 +1,317 @@
+using System;
+using System.IO;
+using System.Threading;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization.Conventions;
+
+namespace MongoDB.Bson.Serialization
+{
+ ///
+ /// //TODO
+ ///
+ internal interface IBsonSerializationDomain
+ {
+ string Name { get; } //FP This is used for debugging purposes, but we could decide to make it public if needed.
+
+ ///
+ /// Returns whether the given type has any discriminators registered for any of its subclasses.
+ ///
+ /// A Type.
+ /// True if the type is discriminated.
+ bool IsTypeDiscriminated(Type type);
+
+ ///
+ /// Looks up the actual type of an object to be deserialized.
+ ///
+ /// The nominal type of the object.
+ /// The discriminator.
+ /// The actual type of the object.
+ Type LookupActualType(Type nominalType, BsonValue discriminator);
+
+ ///
+ /// Looks up the discriminator convention for a type.
+ ///
+ /// The type.
+ /// A discriminator convention.
+ IDiscriminatorConvention LookupDiscriminatorConvention(Type type);
+
+ ///
+ /// Looks up an IdGenerator.
+ ///
+ /// The Id type.
+ /// An IdGenerator for the Id type.
+ IIdGenerator LookupIdGenerator(Type type);
+
+ ///
+ /// Looks up a serializer for a Type.
+ ///
+ /// The type.
+ /// A serializer for type T.
+ IBsonSerializer LookupSerializer();
+
+ ///
+ /// Looks up a serializer for a Type.
+ ///
+ /// The Type.
+ /// A serializer for the Type.
+ IBsonSerializer LookupSerializer(Type type);
+
+ ///
+ /// Gets the serializer registry.
+ ///
+ IBsonSerializerRegistry SerializerRegistry { get; }
+
+ ///
+ /// Registers the discriminator for a type.
+ ///
+ /// The type.
+ /// The discriminator.
+ void RegisterDiscriminator(Type type, BsonValue discriminator);
+
+ ///
+ /// Registers the discriminator convention for a type.
+ ///
+ /// Type type.
+ /// The discriminator convention.
+ void RegisterDiscriminatorConvention(Type type, IDiscriminatorConvention convention);
+
+ ///
+ /// Registers a generic serializer definition for a generic type.
+ ///
+ /// The generic type.
+ /// The generic serializer definition.
+ void RegisterGenericSerializerDefinition(
+ Type genericTypeDefinition,
+ Type genericSerializerDefinition);
+
+ ///
+ /// Registers an IdGenerator for an Id Type.
+ ///
+ /// The Id Type.
+ /// The IdGenerator for the Id Type.
+ void RegisterIdGenerator(Type type, IIdGenerator idGenerator);
+
+ ///
+ /// Registers a serialization provider.
+ ///
+ /// The serialization provider.
+ void RegisterSerializationProvider(IBsonSerializationProvider provider);
+
+ ///
+ /// Registers a serializer for a type.
+ ///
+ /// The type.
+ /// The serializer.
+ void RegisterSerializer(IBsonSerializer serializer);
+
+ ///
+ /// Registers a serializer for a type.
+ ///
+ /// The type.
+ /// The serializer.
+ void RegisterSerializer(Type type, IBsonSerializer serializer);
+
+ ///
+ /// Tries to register a serializer for a type.
+ ///
+ /// The serializer.
+ /// The type.
+ /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.
+ bool TryRegisterSerializer(Type type, IBsonSerializer serializer);
+
+ ///
+ /// Tries to register a serializer for a type.
+ ///
+ /// The type.
+ /// The serializer.
+ /// True if the serializer was registered on this call, false if the same serializer was already registered on a previous call, throws an exception if a different serializer was already registered.
+ bool TryRegisterSerializer(IBsonSerializer serializer);
+
+ ///
+ /// Gets or sets whether to use the NullIdChecker on reference Id types that don't have an IdGenerator registered.
+ ///
+ bool UseNullIdChecker { get; set; }
+
+ ///
+ /// Gets or sets whether to use the ZeroIdChecker on value Id types that don't have an IdGenerator registered.
+ ///
+ bool UseZeroIdChecker { get; set; }
+
+ ///
+ /// Deserializes an object from a BsonDocument.
+ ///
+ /// The nominal type of the object.
+ /// The BsonDocument.
+ /// The configurator.
+ /// A deserialized value.
+ TNominalType Deserialize(BsonDocument document,
+ Action configurator = null);
+
+ ///
+ /// Deserializes a value.
+ ///
+ /// The nominal type of the object.
+ /// The BsonReader.
+ /// The configurator.
+ /// A deserialized value.
+ TNominalType Deserialize(IBsonReader bsonReader,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a BSON byte array.
+ ///
+ /// The nominal type of the object.
+ /// The BSON byte array.
+ /// The configurator.
+ /// A deserialized value.
+ TNominalType Deserialize(byte[] bytes,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a BSON Stream.
+ ///
+ /// The nominal type of the object.
+ /// The BSON Stream.
+ /// The configurator.
+ /// A deserialized value.
+ TNominalType Deserialize(Stream stream,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a JSON string.
+ ///
+ /// The nominal type of the object.
+ /// The JSON string.
+ /// The configurator.
+ /// A deserialized value.
+ TNominalType Deserialize(string json,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a JSON TextReader.
+ ///
+ /// The nominal type of the object.
+ /// The JSON TextReader.
+ /// The configurator.
+ /// A deserialized value.
+ TNominalType Deserialize(TextReader textReader,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a BsonDocument.
+ ///
+ /// The BsonDocument.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ object Deserialize(BsonDocument document, Type nominalType,
+ Action configurator = null);
+
+ ///
+ /// Deserializes a value.
+ ///
+ /// The BsonReader.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ object Deserialize(IBsonReader bsonReader, Type nominalType,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a BSON byte array.
+ ///
+ /// The BSON byte array.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ object Deserialize(byte[] bytes, Type nominalType,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a BSON Stream.
+ ///
+ /// The BSON Stream.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ object Deserialize(Stream stream, Type nominalType,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a JSON string.
+ ///
+ /// The JSON string.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ object Deserialize(string json, Type nominalType,
+ Action configurator = null);
+
+ ///
+ /// Deserializes an object from a JSON TextReader.
+ ///
+ /// The JSON TextReader.
+ /// The nominal type of the object.
+ /// The configurator.
+ /// A deserialized value.
+ object Deserialize(TextReader textReader, Type nominalType,
+ Action configurator = null);
+
+ ///
+ /// Serializes a value.
+ ///
+ /// The nominal type of the object.
+ /// The BsonWriter.
+ /// The object.
+ /// The serialization context configurator.
+ /// The serialization args.
+ void Serialize(
+ IBsonWriter bsonWriter,
+ TNominalType value,
+ Action configurator = null,
+ BsonSerializationArgs args = default(BsonSerializationArgs));
+
+ ///
+ /// Serializes a value.
+ ///
+ /// The BsonWriter.
+ /// The nominal type of the object.
+ /// The object.
+ /// The serialization context configurator.
+ /// The serialization args.
+ void Serialize(
+ IBsonWriter bsonWriter,
+ Type nominalType,
+ object value,
+ Action configurator = null,
+ BsonSerializationArgs args = default(BsonSerializationArgs));
+
+ ///
+ /// //TODO
+ ///
+ IBsonClassMapDomain BsonClassMap { get; }
+
+ ///
+ /// //TODO
+ ///
+ IConventionRegistryDomain ConventionRegistry { get; }
+
+ ///
+ /// //TODO
+ ///
+ IBsonDefaults BsonDefaults { get; }
+
+ //DOMAIN-API The following methods and properties were not public on BsonSerializer
+
+ void EnsureKnownTypesAreRegistered(Type nominalType);
+
+ BsonValue[] GetDiscriminatorsForTypeAndSubTypes(Type type);
+
+ IDiscriminatorConvention GetOrRegisterDiscriminatorConvention(Type type,
+ IDiscriminatorConvention discriminatorConvention);
+
+ bool IsDiscriminatorConventionRegisteredAtThisLevel(Type type);
+
+ ReaderWriterLockSlim ConfigLock { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs b/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs
index cdfca5d0676..6d1472eccea 100644
--- a/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs
+++ b/src/MongoDB.Bson/Serialization/IBsonSerializationProvider.cs
@@ -17,6 +17,7 @@
namespace MongoDB.Bson.Serialization
{
+ //DOMAIN-API We should remove this interface and merge it with IRegistryAwareBsonSerializationProvider.
///
/// An interface implemented by serialization providers.
///
@@ -48,4 +49,13 @@ public interface IRegistryAwareBsonSerializationProvider : IBsonSerializationPro
///
IBsonSerializer GetSerializer(Type type, IBsonSerializerRegistry serializerRegistry);
}
+
+ //DOMAIN-API We should use this interface the default one, and remove the previous two.
+ internal interface IDomainAwareBsonSerializationProvider : IRegistryAwareBsonSerializationProvider
+ {
+ IBsonSerializationDomain SerializationDomain { get; }
+
+ //FP Can't use just GetSerializer because it's already used by the base interface.
+ IBsonSerializer GetSerializerWithDomain(Type type);
+ }
}
diff --git a/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs b/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs
index fd5998c93b3..aa11d7bef91 100644
--- a/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs
+++ b/src/MongoDB.Bson/Serialization/IBsonSerializerExtensions.cs
@@ -13,7 +13,6 @@
* limitations under the License.
*/
-using System;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization.Conventions;
@@ -56,9 +55,18 @@ public static TValue Deserialize(this IBsonSerializer serializer
/// The serializer.
/// The discriminator convention.
public static IDiscriminatorConvention GetDiscriminatorConvention(this IBsonSerializer serializer) =>
+ GetDiscriminatorConvention(serializer, BsonSerializer.DefaultSerializationDomain);
+
+ ///
+ /// //TODO
+ ///
+ ///
+ ///
+ ///
+ internal static IDiscriminatorConvention GetDiscriminatorConvention(this IBsonSerializer serializer, IBsonSerializationDomain serializationDomain) =>
serializer is IHasDiscriminatorConvention hasDiscriminatorConvention
? hasDiscriminatorConvention.DiscriminatorConvention
- : BsonSerializer.LookupDiscriminatorConvention(serializer.ValueType);
+ : serializationDomain.LookupDiscriminatorConvention(serializer.ValueType);
///
/// Serializes a value.
@@ -96,7 +104,8 @@ public static BsonValue ToBsonValue(this IBsonSerializer serializer, object valu
var document = new BsonDocument();
using (var writer = new BsonDocumentWriter(document))
{
- var context = BsonSerializationContext.CreateRoot(writer);
+ //QUESTION Is it correct we only need a default domain here?
+ var context = BsonSerializationContext.CreateRoot(writer, BsonSerializer.DefaultSerializationDomain);
writer.WriteStartDocument();
writer.WriteName("x");
serializer.Serialize(context, value);
@@ -117,7 +126,8 @@ public static BsonValue ToBsonValue(this IBsonSerializer seriali
var document = new BsonDocument();
using (var writer = new BsonDocumentWriter(document))
{
- var context = BsonSerializationContext.CreateRoot(writer);
+ //QUESTION Is it correct we only need a default domain here?
+ var context = BsonSerializationContext.CreateRoot(writer, BsonSerializer.DefaultSerializationDomain);
writer.WriteStartDocument();
writer.WriteName("x");
serializer.Serialize(context, value);
diff --git a/src/MongoDB.Bson/Serialization/IIdGenerator.cs b/src/MongoDB.Bson/Serialization/IIdGenerator.cs
index 5361038d9e3..2ff3c57d46c 100644
--- a/src/MongoDB.Bson/Serialization/IIdGenerator.cs
+++ b/src/MongoDB.Bson/Serialization/IIdGenerator.cs
@@ -27,6 +27,7 @@ public interface IIdGenerator
/// The document.
/// An Id.
object GenerateId(object container, object document);
+
///
/// Tests whether an Id is empty.
///
diff --git a/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs
index fdcd59916ed..74d37b0069d 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/BsonClassMapSerializer.cs
@@ -58,7 +58,7 @@ public BsonClassMapSerializer(BsonClassMap classMap)
// public properties
///
- public IDiscriminatorConvention DiscriminatorConvention => _classMap.GetDiscriminatorConvention();
+ public IDiscriminatorConvention DiscriminatorConvention => _classMap.GetDiscriminatorConvention(); //TODO This should be removed, because we need to have the serialization domain.
///
/// Gets a value indicating whether this serializer's discriminator is compatible with the object serializer.
@@ -88,15 +88,16 @@ public override TClass Deserialize(BsonDeserializationContext context, BsonDeser
return default(TClass);
}
- var discriminatorConvention = _classMap.GetDiscriminatorConvention();
+ var discriminatorConvention = _classMap.GetDiscriminatorConvention(context.SerializationDomain);
+
+ var actualType = discriminatorConvention.GetActualTypeInternal(bsonReader, args.NominalType, context.SerializationDomain);
- var actualType = discriminatorConvention.GetActualType(bsonReader, args.NominalType);
if (actualType == typeof(TClass))
{
return DeserializeClass(context);
}
- var serializer = BsonSerializer.LookupSerializer(actualType);
+ var serializer = context.SerializationDomain.LookupSerializer(actualType);
return (TClass)serializer.Deserialize(context);
}
@@ -146,7 +147,7 @@ public TClass DeserializeClass(BsonDeserializationContext context)
}
}
- var discriminatorConvention = _classMap.GetDiscriminatorConvention();
+ var discriminatorConvention = _classMap.GetDiscriminatorConvention(context.SerializationDomain);
var allMemberMaps = _classMap.AllMemberMaps;
var extraElementsMemberMapIndex = _classMap.ExtraElementsMemberMapIndex;
var memberMapBitArray = FastMemberMapHelper.GetBitArray(allMemberMaps.Count);
@@ -326,6 +327,10 @@ public bool GetDocumentId(
out object id,
out Type idNominalType,
out IIdGenerator idGenerator)
+ => GetDocumentId(document, BsonSerializer.DefaultSerializationDomain, out id, out idNominalType, out idGenerator);
+
+ internal bool GetDocumentId(object document, IBsonSerializationDomain serializationDomain, out object id, out Type idNominalType,
+ out IIdGenerator idGenerator)
{
var idMemberMap = _classMap.IdMemberMap;
if (idMemberMap != null)
@@ -392,7 +397,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati
return;
}
- var serializer = BsonSerializer.LookupSerializer(actualType);
+ var serializer = context.SerializationDomain.LookupSerializer(actualType);
serializer.Serialize(context, args, value);
}
@@ -566,7 +571,7 @@ private object DeserializeMemberValue(BsonDeserializationContext context, BsonMe
{
try
{
- return memberMap.GetSerializer().Deserialize(context);
+ return memberMap.GetSerializer(context.SerializationDomain).Deserialize(context);
}
catch (Exception ex)
{
@@ -637,11 +642,12 @@ private void SerializeExtraElements(BsonSerializationContext context, object obj
private void SerializeDiscriminator(BsonSerializationContext context, Type nominalType, object obj)
{
- var discriminatorConvention = _classMap.GetDiscriminatorConvention();
+ var discriminatorConvention = _classMap.GetDiscriminatorConvention(context.SerializationDomain);
if (discriminatorConvention != null)
{
var actualType = obj.GetType();
- var discriminator = discriminatorConvention.GetDiscriminator(nominalType, actualType);
+ var discriminator = discriminatorConvention.GetDiscriminatorInternal(nominalType, actualType, context.SerializationDomain);
+
if (discriminator != null)
{
context.Writer.WriteName(discriminatorConvention.ElementName);
@@ -684,7 +690,7 @@ private void SerializeNormalMember(BsonSerializationContext context, object obj,
}
bsonWriter.WriteName(memberMap.ElementName);
- memberMap.GetSerializer().Serialize(context, value);
+ memberMap.GetSerializer(context.SerializationDomain).Serialize(context, value);
}
private bool ShouldSerializeDiscriminator(Type nominalType)
diff --git a/src/MongoDB.Bson/Serialization/Serializers/BsonDocumentSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/BsonDocumentSerializer.cs
index 2ba62a8294c..a3e7417ee06 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/BsonDocumentSerializer.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/BsonDocumentSerializer.cs
@@ -81,6 +81,10 @@ public bool GetDocumentId(
object document,
out object id,
out Type idNominalType,
+ out IIdGenerator idGenerator) => GetDocumentId(document, BsonSerializer.DefaultSerializationDomain, out id,
+ out idNominalType, out idGenerator);
+
+ internal bool GetDocumentId(object document, IBsonSerializationDomain serializationDomain, out object id, out Type idNominalType,
out IIdGenerator idGenerator)
{
var bsonDocument = (BsonDocument)document;
@@ -89,7 +93,7 @@ public bool GetDocumentId(
if (bsonDocument.TryGetValue("_id", out idBsonValue))
{
id = idBsonValue;
- idGenerator = BsonSerializer.LookupIdGenerator(id.GetType());
+ idGenerator = serializationDomain.LookupIdGenerator(id.GetType());
if (idGenerator == null)
{
diff --git a/src/MongoDB.Bson/Serialization/Serializers/BsonValueSerializerBase.cs b/src/MongoDB.Bson/Serialization/Serializers/BsonValueSerializerBase.cs
index e3a5776870c..0f636ae834b 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/BsonValueSerializerBase.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/BsonValueSerializerBase.cs
@@ -70,7 +70,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati
var actualType = value.GetType();
if (actualType != ValueType && !args.SerializeAsNominalType)
{
- var serializer = BsonSerializer.LookupSerializer(actualType);
+ var serializer = context.SerializationDomain.LookupSerializer(actualType);
serializer.Serialize(context, value);
return;
}
diff --git a/src/MongoDB.Bson/Serialization/Serializers/ClassSerializerBase.cs b/src/MongoDB.Bson/Serialization/Serializers/ClassSerializerBase.cs
index 07723b9cddb..f21cd498ddf 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/ClassSerializerBase.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/ClassSerializerBase.cs
@@ -47,7 +47,7 @@ public override TValue Deserialize(BsonDeserializationContext context, BsonDeser
}
else
{
- var serializer = BsonSerializer.LookupSerializer(actualType);
+ var serializer = context.SerializationDomain.LookupSerializer(actualType);
return (TValue)serializer.Deserialize(context, args);
}
}
@@ -75,7 +75,7 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati
}
else
{
- var serializer = BsonSerializer.LookupSerializer(actualType);
+ var serializer = context.SerializationDomain.LookupSerializer(actualType);
serializer.Serialize(context, value);
}
}
@@ -100,8 +100,8 @@ protected virtual TValue DeserializeValue(BsonDeserializationContext context, Bs
/// The actual type.
protected virtual Type GetActualType(BsonDeserializationContext context)
{
- var discriminatorConvention = this.GetDiscriminatorConvention();
- return discriminatorConvention.GetActualType(context.Reader, typeof(TValue));
+ var discriminatorConvention = this.GetDiscriminatorConvention(context.SerializationDomain);
+ return discriminatorConvention.GetActualTypeInternal(context.Reader, typeof(TValue), context.SerializationDomain);
}
///
diff --git a/src/MongoDB.Bson/Serialization/Serializers/DictionaryInterfaceImplementerSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/DictionaryInterfaceImplementerSerializer.cs
index 59e6cb42365..e1c60e22b3f 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/DictionaryInterfaceImplementerSerializer.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/DictionaryInterfaceImplementerSerializer.cs
@@ -31,6 +31,7 @@ public sealed class DictionaryInterfaceImplementerSerializer :
IDictionaryRepresentationConfigurable
where TDictionary : class, IDictionary, new()
{
+ //DOMAIN-API This version should be removed in the future.
///
/// Initializes a new instance of the class.
///
@@ -38,6 +39,7 @@ public DictionaryInterfaceImplementerSerializer()
{
}
+ //DOMAIN-API This version should be removed in the future.
///
/// Initializes a new instance of the class.
///
diff --git a/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs b/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs
index 96b708d8aa6..da4be08eae8 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/DictionarySerializerBase.cs
@@ -45,6 +45,7 @@ private static class Flags
private readonly IBsonSerializer _valueSerializer;
// constructors
+ //DOMAIN-API This version should be removed in the future.
///
/// Initializes a new instance of the class.
///
@@ -53,6 +54,7 @@ public DictionarySerializerBase()
{
}
+ //DOMAIN-API This version should be removed in the future.
///
/// Initializes a new instance of the class.
///
@@ -273,7 +275,8 @@ private object DeserializeKeyString(string keyString)
var keyDocument = new BsonDocument("k", keyString);
using (var keyReader = new BsonDocumentReader(keyDocument))
{
- var context = BsonDeserializationContext.CreateRoot(keyReader);
+ //QUESTION Is it correct we only need a default domain here?
+ var context = BsonDeserializationContext.CreateRoot(keyReader, BsonSerializer.DefaultSerializationDomain);
keyReader.ReadStartDocument();
keyReader.ReadName("k");
var key = _keySerializer.Deserialize(context);
@@ -329,7 +332,8 @@ private string SerializeKeyString(object key)
var keyDocument = new BsonDocument();
using (var keyWriter = new BsonDocumentWriter(keyDocument))
{
- var context = BsonSerializationContext.CreateRoot(keyWriter);
+ //QUESTION Is it correct we only need a default domain here?
+ var context = BsonSerializationContext.CreateRoot(keyWriter, BsonSerializer.DefaultSerializationDomain);
keyWriter.WriteStartDocument();
keyWriter.WriteName("k");
_keySerializer.Serialize(context, key);
@@ -373,6 +377,7 @@ private static class Flags
private readonly Lazy> _lazyValueSerializer;
// constructors
+ //DOMAIN-API This version should be removed in the future.
///
/// Initializes a new instance of the class.
///
@@ -381,6 +386,8 @@ public DictionarySerializerBase()
{
}
+ //DOMAIN-API This version should be removed in the future.
+ //FP Fortunately it seems that all the constructors that should not be used are actually not used in the codebase.
///
/// Initializes a new instance of the class.
///
@@ -676,7 +683,8 @@ private TKey DeserializeKeyString(string keyString)
var keyDocument = new BsonDocument("k", keyString);
using (var keyReader = new BsonDocumentReader(keyDocument))
{
- var context = BsonDeserializationContext.CreateRoot(keyReader);
+ //QUESTION Is it correct we only need a default domain here?
+ var context = BsonDeserializationContext.CreateRoot(keyReader, BsonSerializer.DefaultSerializationDomain);
keyReader.ReadStartDocument();
keyReader.ReadName("k");
var key = _lazyKeySerializer.Value.Deserialize(context);
@@ -732,7 +740,8 @@ private string SerializeKeyString(TKey key)
var keyDocument = new BsonDocument();
using (var keyWriter = new BsonDocumentWriter(keyDocument))
{
- var context = BsonSerializationContext.CreateRoot(keyWriter);
+ //QUESTION Is it correct we only need a default domain here?
+ var context = BsonSerializationContext.CreateRoot(keyWriter, BsonSerializer.DefaultSerializationDomain);
keyWriter.WriteStartDocument();
keyWriter.WriteName("k");
_lazyKeySerializer.Value.Serialize(context, key);
diff --git a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs
index eb0035489e0..36719d18b57 100644
--- a/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs
+++ b/src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs
@@ -41,14 +41,14 @@ public sealed class DiscriminatedInterfaceSerializer :
// where TInterface is an interface
{
#region static
- private static IBsonSerializer CreateInterfaceSerializer()
+ private static IBsonSerializer CreateInterfaceSerializer(IBsonSerializationDomain serializationDomain)
{
var classMapDefinition = typeof(BsonClassMap<>);
var classMapType = classMapDefinition.MakeGenericType(typeof(TInterface));
var classMap = (BsonClassMap)Activator.CreateInstance(classMapType);
classMap.AutoMap();
- classMap.SetDiscriminatorConvention(BsonSerializer.LookupDiscriminatorConvention(typeof(TInterface)));
- classMap.Freeze();
+ classMap.SetDiscriminatorConvention(serializationDomain.LookupDiscriminatorConvention(typeof(TInterface)));
+ classMap.Freeze(serializationDomain);
return new BsonClassMapSerializer(classMap);
}
#endregion
@@ -75,7 +75,7 @@ public DiscriminatedInterfaceSerializer()
/// interfaceType
/// interfaceType
public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorConvention)
- : this(discriminatorConvention, CreateInterfaceSerializer(), objectSerializer: null)
+ : this(discriminatorConvention, CreateInterfaceSerializer(BsonSerializer.DefaultSerializationDomain), objectSerializer: null) //TODO Is this ok?
{
}
@@ -109,12 +109,12 @@ public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorCo
}
_interfaceType = typeof(TInterface);
- _discriminatorConvention = discriminatorConvention ?? interfaceSerializer.GetDiscriminatorConvention();
+ _discriminatorConvention = discriminatorConvention ?? interfaceSerializer.GetDiscriminatorConvention(); //QUESTION What do we do here? We don't have the domain close by, should we lazy initialize it during serialization/deserialization?
_interfaceSerializer = interfaceSerializer;
if (objectSerializer == null)
{
- objectSerializer = BsonSerializer.LookupSerializer