Skip to content

Commit

Permalink
CSHARP-2994: Write reference documentation for new V3 GuidRepresentat…
Browse files Browse the repository at this point in the history
…ionMode.
  • Loading branch information
rstam committed Jul 30, 2020
1 parent 9ac03cf commit 6a6b67e
Show file tree
Hide file tree
Showing 9 changed files with 277 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
+++
date = "2020-07-23T00:00:00Z"
draft = false
title = "Background"
[menu.main]
parent = "GuidSerialization"
identifier = "GuidSerializationBackground"
weight = 10
pre = "<i class='fa'></i>"
+++

## Background information

Guids were originally represented in BSON as BsonBinaryData values of subtype 3. Unfortunately, different drivers
inadvertently used different byte orders when converting a Guid to a 16 byte binary value. To standardize on a
single canonical representation BsonBinaryData subtype 4 was created with a well defined byte order.

The C# driver's support for Guids was originally based on the premise that all Guids in a single collection must
be represented the same way (i.e. using the same BsonBinaryData sub type and byte order). In order to accomplish this
the representation of Guids is enforced at the BSON reader and writer levels (because a single reader or writer is
used to read or write an entire document from or to the collection).

However, this original premise has not stood the test of time.

The first issue we ran into was that the server
started returning UUIDs (i.e. Guids) in metadata using standard subtype 4. If a collection was configured to use
subtype 3 (which it usually was since that is the default) the driver could not deserialize the Guids in the metadata
without throwing an exception. We worked around this by temporarily reconfiguring the BSON reader while reading the metadata.

The second issue is that the original premise was too strict. There are valid reasons why a single collection might
have a mix of Guid representations, and we need to allow that.

Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
+++
date = "2020-07-23T00:00:00Z"
draft = false
title = "GuidRepresentationMode"
[menu.main]
parent = "GuidSerialization"
identifier = "GuidRepresentationMode"
weight = 10
pre = "<i class='fa'></i>"
+++

## GuidRepresentationMode

If we just abruptly changed the way the driver serialized Guids that would be a breaking change. In order to help applications
migrate in an orderly fashion to the new way of handling Guids we have introduced a configurable `GuidRepresentationMode`.
In V2 mode the driver will handle Guids the same way that the v2.x versions have in the past. In V3 mode the driver
will handle Guids in the new way. An application can opt-in to V3 mode to transition to the new way Guids are handled.
In the v2.x versions of the driver V2 is the default mode but V3 mode is supported. In future v3.x versions of the driver
V3 will be the default mode (and support for V2 mode will be removed).

### GuidRepresentationMode == V2 (Deprecated)

In V2 mode the central principle is that all Guids in a collection must be represented the same way. In order to enforce
this the representation of Guids is not controlled at the individual serializer level, but rather at the reader/writer
level since the same reader/writer is used to read/write an entire document.

Read more about V2 mode [here]({{< relref "reference\bson\guidserialization\guidrepresentationmode\v2mode.md" >}}).

### GuidRepresentationMode == V3

In V3 mode the central principle is that the representation of Guids is controlled at the level of each individual
property by configuring the serializer for that property. The recommendation is that all Guids in a
collection be represented uniformly using the standard BsonBinaryData subtype 4, but when working with historical
data it is acceptable for different Guid fields in the same document to be represented differently.

Read more about V3 mode [here]({{< relref "reference\bson\guidserialization\guidrepresentationmode\v3mode.md" >}}).

### Opting in to V3 GuidRepresentationMode

An application must choose to use either the original V2 GuidRepresentationMode or the new V3 GuidRepresentationMode. It is
not possible to mix use of both modes in the same application.

If you want to use V2 mode you don't need to do anything because V2 is still the default.

If you want to use V3 mode execute the following line of code as early as possible in your application:

```csharp
BsonDefaults.GuidRepresentationMode = GuidRepresentationMode.V3;
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
+++
date = "2020-07-23T00:00:00Z"
draft = false
title = "V2 mode"
[menu.main]
parent = "GuidRepresentationMode"
identifier = "GuidRepresentationModeV2"
weight = 20
pre = "<i class='fa'></i>"
+++

## V2 GuidRepresentationMode (Deprecated)

In V2 mode the central principle is that all Guids in a collection must be represented the same way. In order to enforce
this the representation of Guids is not controlled at the individual serializer level, but rather at the reader/writer
level since the same reader/writer is used to read/write an entire document.

All of the following properties and methods are only relevant to V2 mode and are now deprecated:

* BsonDefaults GuidRepresentation property
* BsonBinaryData implicit conversion to or from Guid
* BsonBinaryData constructor taking a Guid (without a GuidRepresentation)
* BsonBinaryData constructor taking (byte[], BsonBinarySubType, GuidRepresentation)
* BsonBinaryData GuidRepresentation property
* BsonValue implicit conversion from Guid or Guid? (Nullable\<Guid>)
* BsonDocumentReaderSettings constructor taking a GuidRepresentation
* BsonDocumentWriterSettings constructor taking a GuidRepresentation
* BsonReaderSettings GuidRepresentation property
* BsonWriterSettings GuidRepresentation property
* IBsonReaderExtentions ReadBinaryDataWithGuidRepresentationUnspecified extension method
* MongoClientSettings GuidRepresentation property
* MongoCollectionSettings GuidRepresentation property
* MongoDatabaseSettings GuidRepresentation property
* MongoDefaults GuidRepresentation property
* MongoUrl GuidRepresentation property
* MongoUrlBuilder GuidRepresentation property
* MongoGridFSSettings GuidRepresentation property

Note: the BsonDefaults GuidRepresentationMode property is itself deprecated even though it is new because it is only
intended to be use during the transition period and will be removed when support for V2 mode is removed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
+++
date = "2020-07-23T00:00:00Z"
draft = false
title = "V3 mode"
[menu.main]
parent = "GuidRepresentationMode"
identifier = "GuidRepresentationModeV3"
weight = 20
pre = "<i class='fa'></i>"
+++

## V3 GuidRepresentationMode

In V3 mode the central principle is that the representation of Guids is controlled at the level of each individual
property of a document by configuring the serializer for that property. The recommendation is that all Guids in a
collection be represented uniformly using the standard BsonBinaryData subtype 4, but when working with historical
data it is acceptable for different Guid fields in the same document to be represented differently.

The following existing methods behave differently in V3 mode:

* BsonBinaryReader.ReadBinaryData method ignores readerSettings.GuidRepresentation
* BsonBinaryWriter.WriteBinaryData method ignores writerSettings.GuidRepresentation
* JsonReader ReadBinaryData method ignores readerSettings.GuidRepresentation
* JsonWriter ignores writerSettings.GuidRepresentation
* BsonBinaryData ToGuid without GuidRepresentation argument is only valid for sub type 4


22 changes: 22 additions & 0 deletions Docs/reference/content/reference/bson/guidserialization/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
+++
date = "2020-07-23T00:00:00Z"
draft = false
title = "Guid Serialization"
[menu.main]
parent = "BSON"
identifier = "GuidSerialization"
weight = 35
pre = "<i class='fa'></i>"
+++

# Guid serialization

We are making changes to how Guids will be serialized in the future. For the time being the driver will
continue to serialize Guids as it has in the past, in order to not break backward compatibility. You
can opt-in to the new way of serializing Guids by setting the GuidRepresentationMode to V3.

The folowing sections contain more information:

* - [Background]({{< relref "reference\bson\guidserialization\background.md" >}})
* - [GuidRepresentationMode]({{< relref "reference\bson\guidserialization\guidrepresentationmode\guidrepresentationmode.md" >}})
* - [Serializer changes]({{< relref "reference\bson\guidserialization\serializerchanges\serializerchanges.md" >}})
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
+++
date = "2020-07-23T00:00:00Z"
draft = false
title = "GuidSerializer changes"
[menu.main]
parent = "GuidSerializationSerializerChanges"
identifier = "GuidSerializerChanges"
weight = 20
pre = "<i class='fa'></i>"
+++

# GuidSerializer changes

Some small changes have been made to the GuidSerializer to allow the GuidRepresentation it uses to be configurable at the serializer level.

## GuidRepresentation constructor argument and property

A new constructor has been added that allows you to configure the desired GuidRepresentation when instantiating an instance of
the GuidSerializer. Calling the constructor that takes a GuidRepresentation property implies a BsonType representation of Binary.

For example:

```csharp
var guidSerializer = new GuidSerializer(GuidRepresentation.Standard);
```

If you want to use the Standard GuidRepresentation globally you can register a properly configured GuidSerializer early in your code:

```csharp
BsonSerializer.RegisterSerializer(new GuidSerializer(GuidRepresentation.Standard));
```

## BsonGuidRepresentation attribute

In V3 GuidRepresentationMode you must explicitly specify the GuidRepresentation you want used for every Guid property. If you are
relying on the driver's auto mapping to map C# classes to document schemas you may use the new BsonGuidRepresentation attribute to specify the desired representation.

For example:

```csharp
public class C
{
public int Id { get; set; }

[BsonGuidRepresentation(GuidRepresentation.Standard)]
public Guid G { get; set; }
}
```

If most of your Guids use the same representation and only a few use a different representation, you could alternatively register
a global GuidSerializer (as shown above) for the most commonly used representation, and only use the BsonGuidRepresentation attribute
to mark the ones that use a different representation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
+++
date = "2020-07-23T00:00:00Z"
draft = false
title = "ObjectSerializer changes"
[menu.main]
parent = "GuidSerializationSerializerChanges"
identifier = "ObjectSerializerChanges"
weight = 20
pre = "<i class='fa'></i>"
+++

# ObjectSerializer changes

Some small changes have been made to the ObjectSerializer to allow the GuidRepresentation it uses to be configurable at the serializer level.

## GuidRepresentation constructor argument and property

A new constructor has been added that allows you to configure the desired GuidRepresentation when instantiating an instance of
the ObjectSerializer.

For example:

```csharp
var objectDiscriminatorConvention = BsonSerializer.LookupDiscriminatorConvention(typeof(object));
var objectSerializer = new ObjectSerializer(objectDiscriminatorConvention, GuidRepresentation.Standard);
```

In V3 GuidRepresentationMode, if your application relies on the ObjectSerializer to serialize any Guids you must register
an object serializer that you have configured the way you want. This must be done early in your application and this object
serializer will be globally used whenever an object serializer is needed and has not been otherwise specified.

```csharp
var objectDiscriminatorConvention = BsonSerializer.LookupDiscriminatorConvention(typeof(object));
var objectSerializer = new ObjectSerializer(objectDiscriminatorConvention, GuidRepresentation.Standard);
BsonSerializer.RegisterSerializer(objectSerializer);
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
+++
date = "2020-07-23T00:00:00Z"
draft = false
title = "Serializer changes"
[menu.main]
parent = "GuidSerialization"
identifier = "GuidSerializationSerializerChanges"
weight = 10
pre = "<i class='fa'></i>"
+++

# Serializer changes

The following sections describe changes to the two serializers to handle Guids differently:

* - [GuidSerializer changes]({{< relref "reference\bson\guidserialization\serializerchanges\guidserializerchanges.md" >}})
* - [ObjectSerializer changes]({{< relref "reference\bson\guidserialization\serializerchanges\objectserializerchanges.md" >}})
3 changes: 2 additions & 1 deletion Docs/reference/content/reference/bson/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ The MongoDB.Bson library handles [BSON](http://bsonspec.org) and [JSON](http://j
- [Reading and Writing BSON/JSON]({{< relref "reference\bson\bson.md" >}})
- [BsonDocument]({{< relref "reference\bson\bson_document.md" >}})
- [Serialization]({{< relref "reference\bson\serialization.md" >}})
- [Mapping Classes]({{< relref "reference\bson\mapping\index.md" >}})
- [Guid Serialization]({{< relref "reference\bson\guidserialization\index.md" >}})
- [Mapping Classes]({{< relref "reference\bson\mapping\index.md" >}})

0 comments on commit 6a6b67e

Please sign in to comment.