BsonSerializer.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. /* Copyright 2010-2016 MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.Collections.Generic;
  17. using System.IO;
  18. using System.Linq;
  19. using System.Reflection;
  20. using System.Threading;
  21. // don't add using statement for MongoDB.Bson.Serialization.Serializers to minimize dependencies on DefaultSerializer
  22. using MongoDB.Bson.IO;
  23. using MongoDB.Bson.Serialization.Attributes;
  24. using MongoDB.Bson.Serialization.Conventions;
  25. using MongoDB.Bson.Serialization.IdGenerators;
  26. using MongoDB.Bson.Serialization.Serializers;
  27. namespace MongoDB.Bson.Serialization
  28. {
  29. /// <summary>
  30. /// A static class that represents the BSON serialization functionality.
  31. /// </summary>
  32. public static class BsonSerializer
  33. {
  34. // private static fields
  35. private static ReaderWriterLockSlim __configLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
  36. private static Dictionary<Type, IIdGenerator> __idGenerators = new Dictionary<Type, IIdGenerator>();
  37. private static Dictionary<Type, IDiscriminatorConvention> __discriminatorConventions = new Dictionary<Type, IDiscriminatorConvention>();
  38. private static Dictionary<BsonValue, HashSet<Type>> __discriminators = new Dictionary<BsonValue, HashSet<Type>>();
  39. private static HashSet<Type> __discriminatedTypes = new HashSet<Type>();
  40. private static BsonSerializerRegistry __serializerRegistry;
  41. private static TypeMappingSerializationProvider __typeMappingSerializationProvider;
  42. private static HashSet<Type> __typesWithRegisteredKnownTypes = new HashSet<Type>();
  43. private static bool __useNullIdChecker = false;
  44. private static bool __useZeroIdChecker = false;
  45. // static constructor
  46. static BsonSerializer()
  47. {
  48. CreateSerializerRegistry();
  49. RegisterIdGenerators();
  50. }
  51. // public static properties
  52. /// <summary>
  53. /// Gets the serializer registry.
  54. /// </summary>
  55. public static IBsonSerializerRegistry SerializerRegistry
  56. {
  57. get { return __serializerRegistry; }
  58. }
  59. /// <summary>
  60. /// Gets or sets whether to use the NullIdChecker on reference Id types that don't have an IdGenerator registered.
  61. /// </summary>
  62. public static bool UseNullIdChecker
  63. {
  64. get { return __useNullIdChecker; }
  65. set { __useNullIdChecker = value; }
  66. }
  67. /// <summary>
  68. /// Gets or sets whether to use the ZeroIdChecker on value Id types that don't have an IdGenerator registered.
  69. /// </summary>
  70. public static bool UseZeroIdChecker
  71. {
  72. get { return __useZeroIdChecker; }
  73. set { __useZeroIdChecker = value; }
  74. }
  75. // internal static properties
  76. internal static ReaderWriterLockSlim ConfigLock
  77. {
  78. get { return __configLock; }
  79. }
  80. // public static methods
  81. /// <summary>
  82. /// Deserializes an object from a BsonDocument.
  83. /// </summary>
  84. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  85. /// <param name="document">The BsonDocument.</param>
  86. /// <param name="configurator">The configurator.</param>
  87. /// <returns>A deserialized value.</returns>
  88. public static TNominalType Deserialize<TNominalType>(BsonDocument document, Action<BsonDeserializationContext.Builder> configurator = null)
  89. {
  90. using (var bsonReader = new BsonDocumentReader(document))
  91. {
  92. return Deserialize<TNominalType>(bsonReader, configurator);
  93. }
  94. }
  95. /// <summary>
  96. /// Deserializes a value.
  97. /// </summary>
  98. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  99. /// <param name="bsonReader">The BsonReader.</param>
  100. /// <param name="configurator">The configurator.</param>
  101. /// <returns>A deserialized value.</returns>
  102. public static TNominalType Deserialize<TNominalType>(IBsonReader bsonReader, Action<BsonDeserializationContext.Builder> configurator = null)
  103. {
  104. var serializer = LookupSerializer<TNominalType>();
  105. var context = BsonDeserializationContext.CreateRoot(bsonReader, configurator);
  106. return serializer.Deserialize(context);
  107. }
  108. /// <summary>
  109. /// Deserializes an object from a BSON byte array.
  110. /// </summary>
  111. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  112. /// <param name="bytes">The BSON byte array.</param>
  113. /// <param name="configurator">The configurator.</param>
  114. /// <returns>A deserialized value.</returns>
  115. public static TNominalType Deserialize<TNominalType>(byte[] bytes, Action<BsonDeserializationContext.Builder> configurator = null)
  116. {
  117. using (var buffer = new ByteArrayBuffer(bytes, isReadOnly: true))
  118. using (var stream = new ByteBufferStream(buffer))
  119. {
  120. return Deserialize<TNominalType>(stream, configurator);
  121. }
  122. }
  123. /// <summary>
  124. /// Deserializes an object from a BSON Stream.
  125. /// </summary>
  126. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  127. /// <param name="stream">The BSON Stream.</param>
  128. /// <param name="configurator">The configurator.</param>
  129. /// <returns>A deserialized value.</returns>
  130. public static TNominalType Deserialize<TNominalType>(Stream stream, Action<BsonDeserializationContext.Builder> configurator = null)
  131. {
  132. using (var bsonReader = new BsonBinaryReader(stream))
  133. {
  134. return Deserialize<TNominalType>(bsonReader, configurator);
  135. }
  136. }
  137. /// <summary>
  138. /// Deserializes an object from a JSON string.
  139. /// </summary>
  140. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  141. /// <param name="json">The JSON string.</param>
  142. /// <param name="configurator">The configurator.</param>
  143. /// <returns>A deserialized value.</returns>
  144. public static TNominalType Deserialize<TNominalType>(string json, Action<BsonDeserializationContext.Builder> configurator = null)
  145. {
  146. using (var bsonReader = new JsonReader(json))
  147. {
  148. return Deserialize<TNominalType>(bsonReader, configurator);
  149. }
  150. }
  151. /// <summary>
  152. /// Deserializes an object from a JSON TextReader.
  153. /// </summary>
  154. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  155. /// <param name="textReader">The JSON TextReader.</param>
  156. /// <param name="configurator">The configurator.</param>
  157. /// <returns>A deserialized value.</returns>
  158. public static TNominalType Deserialize<TNominalType>(TextReader textReader, Action<BsonDeserializationContext.Builder> configurator = null)
  159. {
  160. using (var bsonReader = new JsonReader(textReader))
  161. {
  162. return Deserialize<TNominalType>(bsonReader, configurator);
  163. }
  164. }
  165. /// <summary>
  166. /// Deserializes an object from a BsonDocument.
  167. /// </summary>
  168. /// <param name="document">The BsonDocument.</param>
  169. /// <param name="nominalType">The nominal type of the object.</param>
  170. /// <param name="configurator">The configurator.</param>
  171. /// <returns>A deserialized value.</returns>
  172. public static object Deserialize(BsonDocument document, Type nominalType, Action<BsonDeserializationContext.Builder> configurator = null)
  173. {
  174. using (var bsonReader = new BsonDocumentReader(document))
  175. {
  176. return Deserialize(bsonReader, nominalType, configurator);
  177. }
  178. }
  179. /// <summary>
  180. /// Deserializes a value.
  181. /// </summary>
  182. /// <param name="bsonReader">The BsonReader.</param>
  183. /// <param name="nominalType">The nominal type of the object.</param>
  184. /// <param name="configurator">The configurator.</param>
  185. /// <returns>A deserialized value.</returns>
  186. public static object Deserialize(IBsonReader bsonReader, Type nominalType, Action<BsonDeserializationContext.Builder> configurator = null)
  187. {
  188. var serializer = LookupSerializer(nominalType);
  189. var context = BsonDeserializationContext.CreateRoot(bsonReader, configurator);
  190. return serializer.Deserialize(context);
  191. }
  192. /// <summary>
  193. /// Deserializes an object from a BSON byte array.
  194. /// </summary>
  195. /// <param name="bytes">The BSON byte array.</param>
  196. /// <param name="nominalType">The nominal type of the object.</param>
  197. /// <param name="configurator">The configurator.</param>
  198. /// <returns>A deserialized value.</returns>
  199. public static object Deserialize(byte[] bytes, Type nominalType, Action<BsonDeserializationContext.Builder> configurator = null)
  200. {
  201. using (var buffer = new ByteArrayBuffer(bytes, isReadOnly: true))
  202. using (var stream = new ByteBufferStream(buffer))
  203. {
  204. return Deserialize(stream, nominalType, configurator);
  205. }
  206. }
  207. /// <summary>
  208. /// Deserializes an object from a BSON Stream.
  209. /// </summary>
  210. /// <param name="stream">The BSON Stream.</param>
  211. /// <param name="nominalType">The nominal type of the object.</param>
  212. /// <param name="configurator">The configurator.</param>
  213. /// <returns>A deserialized value.</returns>
  214. public static object Deserialize(Stream stream, Type nominalType, Action<BsonDeserializationContext.Builder> configurator = null)
  215. {
  216. using (var bsonReader = new BsonBinaryReader(stream))
  217. {
  218. return Deserialize(bsonReader, nominalType, configurator);
  219. }
  220. }
  221. /// <summary>
  222. /// Deserializes an object from a JSON string.
  223. /// </summary>
  224. /// <param name="json">The JSON string.</param>
  225. /// <param name="nominalType">The nominal type of the object.</param>
  226. /// <param name="configurator">The configurator.</param>
  227. /// <returns>A deserialized value.</returns>
  228. public static object Deserialize(string json, Type nominalType, Action<BsonDeserializationContext.Builder> configurator = null)
  229. {
  230. using (var bsonReader = new JsonReader(json))
  231. {
  232. return Deserialize(bsonReader, nominalType, configurator);
  233. }
  234. }
  235. /// <summary>
  236. /// Deserializes an object from a JSON TextReader.
  237. /// </summary>
  238. /// <param name="textReader">The JSON TextReader.</param>
  239. /// <param name="nominalType">The nominal type of the object.</param>
  240. /// <param name="configurator">The configurator.</param>
  241. /// <returns>A deserialized value.</returns>
  242. public static object Deserialize(TextReader textReader, Type nominalType, Action<BsonDeserializationContext.Builder> configurator = null)
  243. {
  244. using (var bsonReader = new JsonReader(textReader))
  245. {
  246. return Deserialize(bsonReader, nominalType, configurator);
  247. }
  248. }
  249. /// <summary>
  250. /// Returns whether the given type has any discriminators registered for any of its subclasses.
  251. /// </summary>
  252. /// <param name="type">A Type.</param>
  253. /// <returns>True if the type is discriminated.</returns>
  254. public static bool IsTypeDiscriminated(Type type)
  255. {
  256. var typeInfo = type.GetTypeInfo();
  257. return typeInfo.IsInterface || __discriminatedTypes.Contains(type);
  258. }
  259. /// <summary>
  260. /// Looks up the actual type of an object to be deserialized.
  261. /// </summary>
  262. /// <param name="nominalType">The nominal type of the object.</param>
  263. /// <param name="discriminator">The discriminator.</param>
  264. /// <returns>The actual type of the object.</returns>
  265. public static Type LookupActualType(Type nominalType, BsonValue discriminator)
  266. {
  267. if (discriminator == null)
  268. {
  269. return nominalType;
  270. }
  271. // note: EnsureKnownTypesAreRegistered handles its own locking so call from outside any lock
  272. EnsureKnownTypesAreRegistered(nominalType);
  273. __configLock.EnterReadLock();
  274. try
  275. {
  276. Type actualType = null;
  277. HashSet<Type> hashSet;
  278. if (__discriminators.TryGetValue(discriminator, out hashSet))
  279. {
  280. foreach (var type in hashSet)
  281. {
  282. if (nominalType.GetTypeInfo().IsAssignableFrom(type))
  283. {
  284. if (actualType == null)
  285. {
  286. actualType = type;
  287. }
  288. else
  289. {
  290. string message = string.Format("Ambiguous discriminator '{0}'.", discriminator);
  291. throw new BsonSerializationException(message);
  292. }
  293. }
  294. }
  295. }
  296. if (actualType == null && discriminator.IsString)
  297. {
  298. actualType = TypeNameDiscriminator.GetActualType(discriminator.AsString); // see if it's a Type name
  299. }
  300. if (actualType == null)
  301. {
  302. string message = string.Format("Unknown discriminator value '{0}'.", discriminator);
  303. throw new BsonSerializationException(message);
  304. }
  305. if (!nominalType.GetTypeInfo().IsAssignableFrom(actualType))
  306. {
  307. string message = string.Format(
  308. "Actual type {0} is not assignable to expected type {1}.",
  309. actualType.FullName, nominalType.FullName);
  310. throw new BsonSerializationException(message);
  311. }
  312. return actualType;
  313. }
  314. finally
  315. {
  316. __configLock.ExitReadLock();
  317. }
  318. }
  319. /// <summary>
  320. /// Looks up the discriminator convention for a type.
  321. /// </summary>
  322. /// <param name="type">The type.</param>
  323. /// <returns>A discriminator convention.</returns>
  324. public static IDiscriminatorConvention LookupDiscriminatorConvention(Type type)
  325. {
  326. var typeInfo = type.GetTypeInfo();
  327. __configLock.EnterReadLock();
  328. try
  329. {
  330. IDiscriminatorConvention convention;
  331. if (__discriminatorConventions.TryGetValue(type, out convention))
  332. {
  333. return convention;
  334. }
  335. }
  336. finally
  337. {
  338. __configLock.ExitReadLock();
  339. }
  340. __configLock.EnterWriteLock();
  341. try
  342. {
  343. IDiscriminatorConvention convention;
  344. if (!__discriminatorConventions.TryGetValue(type, out convention))
  345. {
  346. if (type == typeof(object))
  347. {
  348. // if there is no convention registered for object register the default one
  349. convention = new ObjectDiscriminatorConvention("_t");
  350. RegisterDiscriminatorConvention(typeof(object), convention);
  351. }
  352. else if (typeInfo.IsInterface)
  353. {
  354. // TODO: should convention for interfaces be inherited from parent interfaces?
  355. convention = LookupDiscriminatorConvention(typeof(object));
  356. RegisterDiscriminatorConvention(type, convention);
  357. }
  358. else
  359. {
  360. // inherit the discriminator convention from the closest parent (that isn't object) that has one
  361. // otherwise default to the standard hierarchical convention
  362. Type parentType = type.GetTypeInfo().BaseType;
  363. while (convention == null)
  364. {
  365. if (parentType == typeof(object))
  366. {
  367. convention = StandardDiscriminatorConvention.Hierarchical;
  368. break;
  369. }
  370. if (__discriminatorConventions.TryGetValue(parentType, out convention))
  371. {
  372. break;
  373. }
  374. parentType = parentType.GetTypeInfo().BaseType;
  375. }
  376. // register this convention for all types between this and the parent type where we found the convention
  377. var unregisteredType = type;
  378. while (unregisteredType != parentType)
  379. {
  380. RegisterDiscriminatorConvention(unregisteredType, convention);
  381. unregisteredType = unregisteredType.GetTypeInfo().BaseType;
  382. }
  383. }
  384. }
  385. return convention;
  386. }
  387. finally
  388. {
  389. __configLock.ExitWriteLock();
  390. }
  391. }
  392. /// <summary>
  393. /// Looks up an IdGenerator.
  394. /// </summary>
  395. /// <param name="type">The Id type.</param>
  396. /// <returns>An IdGenerator for the Id type.</returns>
  397. public static IIdGenerator LookupIdGenerator(Type type)
  398. {
  399. var typeInfo = type.GetTypeInfo();
  400. __configLock.EnterReadLock();
  401. try
  402. {
  403. IIdGenerator idGenerator;
  404. if (__idGenerators.TryGetValue(type, out idGenerator))
  405. {
  406. return idGenerator;
  407. }
  408. }
  409. finally
  410. {
  411. __configLock.ExitReadLock();
  412. }
  413. __configLock.EnterWriteLock();
  414. try
  415. {
  416. IIdGenerator idGenerator;
  417. if (!__idGenerators.TryGetValue(type, out idGenerator))
  418. {
  419. if (typeInfo.IsValueType && __useZeroIdChecker)
  420. {
  421. var iEquatableDefinition = typeof(IEquatable<>);
  422. var iEquatableType = iEquatableDefinition.MakeGenericType(type);
  423. if (iEquatableType.GetTypeInfo().IsAssignableFrom(type))
  424. {
  425. var zeroIdCheckerDefinition = typeof(ZeroIdChecker<>);
  426. var zeroIdCheckerType = zeroIdCheckerDefinition.MakeGenericType(type);
  427. idGenerator = (IIdGenerator)Activator.CreateInstance(zeroIdCheckerType);
  428. }
  429. }
  430. else if (__useNullIdChecker)
  431. {
  432. idGenerator = NullIdChecker.Instance;
  433. }
  434. else
  435. {
  436. idGenerator = null;
  437. }
  438. __idGenerators[type] = idGenerator; // remember it even if it's null
  439. }
  440. return idGenerator;
  441. }
  442. finally
  443. {
  444. __configLock.ExitWriteLock();
  445. }
  446. }
  447. /// <summary>
  448. /// Looks up a serializer for a Type.
  449. /// </summary>
  450. /// <typeparam name="T">The type.</typeparam>
  451. /// <returns>A serializer for type T.</returns>
  452. public static IBsonSerializer<T> LookupSerializer<T>()
  453. {
  454. return (IBsonSerializer<T>)LookupSerializer(typeof(T));
  455. }
  456. /// <summary>
  457. /// Looks up a serializer for a Type.
  458. /// </summary>
  459. /// <param name="type">The Type.</param>
  460. /// <returns>A serializer for the Type.</returns>
  461. public static IBsonSerializer LookupSerializer(Type type)
  462. {
  463. return __serializerRegistry.GetSerializer(type);
  464. }
  465. /// <summary>
  466. /// Registers the discriminator for a type.
  467. /// </summary>
  468. /// <param name="type">The type.</param>
  469. /// <param name="discriminator">The discriminator.</param>
  470. public static void RegisterDiscriminator(Type type, BsonValue discriminator)
  471. {
  472. var typeInfo = type.GetTypeInfo();
  473. if (typeInfo.IsInterface)
  474. {
  475. var message = string.Format("Discriminators can only be registered for classes, not for interface {0}.", type.FullName);
  476. throw new BsonSerializationException(message);
  477. }
  478. __configLock.EnterWriteLock();
  479. try
  480. {
  481. HashSet<Type> hashSet;
  482. if (!__discriminators.TryGetValue(discriminator, out hashSet))
  483. {
  484. hashSet = new HashSet<Type>();
  485. __discriminators.Add(discriminator, hashSet);
  486. }
  487. if (!hashSet.Contains(type))
  488. {
  489. hashSet.Add(type);
  490. // mark all base types as discriminated (so we know that it's worth reading a discriminator)
  491. for (var baseType = type.GetTypeInfo().BaseType; baseType != null; baseType = baseType.GetTypeInfo().BaseType)
  492. {
  493. __discriminatedTypes.Add(baseType);
  494. }
  495. }
  496. }
  497. finally
  498. {
  499. __configLock.ExitWriteLock();
  500. }
  501. }
  502. /// <summary>
  503. /// Registers the discriminator convention for a type.
  504. /// </summary>
  505. /// <param name="type">Type type.</param>
  506. /// <param name="convention">The discriminator convention.</param>
  507. public static void RegisterDiscriminatorConvention(Type type, IDiscriminatorConvention convention)
  508. {
  509. __configLock.EnterWriteLock();
  510. try
  511. {
  512. if (!__discriminatorConventions.ContainsKey(type))
  513. {
  514. __discriminatorConventions.Add(type, convention);
  515. }
  516. else
  517. {
  518. var message = string.Format("There is already a discriminator convention registered for type {0}.", type.FullName);
  519. throw new BsonSerializationException(message);
  520. }
  521. }
  522. finally
  523. {
  524. __configLock.ExitWriteLock();
  525. }
  526. }
  527. /// <summary>
  528. /// Registers a generic serializer definition for a generic type.
  529. /// </summary>
  530. /// <param name="genericTypeDefinition">The generic type.</param>
  531. /// <param name="genericSerializerDefinition">The generic serializer definition.</param>
  532. public static void RegisterGenericSerializerDefinition(
  533. Type genericTypeDefinition,
  534. Type genericSerializerDefinition)
  535. {
  536. __typeMappingSerializationProvider.RegisterMapping(genericTypeDefinition, genericSerializerDefinition);
  537. }
  538. /// <summary>
  539. /// Registers an IdGenerator for an Id Type.
  540. /// </summary>
  541. /// <param name="type">The Id Type.</param>
  542. /// <param name="idGenerator">The IdGenerator for the Id Type.</param>
  543. public static void RegisterIdGenerator(Type type, IIdGenerator idGenerator)
  544. {
  545. __configLock.EnterWriteLock();
  546. try
  547. {
  548. __idGenerators[type] = idGenerator;
  549. }
  550. finally
  551. {
  552. __configLock.ExitWriteLock();
  553. }
  554. }
  555. /// <summary>
  556. /// Registers a serialization provider.
  557. /// </summary>
  558. /// <param name="provider">The serialization provider.</param>
  559. public static void RegisterSerializationProvider(IBsonSerializationProvider provider)
  560. {
  561. __serializerRegistry.RegisterSerializationProvider(provider);
  562. }
  563. /// <summary>
  564. /// Registers a serializer for a type.
  565. /// </summary>
  566. /// <typeparam name="T">The type.</typeparam>
  567. /// <param name="serializer">The serializer.</param>
  568. public static void RegisterSerializer<T>(IBsonSerializer<T> serializer)
  569. {
  570. RegisterSerializer(typeof(T), serializer);
  571. }
  572. /// <summary>
  573. /// Registers a serializer for a type.
  574. /// </summary>
  575. /// <param name="type">The type.</param>
  576. /// <param name="serializer">The serializer.</param>
  577. public static void RegisterSerializer(Type type, IBsonSerializer serializer)
  578. {
  579. __serializerRegistry.RegisterSerializer(type, serializer);
  580. }
  581. /// <summary>
  582. /// Serializes a value.
  583. /// </summary>
  584. /// <typeparam name="TNominalType">The nominal type of the object.</typeparam>
  585. /// <param name="bsonWriter">The BsonWriter.</param>
  586. /// <param name="value">The object.</param>
  587. /// <param name="configurator">The serialization context configurator.</param>
  588. /// <param name="args">The serialization args.</param>
  589. public static void Serialize<TNominalType>(
  590. IBsonWriter bsonWriter,
  591. TNominalType value,
  592. Action<BsonSerializationContext.Builder> configurator = null,
  593. BsonSerializationArgs args = default(BsonSerializationArgs))
  594. {
  595. var serializer = LookupSerializer<TNominalType>();
  596. var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator);
  597. serializer.Serialize(context, args, value);
  598. }
  599. /// <summary>
  600. /// Serializes a value.
  601. /// </summary>
  602. /// <param name="bsonWriter">The BsonWriter.</param>
  603. /// <param name="nominalType">The nominal type of the object.</param>
  604. /// <param name="value">The object.</param>
  605. /// <param name="configurator">The serialization context configurator.</param>
  606. /// <param name="args">The serialization args.</param>
  607. public static void Serialize(
  608. IBsonWriter bsonWriter,
  609. Type nominalType,
  610. object value,
  611. Action<BsonSerializationContext.Builder> configurator = null,
  612. BsonSerializationArgs args = default(BsonSerializationArgs))
  613. {
  614. var serializer = LookupSerializer(nominalType);
  615. var context = BsonSerializationContext.CreateRoot(bsonWriter, configurator);
  616. serializer.Serialize(context, args, value);
  617. }
  618. // internal static methods
  619. internal static void EnsureKnownTypesAreRegistered(Type nominalType)
  620. {
  621. __configLock.EnterReadLock();
  622. try
  623. {
  624. if (__typesWithRegisteredKnownTypes.Contains(nominalType))
  625. {
  626. return;
  627. }
  628. }
  629. finally
  630. {
  631. __configLock.ExitReadLock();
  632. }
  633. __configLock.EnterWriteLock();
  634. try
  635. {
  636. if (!__typesWithRegisteredKnownTypes.Contains(nominalType))
  637. {
  638. // only call LookupClassMap for classes with a BsonKnownTypesAttribute
  639. #if NET45
  640. var knownTypesAttribute = nominalType.GetTypeInfo().GetCustomAttributes(typeof(BsonKnownTypesAttribute), false);
  641. #else
  642. var knownTypesAttribute = nominalType.GetTypeInfo().GetCustomAttributes(typeof(BsonKnownTypesAttribute), false).ToArray();
  643. #endif
  644. if (knownTypesAttribute != null && knownTypesAttribute.Length > 0)
  645. {
  646. // try and force a scan of the known types
  647. LookupSerializer(nominalType);
  648. }
  649. __typesWithRegisteredKnownTypes.Add(nominalType);
  650. }
  651. }
  652. finally
  653. {
  654. __configLock.ExitWriteLock();
  655. }
  656. }
  657. // private static methods
  658. private static void CreateSerializerRegistry()
  659. {
  660. __serializerRegistry = new BsonSerializerRegistry();
  661. __typeMappingSerializationProvider = new TypeMappingSerializationProvider();
  662. // order matters. It's in reverse order of how they'll get consumed
  663. __serializerRegistry.RegisterSerializationProvider(new BsonClassMapSerializationProvider());
  664. __serializerRegistry.RegisterSerializationProvider(new DiscriminatedInterfaceSerializationProvider());
  665. __serializerRegistry.RegisterSerializationProvider(new CollectionsSerializationProvider());
  666. __serializerRegistry.RegisterSerializationProvider(new PrimitiveSerializationProvider());
  667. __serializerRegistry.RegisterSerializationProvider(new AttributedSerializationProvider());
  668. __serializerRegistry.RegisterSerializationProvider(__typeMappingSerializationProvider);
  669. __serializerRegistry.RegisterSerializationProvider(new BsonObjectModelSerializationProvider());
  670. }
  671. private static void RegisterIdGenerators()
  672. {
  673. RegisterIdGenerator(typeof(BsonObjectId), BsonObjectIdGenerator.Instance);
  674. RegisterIdGenerator(typeof(Guid), GuidGenerator.Instance);
  675. RegisterIdGenerator(typeof(ObjectId), ObjectIdGenerator.Instance);
  676. }
  677. }
  678. }