diff --git a/docs/client-api/configuration/content/_deserialization-csharp.mdx b/docs/client-api/configuration/content/_deserialization-csharp.mdx
index b2d4586e79..fb62d29d45 100644
--- a/docs/client-api/configuration/content/_deserialization-csharp.mdx
+++ b/docs/client-api/configuration/content/_deserialization-csharp.mdx
@@ -1,15 +1,13 @@
import Admonition from '@theme/Admonition';
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-import CodeBlock from '@theme/CodeBlock';
-import ContentFrame from "@site/src/components/ContentFrame";
+import Panel from "@site/src/components/Panel";
-Use the methods described in this page to customize the [conventions](../../../client-api/configuration/conventions.mdx)
-by which entities are deserialized as they are received by the client.
-
-* In this page:
+* The C# client deserializes documents loaded from the server into entities using the
+ [Newtonsoft.Json](https://www.newtonsoft.com/json/help/html/SerializingJSON.htm) library (also known as Json.NET).
+* Use the [conventions](../../../client-api/configuration/conventions.mdx) described in this article
+ to customize the deserialization (e.g., to preserve document properties that your entity class does not define).
+* In this article:
* [CustomizeJsonDeserializer](../../../client-api/configuration/deserialization.mdx#customizejsondeserializer)
* [DeserializeEntityFromBlittable](../../../client-api/configuration/deserialization.mdx#deserializeentityfromblittable)
* [PreserveDocumentPropertiesNotFoundOnModel](../../../client-api/configuration/deserialization.mdx#preservedocumentpropertiesnotfoundonmodel)
@@ -18,35 +16,34 @@ by which entities are deserialized as they are received by the client.
-
-
-## CustomizeJsonDeserializer
-
-* The `JsonSerializer` object is used by the client to deserialize entities
- loaded from the server.
-* Use the `CustomizeJsonDeserializer` convention to modify `JsonSerializer`
- by registering a deserialization customization action.
-
-```csharp
-Conventions =
-{
- Serialization = new NewtonsoftJsonSerializationConventions
- {
- CustomizeJsonDeserializer = serializer => throw new CodeOmitted()
- }
-}
-```
-
-
-
----
-
-
-
-## DeserializeEntityFromBlittable
-
-* Use the `DeserializeEntityFromBlittable` convention to customize entity
- deserialization from a blittable JSON.
+
+
+* The client uses `JsonSerializer` objects of the [Newtonsoft.Json](https://www.newtonsoft.com/json/help/html/SerializingJSON.htm)
+ library to **deserialize** documents loaded from the server into entities.
+* Use the `CustomizeJsonDeserializer` convention to register an action that modifies only the `JsonSerializer` objects
+ used to load documents (e.g., to keep a property's default value when the loaded document holds `null` for this property).
+
+ ```csharp
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ CustomizeJsonDeserializer = serializer => throw new CodeOmitted()
+ }
+ }
+ ```
+
+* Note that an action registered using [CustomizeJsonSerializer](../../../client-api/configuration/serialization.mdx#customizejsonserializer)
+ also applies when loading documents, and runs before the `CustomizeJsonDeserializer` action.
+ A [converter](../../../client-api/configuration/serialization.mdx#adding-a-converter) registered using `CustomizeJsonSerializer`
+ therefore does not need to be registered using `CustomizeJsonDeserializer` as well.
+
+
+
+
+
+Use the `DeserializeEntityFromBlittable` convention to customize entity
+deserialization from a blittable JSON.
```csharp
Conventions =
@@ -58,13 +55,9 @@ Conventions =
}
```
-
-
----
+
-
-
-## PreserveDocumentPropertiesNotFoundOnModel
+
* Some document properties are not deserialized to an object.
* Set the `PreserveDocumentPropertiesNotFoundOnModel` convention to `true`
@@ -80,13 +73,9 @@ Conventions =
}
```
-
-
----
-
-
+
-## DefaultRavenSerializationBinder
+
Use the `DefaultRavenSerializationBinder` convention and its methods to
prevent gadgets from running RCE (Remote Code Execution) attacks while
@@ -95,18 +84,14 @@ data is deserialized by the client.
Read about this security convention and maintaining deserialization security
[here](../../../client-api/security/deserialization-security.mdx).
-
-
----
-
-
+
-## Number Deserialization
+
* RavenDB client supports all common numeric value types (including `int`, `long`,
`double`, `decimal`, etc.) out of the box.
* Note that although deserialization of `decimals` is fully supported, there are
[server side limitations](../../../server/kb/numbers-in-ravendb.mdx) to numbers in this range.
-* Other number types, like `BigInteger`, must be handled using custom deserialization.
+* Other number types, like `BigInteger`, must be handled using a [converter](../../../client-api/configuration/serialization.mdx#adding-a-converter).
-
+
diff --git a/docs/client-api/configuration/content/_serialization-csharp.mdx b/docs/client-api/configuration/content/_serialization-csharp.mdx
index 403f79e063..c1b30da8e0 100644
--- a/docs/client-api/configuration/content/_serialization-csharp.mdx
+++ b/docs/client-api/configuration/content/_serialization-csharp.mdx
@@ -1,139 +1,384 @@
import Admonition from '@theme/Admonition';
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-import CodeBlock from '@theme/CodeBlock';
+import Panel from "@site/src/components/Panel";
import ContentFrame from "@site/src/components/ContentFrame";
-Use the methods described in this page to customize the [conventions](../../../client-api/configuration/conventions.mdx)
-by which entities are serialized as they are sent by the client to the server.
-
-* In this page:
+* The C# client serializes entities into JSON using the
+ [Newtonsoft.Json](https://www.newtonsoft.com/json/help/html/SerializingJSON.htm) library (also known as Json.NET).
+* Use the [conventions](../../../client-api/configuration/conventions.mdx) described in this article
+ to customize the serialization (e.g., to exclude a property, or to control the JSON form of a type).
+* In this article:
* [Ignoring a property](../../../client-api/configuration/serialization.mdx#ignoring-a-property)
* [CustomizeJsonSerializer](../../../client-api/configuration/serialization.mdx#customizejsonserializer)
+ * [Adding a converter](../../../client-api/configuration/serialization.mdx#adding-a-converter)
+ * [Example: Storing a temperature as a string](../../../client-api/configuration/serialization.mdx#example-storing-a-temperature-as-a-string)
+ * [Example: Storing FHIR resources](../../../client-api/configuration/serialization.mdx#example-storing-fhir-resources)
* [JsonContractResolver](../../../client-api/configuration/serialization.mdx#jsoncontractresolver)
- * [BulkInsert.TrySerializeEntityToJsonStream](../../../client-api/configuration/serialization.mdx#bulkinserttryserializeentitytojsonstream)
+ * [BulkInsert.TrySerializeEntityToJsonStream](../../../client-api/configuration/serialization.mdx#bulkinsert-tryserializeentitytojsonstream)
* [IgnoreByRefMembers and IgnoreUnsafeMembers](../../../client-api/configuration/serialization.mdx#ignorebyrefmembers-and-ignoreunsafemembers)
-
-
-## Ignoring a property
+
* By default, RavenDB serializes **all** properties and **all** public fields of an entity.
-* Decorate a property with `[JsonIgnore]` to exclude it from serialization.
+* Decorate a property with `[JsonIgnore]` (from the `Newtonsoft.Json` namespace) to exclude it from serialization.
The decorated property will not be stored in the document and will not be available for indexing.
-* `[JsonIgnore]` is from the `Newtonsoft.Json` namespace.
+
+ ```csharp
+ public class Shirt
+ {
+ public string Id { get; set; }
+
+ // Stored in the document
+ public decimal Price { get; set; }
+
+ // Not stored - computed from Price at runtime
+ [JsonIgnore]
+ public decimal PriceWithTax => Price * 1.2m;
+ }
+ ```
+
+
+
+
+
+* The client uses `JsonSerializer` objects of the [Newtonsoft.Json](https://www.newtonsoft.com/json/help/html/SerializingJSON.htm)
+ library to **serialize** entities into JSON before sending the entities to the server,
+ and to **deserialize** documents loaded from the server back into entities.
+* Use the `CustomizeJsonSerializer` convention to register an action that modifies the `JsonSerializer` objects.
+ The client applies the registered action when storing entities as well as when loading documents into entities.
+ To customize only the deserialization of loaded documents, use the
+ [CustomizeJsonDeserializer](../../../client-api/configuration/deserialization.mdx#customizejsondeserializer) convention.
+
+ ```csharp
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ CustomizeJsonSerializer = serializer => throw new CodeOmitted()
+ }
+ }
+ ```
-```csharp
-public class Shirt
-{
- public string Id { get; set; }
+---
- // Stored in the document
- public decimal Price { get; set; }
+### Adding a converter
- // Not stored - computed from Price at runtime
- [JsonIgnore]
- public decimal PriceWithTax => Price * 1.2m;
-}
-```
+To control the JSON form of a specific type (e.g., to store a temperature as the string `"30C"`),
+add a **converter** for this type: a class that tells the `JsonSerializer` object how to serialize and deserialize the type.
+Learn more about converters in the Newtonsoft.Json [Custom JsonConverter](https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm) article.
-
+
----
+Define and register a converter as follows:
+
+1. Define a converter class derived from the library's `JsonConverter` class, with your type as `T`.
+2. Override the converter's `WriteJson` method to write the type's JSON form.
+ `WriteJson` receives a **writer** (a `JsonWriter` object) that writes JSON one element at a time,
+ e.g., the writer's `WriteValue` method writes a single value.
+
+ ```csharp
+ public override void WriteJson(JsonWriter writer, Temperature value, JsonSerializer serializer)
+ {
+ // Supported: WriteValue writes the string "30C" as a single JSON value
+ writer.WriteValue($"{value.Celsius}C");
+
+ // Not supported: WriteRaw would write "30C" as raw JSON text
+ // writer.WriteRaw($"\"{value.Celsius}C\"");
+ }
+ ```
+
+
+ The writer that the client provides does not support raw JSON text (a JSON string written in one piece),
+ so calling the writer's `WriteRaw` or `WriteRawValue` method throws a `NotSupportedException`.
+
+3. Override the converter's `ReadJson` method to convert the JSON form back into the type.
+4. In the action you register using `CustomizeJsonSerializer`,
+ add the converter to the `Converters` collection of the `JsonSerializer` object.
+
+
-## CustomizeJsonSerializer
+#### Example: Storing a temperature as a string
-* The `JsonSerializer` object is used by the client to serialize entities
- sent by the client to the server.
-* Use the `CustomizeJsonSerializer` convention to modify `JsonSerializer`
- by registering a serialization customization action.
+In the following example, a `WeatherReport` entity holds a `Temperature` object in its `Temp` property.
+A converter stores the `Temperature` object as a string (e.g., `"30C"`) rather than as a JSON object (e.g., `{"Celsius": 30}`).
```csharp
-Serialization = new NewtonsoftJsonSerializationConventions
+public class Temperature
{
- CustomizeJsonSerializer = serializer => throw new CodeOmitted()
+ public int Celsius { get; set; }
}
-```
-
+public class WeatherReport
+{
+ public string Id { get; set; }
+ public Temperature Temp { get; set; }
+}
----
+public class TemperatureConverter : JsonConverter
+{
+ public override void WriteJson(JsonWriter writer, Temperature value, JsonSerializer serializer)
+ {
+ writer.WriteValue($"{value.Celsius}C");
+ }
-
+ public override Temperature ReadJson(JsonReader reader, Type objectType, Temperature existingValue,
+ bool hasExistingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ return null;
-## JsonContractResolver
+ // Remove the trailing "C" and parse the number
+ var text = (string)reader.Value;
+ return new Temperature { Celsius = int.Parse(text.Substring(0, text.Length - 1)) };
+ }
+}
+```
+
-* The default `JsonContractResolver` convention used by RavenDB will serialize
- **all** properties and **all** public fields.
-* Change this behavior by providing your own implementation of the `IContractResolver`
- interface.
+The following code uses `CustomizeJsonSerializer` to register the `TemperatureConverter` class defined above,
+stores a `WeatherReport` document, and loads the document back.
+Since `CustomizeJsonSerializer` applies when loading documents as well, the same converter converts the stored string
+back into a `Temperature` object.
```csharp
-Serialization = new NewtonsoftJsonSerializationConventions
+using (var store = new DocumentStore
+{
+ Urls = new[] { "http://localhost:8080" },
+ Database = "Demo",
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ // Register the converter
+ CustomizeJsonSerializer = serializer => serializer.Converters.Add(new TemperatureConverter())
+ }
+ }
+}.Initialize())
{
- JsonContractResolver = new CustomJsonContractResolver()
+ using (var session = store.OpenSession())
+ {
+ // The document is stored with: "Temp": "30C"
+ session.Store(new WeatherReport { Temp = new Temperature { Celsius = 30 } }, "weatherReports/1");
+ session.SaveChanges();
+ }
+
+ using (var session = store.OpenSession())
+ {
+ // report.Temp is loaded back into a Temperature object with Celsius = 30
+ var report = session.Load("weatherReports/1");
+ }
}
```
+
+
+
+
+#### Example: Storing FHIR resources
+
+[FHIR](https://hl7.org/fhir/) (Fast Healthcare Interoperability Resources) is a standard for exchanging healthcare data,
+published by HL7.
+The [Firely .NET SDK](https://docs.fire.ly/projects/Firely-NET-SDK/en/latest/) provides .NET classes for FHIR resources
+(e.g., `Patient`), along with its own JSON serializer and parser for these classes.
+
+In the following example, a converter hands the serialization of FHIR resources to the SDK's serializer and parser,
+so a `Patient` resource is stored in FHIR's JSON format and loaded back into a `Patient` object.
+The converter's `WriteJson` method writes the serializer's output to the writer element by element,
+since the writer does not support [raw JSON text](../../../client-api/configuration/serialization.mdx#adding-a-converter).
+
```csharp
-public class CustomJsonContractResolver : IContractResolver
+using System;
+using System.IO;
+// Firely .NET SDK namespaces, from the Hl7.Fhir.R4 NuGet package
+using Hl7.Fhir.ElementModel;
+using Hl7.Fhir.Model;
+using Hl7.Fhir.Serialization;
+using Newtonsoft.Json;
+
+public class FhirResourceConverter : JsonConverter where T : Base
{
- public JsonContract ResolveContract(Type type)
+ // Skip JSON properties that the SDK's class does not define
+ // (e.g., the @metadata property of a loaded RavenDB document)
+ private static readonly PocoBuilderSettings BuilderSettings = new() { IgnoreUnknownMembers = true };
+
+ public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer)
+ {
+ // Serialize the resource using the SDK's serializer
+ var json = new FhirJsonSerializer().SerializeToString(value);
+
+ // Write the resulting JSON to the writer element by element,
+ // keeping dates and decimal values exactly as the SDK wrote them
+ using (var reader = new JsonTextReader(new StringReader(json))
+ { DateParseHandling = DateParseHandling.None, FloatParseHandling = FloatParseHandling.Decimal })
+ {
+ writer.WriteToken(reader);
+ }
+ }
+
+ public override T ReadJson(JsonReader reader, Type objectType, T existingValue,
+ bool hasExistingValue, JsonSerializer serializer)
{
- throw new CodeOmitted();
+ // Parse the stored JSON into the SDK's class
+ return FhirJsonNode.Read(reader).ToPoco(BuilderSettings);
}
}
```
+
-* You can also customize the behavior of the **default resolver** by inheriting
- from `DefaultRavenContractResolver` and overriding specific methods.
+The following code uses `CustomizeJsonSerializer` to register the converter class defined above for the `Patient` class
+(`FhirResourceConverter`), stores a `Patient` resource as a document, and loads the document back into a `Patient` object.
```csharp
-public class CustomizedRavenJsonContractResolver : DefaultRavenContractResolver
+using (var store = new DocumentStore
+{
+ Urls = new[] { "http://localhost:8080" },
+ Database = "Demo",
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ // Register a converter for each FHIR resource class you store
+ CustomizeJsonSerializer = serializer => serializer.Converters.Add(new FhirResourceConverter())
+ }
+ }
+}.Initialize())
{
- public CustomizedRavenJsonContractResolver(ISerializationConventions conventions) : base(conventions)
+ using (var session = store.OpenSession())
{
+ var patient = new Patient
+ {
+ // The resource ID is used as the document ID;
+ // FHIR IDs may contain only letters, digits, '-', and '.'
+ Id = "pat-1001",
+ Active = true,
+ Name = new List
+ {
+ new HumanName { Family = "Patel", Given = new List { "Sandeep" } }
+ }
+ };
+
+ session.Store(patient);
+ session.SaveChanges();
}
- protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
+ using (var session = store.OpenSession())
{
- throw new CodeOmitted();
+ // Loaded back into a Patient object
+ var patient = session.Load("pat-1001");
}
}
```
----
-
-
-
-## BulkInsert.TrySerializeEntityToJsonStream
+
-* Adjust [Bulk Insert](../../../client-api/bulk-insert/how-to-work-with-bulk-insert-operation.mdx)
- behavior by using the `TrySerializeEntityToJsonStream` convention to register a custom
- serialization implementation.
+
-```csharp
-BulkInsert =
-{
- TrySerializeEntityToJsonStream = (entity, metadata, writer) => throw new CodeOmitted(),
-}
-```
+* The default `JsonContractResolver` convention used by RavenDB will serialize
+ **all** properties and **all** public fields.
+* Change this behavior by providing your own implementation of the `IContractResolver`
+ interface.
+
+ ```csharp
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ JsonContractResolver = new CustomJsonContractResolver()
+ }
+ }
+ ```
+
+ ```csharp
+ public class CustomJsonContractResolver : IContractResolver
+ {
+ public JsonContract ResolveContract(Type type)
+ {
+ throw new CodeOmitted();
+ }
+ }
+ ```
+
+* You can also customize the behavior of the **default resolver** by inheriting
+ from `DefaultRavenContractResolver` and overriding specific methods.
+
+ ```csharp
+ public class CustomizedRavenJsonContractResolver : DefaultRavenContractResolver
+ {
+ public CustomizedRavenJsonContractResolver(ISerializationConventions conventions) : base(conventions)
+ {
+ }
-
+ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
+ {
+ throw new CodeOmitted();
+ }
+ }
+ ```
----
+
-
+
-## IgnoreByRefMembers and IgnoreUnsafeMembers
+* Adjust [Bulk Insert](../../../client-api/bulk-insert/how-to-work-with-bulk-insert-operation.mdx)
+ behavior by using the `TrySerializeEntityToJsonStream` convention to register a custom
+ serialization implementation.
+
+ ```csharp
+ Conventions =
+ {
+ BulkInsert =
+ {
+ TrySerializeEntityToJsonStream = (entity, metadata, writer) => throw new CodeOmitted(),
+ }
+ }
+ ```
+
+* The registered function receives the entity, the entity's metadata, and the writer of the bulk insert stream
+ (a `StreamWriter` object).
+ Return `true` after writing the entity to the writer as a JSON document, with the entity's metadata under the `@metadata` property.
+ To have the client serialize the entity using the default serialization instead, return `false` without writing to the writer.
+
+ ```csharp
+ Conventions =
+ {
+ BulkInsert =
+ {
+ TrySerializeEntityToJsonStream = (entity, metadata, writer) =>
+ {
+ // Let the client serialize entities of other types
+ if (entity is not User)
+ return false;
+
+ // Convert the entity into a JSON document
+ var document = JObject.FromObject(entity);
+
+ // Add the entity's metadata under the @metadata property
+ var metadataObject = new JObject();
+ foreach (var keyValue in metadata)
+ metadataObject.Add(keyValue.Key, new JValue(keyValue.Value));
+ document["@metadata"] = metadataObject;
+
+ // Write the document to the bulk insert stream
+ var jsonWriter = new JsonTextWriter(writer);
+ new JsonSerializer().Serialize(jsonWriter, document);
+ jsonWriter.Flush();
+
+ return true;
+ }
+ }
+ }
+ ```
+
+
+
+
* By default, if you try to store an entity with `ref` or unsafe members,
the Client will throw an exception when [`session.SaveChanges()`](../../../client-api/session/saving-changes.mdx)
@@ -149,4 +394,4 @@ BulkInsert =
* `IgnoreByRefMembers` default value: `false`
* `IgnoreUnsafeMembers` default value: `false`
-
+
diff --git a/docs/server/kb/numbers-in-ravendb.mdx b/docs/server/kb/numbers-in-ravendb.mdx
index 2e9e8fc491..7dbf7f99e3 100644
--- a/docs/server/kb/numbers-in-ravendb.mdx
+++ b/docs/server/kb/numbers-in-ravendb.mdx
@@ -159,9 +159,8 @@ Note that editing documents with numeric data outside of the precision range of
## Numbers in client API
-Numbers in RavenDB clients depend on the limitations of the platforms and the serialization/deserialization mechanisms. See articles in the desired languages:
-
-[Number (de)serialization](../../client-api/configuration/serialization.mdx#working-with-numbers)
+Numbers in RavenDB clients depend on the limitations of the platforms and the serialization/deserialization mechanisms.
+See [Conventions: Deserialization](../../client-api/configuration/deserialization.mdx)
diff --git a/versioned_docs/version-6.2/client-api/configuration/content/_deserialization-csharp.mdx b/versioned_docs/version-6.2/client-api/configuration/content/_deserialization-csharp.mdx
index b4191f5ca9..fb62d29d45 100644
Binary files a/versioned_docs/version-6.2/client-api/configuration/content/_deserialization-csharp.mdx and b/versioned_docs/version-6.2/client-api/configuration/content/_deserialization-csharp.mdx differ
diff --git a/versioned_docs/version-6.2/client-api/configuration/content/_serialization-csharp.mdx b/versioned_docs/version-6.2/client-api/configuration/content/_serialization-csharp.mdx
index 403f79e063..c1b30da8e0 100644
--- a/versioned_docs/version-6.2/client-api/configuration/content/_serialization-csharp.mdx
+++ b/versioned_docs/version-6.2/client-api/configuration/content/_serialization-csharp.mdx
@@ -1,139 +1,384 @@
import Admonition from '@theme/Admonition';
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-import CodeBlock from '@theme/CodeBlock';
+import Panel from "@site/src/components/Panel";
import ContentFrame from "@site/src/components/ContentFrame";
-Use the methods described in this page to customize the [conventions](../../../client-api/configuration/conventions.mdx)
-by which entities are serialized as they are sent by the client to the server.
-
-* In this page:
+* The C# client serializes entities into JSON using the
+ [Newtonsoft.Json](https://www.newtonsoft.com/json/help/html/SerializingJSON.htm) library (also known as Json.NET).
+* Use the [conventions](../../../client-api/configuration/conventions.mdx) described in this article
+ to customize the serialization (e.g., to exclude a property, or to control the JSON form of a type).
+* In this article:
* [Ignoring a property](../../../client-api/configuration/serialization.mdx#ignoring-a-property)
* [CustomizeJsonSerializer](../../../client-api/configuration/serialization.mdx#customizejsonserializer)
+ * [Adding a converter](../../../client-api/configuration/serialization.mdx#adding-a-converter)
+ * [Example: Storing a temperature as a string](../../../client-api/configuration/serialization.mdx#example-storing-a-temperature-as-a-string)
+ * [Example: Storing FHIR resources](../../../client-api/configuration/serialization.mdx#example-storing-fhir-resources)
* [JsonContractResolver](../../../client-api/configuration/serialization.mdx#jsoncontractresolver)
- * [BulkInsert.TrySerializeEntityToJsonStream](../../../client-api/configuration/serialization.mdx#bulkinserttryserializeentitytojsonstream)
+ * [BulkInsert.TrySerializeEntityToJsonStream](../../../client-api/configuration/serialization.mdx#bulkinsert-tryserializeentitytojsonstream)
* [IgnoreByRefMembers and IgnoreUnsafeMembers](../../../client-api/configuration/serialization.mdx#ignorebyrefmembers-and-ignoreunsafemembers)
-
-
-## Ignoring a property
+
* By default, RavenDB serializes **all** properties and **all** public fields of an entity.
-* Decorate a property with `[JsonIgnore]` to exclude it from serialization.
+* Decorate a property with `[JsonIgnore]` (from the `Newtonsoft.Json` namespace) to exclude it from serialization.
The decorated property will not be stored in the document and will not be available for indexing.
-* `[JsonIgnore]` is from the `Newtonsoft.Json` namespace.
+
+ ```csharp
+ public class Shirt
+ {
+ public string Id { get; set; }
+
+ // Stored in the document
+ public decimal Price { get; set; }
+
+ // Not stored - computed from Price at runtime
+ [JsonIgnore]
+ public decimal PriceWithTax => Price * 1.2m;
+ }
+ ```
+
+
+
+
+
+* The client uses `JsonSerializer` objects of the [Newtonsoft.Json](https://www.newtonsoft.com/json/help/html/SerializingJSON.htm)
+ library to **serialize** entities into JSON before sending the entities to the server,
+ and to **deserialize** documents loaded from the server back into entities.
+* Use the `CustomizeJsonSerializer` convention to register an action that modifies the `JsonSerializer` objects.
+ The client applies the registered action when storing entities as well as when loading documents into entities.
+ To customize only the deserialization of loaded documents, use the
+ [CustomizeJsonDeserializer](../../../client-api/configuration/deserialization.mdx#customizejsondeserializer) convention.
+
+ ```csharp
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ CustomizeJsonSerializer = serializer => throw new CodeOmitted()
+ }
+ }
+ ```
-```csharp
-public class Shirt
-{
- public string Id { get; set; }
+---
- // Stored in the document
- public decimal Price { get; set; }
+### Adding a converter
- // Not stored - computed from Price at runtime
- [JsonIgnore]
- public decimal PriceWithTax => Price * 1.2m;
-}
-```
+To control the JSON form of a specific type (e.g., to store a temperature as the string `"30C"`),
+add a **converter** for this type: a class that tells the `JsonSerializer` object how to serialize and deserialize the type.
+Learn more about converters in the Newtonsoft.Json [Custom JsonConverter](https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm) article.
-
+
----
+Define and register a converter as follows:
+
+1. Define a converter class derived from the library's `JsonConverter` class, with your type as `T`.
+2. Override the converter's `WriteJson` method to write the type's JSON form.
+ `WriteJson` receives a **writer** (a `JsonWriter` object) that writes JSON one element at a time,
+ e.g., the writer's `WriteValue` method writes a single value.
+
+ ```csharp
+ public override void WriteJson(JsonWriter writer, Temperature value, JsonSerializer serializer)
+ {
+ // Supported: WriteValue writes the string "30C" as a single JSON value
+ writer.WriteValue($"{value.Celsius}C");
+
+ // Not supported: WriteRaw would write "30C" as raw JSON text
+ // writer.WriteRaw($"\"{value.Celsius}C\"");
+ }
+ ```
+
+
+ The writer that the client provides does not support raw JSON text (a JSON string written in one piece),
+ so calling the writer's `WriteRaw` or `WriteRawValue` method throws a `NotSupportedException`.
+
+3. Override the converter's `ReadJson` method to convert the JSON form back into the type.
+4. In the action you register using `CustomizeJsonSerializer`,
+ add the converter to the `Converters` collection of the `JsonSerializer` object.
+
+
-## CustomizeJsonSerializer
+#### Example: Storing a temperature as a string
-* The `JsonSerializer` object is used by the client to serialize entities
- sent by the client to the server.
-* Use the `CustomizeJsonSerializer` convention to modify `JsonSerializer`
- by registering a serialization customization action.
+In the following example, a `WeatherReport` entity holds a `Temperature` object in its `Temp` property.
+A converter stores the `Temperature` object as a string (e.g., `"30C"`) rather than as a JSON object (e.g., `{"Celsius": 30}`).
```csharp
-Serialization = new NewtonsoftJsonSerializationConventions
+public class Temperature
{
- CustomizeJsonSerializer = serializer => throw new CodeOmitted()
+ public int Celsius { get; set; }
}
-```
-
+public class WeatherReport
+{
+ public string Id { get; set; }
+ public Temperature Temp { get; set; }
+}
----
+public class TemperatureConverter : JsonConverter
+{
+ public override void WriteJson(JsonWriter writer, Temperature value, JsonSerializer serializer)
+ {
+ writer.WriteValue($"{value.Celsius}C");
+ }
-
+ public override Temperature ReadJson(JsonReader reader, Type objectType, Temperature existingValue,
+ bool hasExistingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ return null;
-## JsonContractResolver
+ // Remove the trailing "C" and parse the number
+ var text = (string)reader.Value;
+ return new Temperature { Celsius = int.Parse(text.Substring(0, text.Length - 1)) };
+ }
+}
+```
+
-* The default `JsonContractResolver` convention used by RavenDB will serialize
- **all** properties and **all** public fields.
-* Change this behavior by providing your own implementation of the `IContractResolver`
- interface.
+The following code uses `CustomizeJsonSerializer` to register the `TemperatureConverter` class defined above,
+stores a `WeatherReport` document, and loads the document back.
+Since `CustomizeJsonSerializer` applies when loading documents as well, the same converter converts the stored string
+back into a `Temperature` object.
```csharp
-Serialization = new NewtonsoftJsonSerializationConventions
+using (var store = new DocumentStore
+{
+ Urls = new[] { "http://localhost:8080" },
+ Database = "Demo",
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ // Register the converter
+ CustomizeJsonSerializer = serializer => serializer.Converters.Add(new TemperatureConverter())
+ }
+ }
+}.Initialize())
{
- JsonContractResolver = new CustomJsonContractResolver()
+ using (var session = store.OpenSession())
+ {
+ // The document is stored with: "Temp": "30C"
+ session.Store(new WeatherReport { Temp = new Temperature { Celsius = 30 } }, "weatherReports/1");
+ session.SaveChanges();
+ }
+
+ using (var session = store.OpenSession())
+ {
+ // report.Temp is loaded back into a Temperature object with Celsius = 30
+ var report = session.Load("weatherReports/1");
+ }
}
```
+
+
+
+
+#### Example: Storing FHIR resources
+
+[FHIR](https://hl7.org/fhir/) (Fast Healthcare Interoperability Resources) is a standard for exchanging healthcare data,
+published by HL7.
+The [Firely .NET SDK](https://docs.fire.ly/projects/Firely-NET-SDK/en/latest/) provides .NET classes for FHIR resources
+(e.g., `Patient`), along with its own JSON serializer and parser for these classes.
+
+In the following example, a converter hands the serialization of FHIR resources to the SDK's serializer and parser,
+so a `Patient` resource is stored in FHIR's JSON format and loaded back into a `Patient` object.
+The converter's `WriteJson` method writes the serializer's output to the writer element by element,
+since the writer does not support [raw JSON text](../../../client-api/configuration/serialization.mdx#adding-a-converter).
+
```csharp
-public class CustomJsonContractResolver : IContractResolver
+using System;
+using System.IO;
+// Firely .NET SDK namespaces, from the Hl7.Fhir.R4 NuGet package
+using Hl7.Fhir.ElementModel;
+using Hl7.Fhir.Model;
+using Hl7.Fhir.Serialization;
+using Newtonsoft.Json;
+
+public class FhirResourceConverter : JsonConverter where T : Base
{
- public JsonContract ResolveContract(Type type)
+ // Skip JSON properties that the SDK's class does not define
+ // (e.g., the @metadata property of a loaded RavenDB document)
+ private static readonly PocoBuilderSettings BuilderSettings = new() { IgnoreUnknownMembers = true };
+
+ public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer)
+ {
+ // Serialize the resource using the SDK's serializer
+ var json = new FhirJsonSerializer().SerializeToString(value);
+
+ // Write the resulting JSON to the writer element by element,
+ // keeping dates and decimal values exactly as the SDK wrote them
+ using (var reader = new JsonTextReader(new StringReader(json))
+ { DateParseHandling = DateParseHandling.None, FloatParseHandling = FloatParseHandling.Decimal })
+ {
+ writer.WriteToken(reader);
+ }
+ }
+
+ public override T ReadJson(JsonReader reader, Type objectType, T existingValue,
+ bool hasExistingValue, JsonSerializer serializer)
{
- throw new CodeOmitted();
+ // Parse the stored JSON into the SDK's class
+ return FhirJsonNode.Read(reader).ToPoco(BuilderSettings);
}
}
```
+
-* You can also customize the behavior of the **default resolver** by inheriting
- from `DefaultRavenContractResolver` and overriding specific methods.
+The following code uses `CustomizeJsonSerializer` to register the converter class defined above for the `Patient` class
+(`FhirResourceConverter`), stores a `Patient` resource as a document, and loads the document back into a `Patient` object.
```csharp
-public class CustomizedRavenJsonContractResolver : DefaultRavenContractResolver
+using (var store = new DocumentStore
+{
+ Urls = new[] { "http://localhost:8080" },
+ Database = "Demo",
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ // Register a converter for each FHIR resource class you store
+ CustomizeJsonSerializer = serializer => serializer.Converters.Add(new FhirResourceConverter())
+ }
+ }
+}.Initialize())
{
- public CustomizedRavenJsonContractResolver(ISerializationConventions conventions) : base(conventions)
+ using (var session = store.OpenSession())
{
+ var patient = new Patient
+ {
+ // The resource ID is used as the document ID;
+ // FHIR IDs may contain only letters, digits, '-', and '.'
+ Id = "pat-1001",
+ Active = true,
+ Name = new List
+ {
+ new HumanName { Family = "Patel", Given = new List { "Sandeep" } }
+ }
+ };
+
+ session.Store(patient);
+ session.SaveChanges();
}
- protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
+ using (var session = store.OpenSession())
{
- throw new CodeOmitted();
+ // Loaded back into a Patient object
+ var patient = session.Load("pat-1001");
}
}
```
----
-
-
-
-## BulkInsert.TrySerializeEntityToJsonStream
+
-* Adjust [Bulk Insert](../../../client-api/bulk-insert/how-to-work-with-bulk-insert-operation.mdx)
- behavior by using the `TrySerializeEntityToJsonStream` convention to register a custom
- serialization implementation.
+
-```csharp
-BulkInsert =
-{
- TrySerializeEntityToJsonStream = (entity, metadata, writer) => throw new CodeOmitted(),
-}
-```
+* The default `JsonContractResolver` convention used by RavenDB will serialize
+ **all** properties and **all** public fields.
+* Change this behavior by providing your own implementation of the `IContractResolver`
+ interface.
+
+ ```csharp
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ JsonContractResolver = new CustomJsonContractResolver()
+ }
+ }
+ ```
+
+ ```csharp
+ public class CustomJsonContractResolver : IContractResolver
+ {
+ public JsonContract ResolveContract(Type type)
+ {
+ throw new CodeOmitted();
+ }
+ }
+ ```
+
+* You can also customize the behavior of the **default resolver** by inheriting
+ from `DefaultRavenContractResolver` and overriding specific methods.
+
+ ```csharp
+ public class CustomizedRavenJsonContractResolver : DefaultRavenContractResolver
+ {
+ public CustomizedRavenJsonContractResolver(ISerializationConventions conventions) : base(conventions)
+ {
+ }
-
+ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
+ {
+ throw new CodeOmitted();
+ }
+ }
+ ```
----
+
-
+
-## IgnoreByRefMembers and IgnoreUnsafeMembers
+* Adjust [Bulk Insert](../../../client-api/bulk-insert/how-to-work-with-bulk-insert-operation.mdx)
+ behavior by using the `TrySerializeEntityToJsonStream` convention to register a custom
+ serialization implementation.
+
+ ```csharp
+ Conventions =
+ {
+ BulkInsert =
+ {
+ TrySerializeEntityToJsonStream = (entity, metadata, writer) => throw new CodeOmitted(),
+ }
+ }
+ ```
+
+* The registered function receives the entity, the entity's metadata, and the writer of the bulk insert stream
+ (a `StreamWriter` object).
+ Return `true` after writing the entity to the writer as a JSON document, with the entity's metadata under the `@metadata` property.
+ To have the client serialize the entity using the default serialization instead, return `false` without writing to the writer.
+
+ ```csharp
+ Conventions =
+ {
+ BulkInsert =
+ {
+ TrySerializeEntityToJsonStream = (entity, metadata, writer) =>
+ {
+ // Let the client serialize entities of other types
+ if (entity is not User)
+ return false;
+
+ // Convert the entity into a JSON document
+ var document = JObject.FromObject(entity);
+
+ // Add the entity's metadata under the @metadata property
+ var metadataObject = new JObject();
+ foreach (var keyValue in metadata)
+ metadataObject.Add(keyValue.Key, new JValue(keyValue.Value));
+ document["@metadata"] = metadataObject;
+
+ // Write the document to the bulk insert stream
+ var jsonWriter = new JsonTextWriter(writer);
+ new JsonSerializer().Serialize(jsonWriter, document);
+ jsonWriter.Flush();
+
+ return true;
+ }
+ }
+ }
+ ```
+
+
+
+
* By default, if you try to store an entity with `ref` or unsafe members,
the Client will throw an exception when [`session.SaveChanges()`](../../../client-api/session/saving-changes.mdx)
@@ -149,4 +394,4 @@ BulkInsert =
* `IgnoreByRefMembers` default value: `false`
* `IgnoreUnsafeMembers` default value: `false`
-
+
diff --git a/versioned_docs/version-6.2/server/kb/numbers-in-ravendb.mdx b/versioned_docs/version-6.2/server/kb/numbers-in-ravendb.mdx
index aaba9fe80c..b1de23415d 100644
--- a/versioned_docs/version-6.2/server/kb/numbers-in-ravendb.mdx
+++ b/versioned_docs/version-6.2/server/kb/numbers-in-ravendb.mdx
@@ -158,9 +158,8 @@ Note that editing documents with numeric data outside of the precision range of
## Numbers in client API
-Numbers in RavenDB clients depend on the limitations of the platforms and the serialization/deserialization mechanisms. See articles in the desired languages:
-
-[Number (de)serialization](../../client-api/configuration/serialization.mdx#working-with-numbers)
+Numbers in RavenDB clients depend on the limitations of the platforms and the serialization/deserialization mechanisms.
+See [Conventions: Deserialization](../../client-api/configuration/deserialization.mdx)
diff --git a/versioned_docs/version-7.0/client-api/configuration/content/_deserialization-csharp.mdx b/versioned_docs/version-7.0/client-api/configuration/content/_deserialization-csharp.mdx
index b4191f5ca9..fb62d29d45 100644
Binary files a/versioned_docs/version-7.0/client-api/configuration/content/_deserialization-csharp.mdx and b/versioned_docs/version-7.0/client-api/configuration/content/_deserialization-csharp.mdx differ
diff --git a/versioned_docs/version-7.0/client-api/configuration/content/_serialization-csharp.mdx b/versioned_docs/version-7.0/client-api/configuration/content/_serialization-csharp.mdx
index 403f79e063..c1b30da8e0 100644
--- a/versioned_docs/version-7.0/client-api/configuration/content/_serialization-csharp.mdx
+++ b/versioned_docs/version-7.0/client-api/configuration/content/_serialization-csharp.mdx
@@ -1,139 +1,384 @@
import Admonition from '@theme/Admonition';
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-import CodeBlock from '@theme/CodeBlock';
+import Panel from "@site/src/components/Panel";
import ContentFrame from "@site/src/components/ContentFrame";
-Use the methods described in this page to customize the [conventions](../../../client-api/configuration/conventions.mdx)
-by which entities are serialized as they are sent by the client to the server.
-
-* In this page:
+* The C# client serializes entities into JSON using the
+ [Newtonsoft.Json](https://www.newtonsoft.com/json/help/html/SerializingJSON.htm) library (also known as Json.NET).
+* Use the [conventions](../../../client-api/configuration/conventions.mdx) described in this article
+ to customize the serialization (e.g., to exclude a property, or to control the JSON form of a type).
+* In this article:
* [Ignoring a property](../../../client-api/configuration/serialization.mdx#ignoring-a-property)
* [CustomizeJsonSerializer](../../../client-api/configuration/serialization.mdx#customizejsonserializer)
+ * [Adding a converter](../../../client-api/configuration/serialization.mdx#adding-a-converter)
+ * [Example: Storing a temperature as a string](../../../client-api/configuration/serialization.mdx#example-storing-a-temperature-as-a-string)
+ * [Example: Storing FHIR resources](../../../client-api/configuration/serialization.mdx#example-storing-fhir-resources)
* [JsonContractResolver](../../../client-api/configuration/serialization.mdx#jsoncontractresolver)
- * [BulkInsert.TrySerializeEntityToJsonStream](../../../client-api/configuration/serialization.mdx#bulkinserttryserializeentitytojsonstream)
+ * [BulkInsert.TrySerializeEntityToJsonStream](../../../client-api/configuration/serialization.mdx#bulkinsert-tryserializeentitytojsonstream)
* [IgnoreByRefMembers and IgnoreUnsafeMembers](../../../client-api/configuration/serialization.mdx#ignorebyrefmembers-and-ignoreunsafemembers)
-
-
-## Ignoring a property
+
* By default, RavenDB serializes **all** properties and **all** public fields of an entity.
-* Decorate a property with `[JsonIgnore]` to exclude it from serialization.
+* Decorate a property with `[JsonIgnore]` (from the `Newtonsoft.Json` namespace) to exclude it from serialization.
The decorated property will not be stored in the document and will not be available for indexing.
-* `[JsonIgnore]` is from the `Newtonsoft.Json` namespace.
+
+ ```csharp
+ public class Shirt
+ {
+ public string Id { get; set; }
+
+ // Stored in the document
+ public decimal Price { get; set; }
+
+ // Not stored - computed from Price at runtime
+ [JsonIgnore]
+ public decimal PriceWithTax => Price * 1.2m;
+ }
+ ```
+
+
+
+
+
+* The client uses `JsonSerializer` objects of the [Newtonsoft.Json](https://www.newtonsoft.com/json/help/html/SerializingJSON.htm)
+ library to **serialize** entities into JSON before sending the entities to the server,
+ and to **deserialize** documents loaded from the server back into entities.
+* Use the `CustomizeJsonSerializer` convention to register an action that modifies the `JsonSerializer` objects.
+ The client applies the registered action when storing entities as well as when loading documents into entities.
+ To customize only the deserialization of loaded documents, use the
+ [CustomizeJsonDeserializer](../../../client-api/configuration/deserialization.mdx#customizejsondeserializer) convention.
+
+ ```csharp
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ CustomizeJsonSerializer = serializer => throw new CodeOmitted()
+ }
+ }
+ ```
-```csharp
-public class Shirt
-{
- public string Id { get; set; }
+---
- // Stored in the document
- public decimal Price { get; set; }
+### Adding a converter
- // Not stored - computed from Price at runtime
- [JsonIgnore]
- public decimal PriceWithTax => Price * 1.2m;
-}
-```
+To control the JSON form of a specific type (e.g., to store a temperature as the string `"30C"`),
+add a **converter** for this type: a class that tells the `JsonSerializer` object how to serialize and deserialize the type.
+Learn more about converters in the Newtonsoft.Json [Custom JsonConverter](https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm) article.
-
+
----
+Define and register a converter as follows:
+
+1. Define a converter class derived from the library's `JsonConverter` class, with your type as `T`.
+2. Override the converter's `WriteJson` method to write the type's JSON form.
+ `WriteJson` receives a **writer** (a `JsonWriter` object) that writes JSON one element at a time,
+ e.g., the writer's `WriteValue` method writes a single value.
+
+ ```csharp
+ public override void WriteJson(JsonWriter writer, Temperature value, JsonSerializer serializer)
+ {
+ // Supported: WriteValue writes the string "30C" as a single JSON value
+ writer.WriteValue($"{value.Celsius}C");
+
+ // Not supported: WriteRaw would write "30C" as raw JSON text
+ // writer.WriteRaw($"\"{value.Celsius}C\"");
+ }
+ ```
+
+
+ The writer that the client provides does not support raw JSON text (a JSON string written in one piece),
+ so calling the writer's `WriteRaw` or `WriteRawValue` method throws a `NotSupportedException`.
+
+3. Override the converter's `ReadJson` method to convert the JSON form back into the type.
+4. In the action you register using `CustomizeJsonSerializer`,
+ add the converter to the `Converters` collection of the `JsonSerializer` object.
+
+
-## CustomizeJsonSerializer
+#### Example: Storing a temperature as a string
-* The `JsonSerializer` object is used by the client to serialize entities
- sent by the client to the server.
-* Use the `CustomizeJsonSerializer` convention to modify `JsonSerializer`
- by registering a serialization customization action.
+In the following example, a `WeatherReport` entity holds a `Temperature` object in its `Temp` property.
+A converter stores the `Temperature` object as a string (e.g., `"30C"`) rather than as a JSON object (e.g., `{"Celsius": 30}`).
```csharp
-Serialization = new NewtonsoftJsonSerializationConventions
+public class Temperature
{
- CustomizeJsonSerializer = serializer => throw new CodeOmitted()
+ public int Celsius { get; set; }
}
-```
-
+public class WeatherReport
+{
+ public string Id { get; set; }
+ public Temperature Temp { get; set; }
+}
----
+public class TemperatureConverter : JsonConverter
+{
+ public override void WriteJson(JsonWriter writer, Temperature value, JsonSerializer serializer)
+ {
+ writer.WriteValue($"{value.Celsius}C");
+ }
-
+ public override Temperature ReadJson(JsonReader reader, Type objectType, Temperature existingValue,
+ bool hasExistingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ return null;
-## JsonContractResolver
+ // Remove the trailing "C" and parse the number
+ var text = (string)reader.Value;
+ return new Temperature { Celsius = int.Parse(text.Substring(0, text.Length - 1)) };
+ }
+}
+```
+
-* The default `JsonContractResolver` convention used by RavenDB will serialize
- **all** properties and **all** public fields.
-* Change this behavior by providing your own implementation of the `IContractResolver`
- interface.
+The following code uses `CustomizeJsonSerializer` to register the `TemperatureConverter` class defined above,
+stores a `WeatherReport` document, and loads the document back.
+Since `CustomizeJsonSerializer` applies when loading documents as well, the same converter converts the stored string
+back into a `Temperature` object.
```csharp
-Serialization = new NewtonsoftJsonSerializationConventions
+using (var store = new DocumentStore
+{
+ Urls = new[] { "http://localhost:8080" },
+ Database = "Demo",
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ // Register the converter
+ CustomizeJsonSerializer = serializer => serializer.Converters.Add(new TemperatureConverter())
+ }
+ }
+}.Initialize())
{
- JsonContractResolver = new CustomJsonContractResolver()
+ using (var session = store.OpenSession())
+ {
+ // The document is stored with: "Temp": "30C"
+ session.Store(new WeatherReport { Temp = new Temperature { Celsius = 30 } }, "weatherReports/1");
+ session.SaveChanges();
+ }
+
+ using (var session = store.OpenSession())
+ {
+ // report.Temp is loaded back into a Temperature object with Celsius = 30
+ var report = session.Load("weatherReports/1");
+ }
}
```
+
+
+
+
+#### Example: Storing FHIR resources
+
+[FHIR](https://hl7.org/fhir/) (Fast Healthcare Interoperability Resources) is a standard for exchanging healthcare data,
+published by HL7.
+The [Firely .NET SDK](https://docs.fire.ly/projects/Firely-NET-SDK/en/latest/) provides .NET classes for FHIR resources
+(e.g., `Patient`), along with its own JSON serializer and parser for these classes.
+
+In the following example, a converter hands the serialization of FHIR resources to the SDK's serializer and parser,
+so a `Patient` resource is stored in FHIR's JSON format and loaded back into a `Patient` object.
+The converter's `WriteJson` method writes the serializer's output to the writer element by element,
+since the writer does not support [raw JSON text](../../../client-api/configuration/serialization.mdx#adding-a-converter).
+
```csharp
-public class CustomJsonContractResolver : IContractResolver
+using System;
+using System.IO;
+// Firely .NET SDK namespaces, from the Hl7.Fhir.R4 NuGet package
+using Hl7.Fhir.ElementModel;
+using Hl7.Fhir.Model;
+using Hl7.Fhir.Serialization;
+using Newtonsoft.Json;
+
+public class FhirResourceConverter : JsonConverter where T : Base
{
- public JsonContract ResolveContract(Type type)
+ // Skip JSON properties that the SDK's class does not define
+ // (e.g., the @metadata property of a loaded RavenDB document)
+ private static readonly PocoBuilderSettings BuilderSettings = new() { IgnoreUnknownMembers = true };
+
+ public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer)
+ {
+ // Serialize the resource using the SDK's serializer
+ var json = new FhirJsonSerializer().SerializeToString(value);
+
+ // Write the resulting JSON to the writer element by element,
+ // keeping dates and decimal values exactly as the SDK wrote them
+ using (var reader = new JsonTextReader(new StringReader(json))
+ { DateParseHandling = DateParseHandling.None, FloatParseHandling = FloatParseHandling.Decimal })
+ {
+ writer.WriteToken(reader);
+ }
+ }
+
+ public override T ReadJson(JsonReader reader, Type objectType, T existingValue,
+ bool hasExistingValue, JsonSerializer serializer)
{
- throw new CodeOmitted();
+ // Parse the stored JSON into the SDK's class
+ return FhirJsonNode.Read(reader).ToPoco(BuilderSettings);
}
}
```
+
-* You can also customize the behavior of the **default resolver** by inheriting
- from `DefaultRavenContractResolver` and overriding specific methods.
+The following code uses `CustomizeJsonSerializer` to register the converter class defined above for the `Patient` class
+(`FhirResourceConverter`), stores a `Patient` resource as a document, and loads the document back into a `Patient` object.
```csharp
-public class CustomizedRavenJsonContractResolver : DefaultRavenContractResolver
+using (var store = new DocumentStore
+{
+ Urls = new[] { "http://localhost:8080" },
+ Database = "Demo",
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ // Register a converter for each FHIR resource class you store
+ CustomizeJsonSerializer = serializer => serializer.Converters.Add(new FhirResourceConverter())
+ }
+ }
+}.Initialize())
{
- public CustomizedRavenJsonContractResolver(ISerializationConventions conventions) : base(conventions)
+ using (var session = store.OpenSession())
{
+ var patient = new Patient
+ {
+ // The resource ID is used as the document ID;
+ // FHIR IDs may contain only letters, digits, '-', and '.'
+ Id = "pat-1001",
+ Active = true,
+ Name = new List
+ {
+ new HumanName { Family = "Patel", Given = new List { "Sandeep" } }
+ }
+ };
+
+ session.Store(patient);
+ session.SaveChanges();
}
- protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
+ using (var session = store.OpenSession())
{
- throw new CodeOmitted();
+ // Loaded back into a Patient object
+ var patient = session.Load("pat-1001");
}
}
```
----
-
-
-
-## BulkInsert.TrySerializeEntityToJsonStream
+
-* Adjust [Bulk Insert](../../../client-api/bulk-insert/how-to-work-with-bulk-insert-operation.mdx)
- behavior by using the `TrySerializeEntityToJsonStream` convention to register a custom
- serialization implementation.
+
-```csharp
-BulkInsert =
-{
- TrySerializeEntityToJsonStream = (entity, metadata, writer) => throw new CodeOmitted(),
-}
-```
+* The default `JsonContractResolver` convention used by RavenDB will serialize
+ **all** properties and **all** public fields.
+* Change this behavior by providing your own implementation of the `IContractResolver`
+ interface.
+
+ ```csharp
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ JsonContractResolver = new CustomJsonContractResolver()
+ }
+ }
+ ```
+
+ ```csharp
+ public class CustomJsonContractResolver : IContractResolver
+ {
+ public JsonContract ResolveContract(Type type)
+ {
+ throw new CodeOmitted();
+ }
+ }
+ ```
+
+* You can also customize the behavior of the **default resolver** by inheriting
+ from `DefaultRavenContractResolver` and overriding specific methods.
+
+ ```csharp
+ public class CustomizedRavenJsonContractResolver : DefaultRavenContractResolver
+ {
+ public CustomizedRavenJsonContractResolver(ISerializationConventions conventions) : base(conventions)
+ {
+ }
-
+ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
+ {
+ throw new CodeOmitted();
+ }
+ }
+ ```
----
+
-
+
-## IgnoreByRefMembers and IgnoreUnsafeMembers
+* Adjust [Bulk Insert](../../../client-api/bulk-insert/how-to-work-with-bulk-insert-operation.mdx)
+ behavior by using the `TrySerializeEntityToJsonStream` convention to register a custom
+ serialization implementation.
+
+ ```csharp
+ Conventions =
+ {
+ BulkInsert =
+ {
+ TrySerializeEntityToJsonStream = (entity, metadata, writer) => throw new CodeOmitted(),
+ }
+ }
+ ```
+
+* The registered function receives the entity, the entity's metadata, and the writer of the bulk insert stream
+ (a `StreamWriter` object).
+ Return `true` after writing the entity to the writer as a JSON document, with the entity's metadata under the `@metadata` property.
+ To have the client serialize the entity using the default serialization instead, return `false` without writing to the writer.
+
+ ```csharp
+ Conventions =
+ {
+ BulkInsert =
+ {
+ TrySerializeEntityToJsonStream = (entity, metadata, writer) =>
+ {
+ // Let the client serialize entities of other types
+ if (entity is not User)
+ return false;
+
+ // Convert the entity into a JSON document
+ var document = JObject.FromObject(entity);
+
+ // Add the entity's metadata under the @metadata property
+ var metadataObject = new JObject();
+ foreach (var keyValue in metadata)
+ metadataObject.Add(keyValue.Key, new JValue(keyValue.Value));
+ document["@metadata"] = metadataObject;
+
+ // Write the document to the bulk insert stream
+ var jsonWriter = new JsonTextWriter(writer);
+ new JsonSerializer().Serialize(jsonWriter, document);
+ jsonWriter.Flush();
+
+ return true;
+ }
+ }
+ }
+ ```
+
+
+
+
* By default, if you try to store an entity with `ref` or unsafe members,
the Client will throw an exception when [`session.SaveChanges()`](../../../client-api/session/saving-changes.mdx)
@@ -149,4 +394,4 @@ BulkInsert =
* `IgnoreByRefMembers` default value: `false`
* `IgnoreUnsafeMembers` default value: `false`
-
+
diff --git a/versioned_docs/version-7.0/server/kb/numbers-in-ravendb.mdx b/versioned_docs/version-7.0/server/kb/numbers-in-ravendb.mdx
index aaba9fe80c..b1de23415d 100644
--- a/versioned_docs/version-7.0/server/kb/numbers-in-ravendb.mdx
+++ b/versioned_docs/version-7.0/server/kb/numbers-in-ravendb.mdx
@@ -158,9 +158,8 @@ Note that editing documents with numeric data outside of the precision range of
## Numbers in client API
-Numbers in RavenDB clients depend on the limitations of the platforms and the serialization/deserialization mechanisms. See articles in the desired languages:
-
-[Number (de)serialization](../../client-api/configuration/serialization.mdx#working-with-numbers)
+Numbers in RavenDB clients depend on the limitations of the platforms and the serialization/deserialization mechanisms.
+See [Conventions: Deserialization](../../client-api/configuration/deserialization.mdx)
diff --git a/versioned_docs/version-7.1/client-api/configuration/content/_deserialization-csharp.mdx b/versioned_docs/version-7.1/client-api/configuration/content/_deserialization-csharp.mdx
index b4191f5ca9..fb62d29d45 100644
Binary files a/versioned_docs/version-7.1/client-api/configuration/content/_deserialization-csharp.mdx and b/versioned_docs/version-7.1/client-api/configuration/content/_deserialization-csharp.mdx differ
diff --git a/versioned_docs/version-7.1/client-api/configuration/content/_serialization-csharp.mdx b/versioned_docs/version-7.1/client-api/configuration/content/_serialization-csharp.mdx
index 403f79e063..c1b30da8e0 100644
--- a/versioned_docs/version-7.1/client-api/configuration/content/_serialization-csharp.mdx
+++ b/versioned_docs/version-7.1/client-api/configuration/content/_serialization-csharp.mdx
@@ -1,139 +1,384 @@
import Admonition from '@theme/Admonition';
-import Tabs from '@theme/Tabs';
-import TabItem from '@theme/TabItem';
-import CodeBlock from '@theme/CodeBlock';
+import Panel from "@site/src/components/Panel";
import ContentFrame from "@site/src/components/ContentFrame";
-Use the methods described in this page to customize the [conventions](../../../client-api/configuration/conventions.mdx)
-by which entities are serialized as they are sent by the client to the server.
-
-* In this page:
+* The C# client serializes entities into JSON using the
+ [Newtonsoft.Json](https://www.newtonsoft.com/json/help/html/SerializingJSON.htm) library (also known as Json.NET).
+* Use the [conventions](../../../client-api/configuration/conventions.mdx) described in this article
+ to customize the serialization (e.g., to exclude a property, or to control the JSON form of a type).
+* In this article:
* [Ignoring a property](../../../client-api/configuration/serialization.mdx#ignoring-a-property)
* [CustomizeJsonSerializer](../../../client-api/configuration/serialization.mdx#customizejsonserializer)
+ * [Adding a converter](../../../client-api/configuration/serialization.mdx#adding-a-converter)
+ * [Example: Storing a temperature as a string](../../../client-api/configuration/serialization.mdx#example-storing-a-temperature-as-a-string)
+ * [Example: Storing FHIR resources](../../../client-api/configuration/serialization.mdx#example-storing-fhir-resources)
* [JsonContractResolver](../../../client-api/configuration/serialization.mdx#jsoncontractresolver)
- * [BulkInsert.TrySerializeEntityToJsonStream](../../../client-api/configuration/serialization.mdx#bulkinserttryserializeentitytojsonstream)
+ * [BulkInsert.TrySerializeEntityToJsonStream](../../../client-api/configuration/serialization.mdx#bulkinsert-tryserializeentitytojsonstream)
* [IgnoreByRefMembers and IgnoreUnsafeMembers](../../../client-api/configuration/serialization.mdx#ignorebyrefmembers-and-ignoreunsafemembers)
-
-
-## Ignoring a property
+
* By default, RavenDB serializes **all** properties and **all** public fields of an entity.
-* Decorate a property with `[JsonIgnore]` to exclude it from serialization.
+* Decorate a property with `[JsonIgnore]` (from the `Newtonsoft.Json` namespace) to exclude it from serialization.
The decorated property will not be stored in the document and will not be available for indexing.
-* `[JsonIgnore]` is from the `Newtonsoft.Json` namespace.
+
+ ```csharp
+ public class Shirt
+ {
+ public string Id { get; set; }
+
+ // Stored in the document
+ public decimal Price { get; set; }
+
+ // Not stored - computed from Price at runtime
+ [JsonIgnore]
+ public decimal PriceWithTax => Price * 1.2m;
+ }
+ ```
+
+
+
+
+
+* The client uses `JsonSerializer` objects of the [Newtonsoft.Json](https://www.newtonsoft.com/json/help/html/SerializingJSON.htm)
+ library to **serialize** entities into JSON before sending the entities to the server,
+ and to **deserialize** documents loaded from the server back into entities.
+* Use the `CustomizeJsonSerializer` convention to register an action that modifies the `JsonSerializer` objects.
+ The client applies the registered action when storing entities as well as when loading documents into entities.
+ To customize only the deserialization of loaded documents, use the
+ [CustomizeJsonDeserializer](../../../client-api/configuration/deserialization.mdx#customizejsondeserializer) convention.
+
+ ```csharp
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ CustomizeJsonSerializer = serializer => throw new CodeOmitted()
+ }
+ }
+ ```
-```csharp
-public class Shirt
-{
- public string Id { get; set; }
+---
- // Stored in the document
- public decimal Price { get; set; }
+### Adding a converter
- // Not stored - computed from Price at runtime
- [JsonIgnore]
- public decimal PriceWithTax => Price * 1.2m;
-}
-```
+To control the JSON form of a specific type (e.g., to store a temperature as the string `"30C"`),
+add a **converter** for this type: a class that tells the `JsonSerializer` object how to serialize and deserialize the type.
+Learn more about converters in the Newtonsoft.Json [Custom JsonConverter](https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm) article.
-
+
----
+Define and register a converter as follows:
+
+1. Define a converter class derived from the library's `JsonConverter` class, with your type as `T`.
+2. Override the converter's `WriteJson` method to write the type's JSON form.
+ `WriteJson` receives a **writer** (a `JsonWriter` object) that writes JSON one element at a time,
+ e.g., the writer's `WriteValue` method writes a single value.
+
+ ```csharp
+ public override void WriteJson(JsonWriter writer, Temperature value, JsonSerializer serializer)
+ {
+ // Supported: WriteValue writes the string "30C" as a single JSON value
+ writer.WriteValue($"{value.Celsius}C");
+
+ // Not supported: WriteRaw would write "30C" as raw JSON text
+ // writer.WriteRaw($"\"{value.Celsius}C\"");
+ }
+ ```
+
+
+ The writer that the client provides does not support raw JSON text (a JSON string written in one piece),
+ so calling the writer's `WriteRaw` or `WriteRawValue` method throws a `NotSupportedException`.
+
+3. Override the converter's `ReadJson` method to convert the JSON form back into the type.
+4. In the action you register using `CustomizeJsonSerializer`,
+ add the converter to the `Converters` collection of the `JsonSerializer` object.
+
+
-## CustomizeJsonSerializer
+#### Example: Storing a temperature as a string
-* The `JsonSerializer` object is used by the client to serialize entities
- sent by the client to the server.
-* Use the `CustomizeJsonSerializer` convention to modify `JsonSerializer`
- by registering a serialization customization action.
+In the following example, a `WeatherReport` entity holds a `Temperature` object in its `Temp` property.
+A converter stores the `Temperature` object as a string (e.g., `"30C"`) rather than as a JSON object (e.g., `{"Celsius": 30}`).
```csharp
-Serialization = new NewtonsoftJsonSerializationConventions
+public class Temperature
{
- CustomizeJsonSerializer = serializer => throw new CodeOmitted()
+ public int Celsius { get; set; }
}
-```
-
+public class WeatherReport
+{
+ public string Id { get; set; }
+ public Temperature Temp { get; set; }
+}
----
+public class TemperatureConverter : JsonConverter
+{
+ public override void WriteJson(JsonWriter writer, Temperature value, JsonSerializer serializer)
+ {
+ writer.WriteValue($"{value.Celsius}C");
+ }
-
+ public override Temperature ReadJson(JsonReader reader, Type objectType, Temperature existingValue,
+ bool hasExistingValue, JsonSerializer serializer)
+ {
+ if (reader.TokenType == JsonToken.Null)
+ return null;
-## JsonContractResolver
+ // Remove the trailing "C" and parse the number
+ var text = (string)reader.Value;
+ return new Temperature { Celsius = int.Parse(text.Substring(0, text.Length - 1)) };
+ }
+}
+```
+
-* The default `JsonContractResolver` convention used by RavenDB will serialize
- **all** properties and **all** public fields.
-* Change this behavior by providing your own implementation of the `IContractResolver`
- interface.
+The following code uses `CustomizeJsonSerializer` to register the `TemperatureConverter` class defined above,
+stores a `WeatherReport` document, and loads the document back.
+Since `CustomizeJsonSerializer` applies when loading documents as well, the same converter converts the stored string
+back into a `Temperature` object.
```csharp
-Serialization = new NewtonsoftJsonSerializationConventions
+using (var store = new DocumentStore
+{
+ Urls = new[] { "http://localhost:8080" },
+ Database = "Demo",
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ // Register the converter
+ CustomizeJsonSerializer = serializer => serializer.Converters.Add(new TemperatureConverter())
+ }
+ }
+}.Initialize())
{
- JsonContractResolver = new CustomJsonContractResolver()
+ using (var session = store.OpenSession())
+ {
+ // The document is stored with: "Temp": "30C"
+ session.Store(new WeatherReport { Temp = new Temperature { Celsius = 30 } }, "weatherReports/1");
+ session.SaveChanges();
+ }
+
+ using (var session = store.OpenSession())
+ {
+ // report.Temp is loaded back into a Temperature object with Celsius = 30
+ var report = session.Load("weatherReports/1");
+ }
}
```
+
+
+
+
+#### Example: Storing FHIR resources
+
+[FHIR](https://hl7.org/fhir/) (Fast Healthcare Interoperability Resources) is a standard for exchanging healthcare data,
+published by HL7.
+The [Firely .NET SDK](https://docs.fire.ly/projects/Firely-NET-SDK/en/latest/) provides .NET classes for FHIR resources
+(e.g., `Patient`), along with its own JSON serializer and parser for these classes.
+
+In the following example, a converter hands the serialization of FHIR resources to the SDK's serializer and parser,
+so a `Patient` resource is stored in FHIR's JSON format and loaded back into a `Patient` object.
+The converter's `WriteJson` method writes the serializer's output to the writer element by element,
+since the writer does not support [raw JSON text](../../../client-api/configuration/serialization.mdx#adding-a-converter).
+
```csharp
-public class CustomJsonContractResolver : IContractResolver
+using System;
+using System.IO;
+// Firely .NET SDK namespaces, from the Hl7.Fhir.R4 NuGet package
+using Hl7.Fhir.ElementModel;
+using Hl7.Fhir.Model;
+using Hl7.Fhir.Serialization;
+using Newtonsoft.Json;
+
+public class FhirResourceConverter : JsonConverter where T : Base
{
- public JsonContract ResolveContract(Type type)
+ // Skip JSON properties that the SDK's class does not define
+ // (e.g., the @metadata property of a loaded RavenDB document)
+ private static readonly PocoBuilderSettings BuilderSettings = new() { IgnoreUnknownMembers = true };
+
+ public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer)
+ {
+ // Serialize the resource using the SDK's serializer
+ var json = new FhirJsonSerializer().SerializeToString(value);
+
+ // Write the resulting JSON to the writer element by element,
+ // keeping dates and decimal values exactly as the SDK wrote them
+ using (var reader = new JsonTextReader(new StringReader(json))
+ { DateParseHandling = DateParseHandling.None, FloatParseHandling = FloatParseHandling.Decimal })
+ {
+ writer.WriteToken(reader);
+ }
+ }
+
+ public override T ReadJson(JsonReader reader, Type objectType, T existingValue,
+ bool hasExistingValue, JsonSerializer serializer)
{
- throw new CodeOmitted();
+ // Parse the stored JSON into the SDK's class
+ return FhirJsonNode.Read(reader).ToPoco(BuilderSettings);
}
}
```
+
-* You can also customize the behavior of the **default resolver** by inheriting
- from `DefaultRavenContractResolver` and overriding specific methods.
+The following code uses `CustomizeJsonSerializer` to register the converter class defined above for the `Patient` class
+(`FhirResourceConverter`), stores a `Patient` resource as a document, and loads the document back into a `Patient` object.
```csharp
-public class CustomizedRavenJsonContractResolver : DefaultRavenContractResolver
+using (var store = new DocumentStore
+{
+ Urls = new[] { "http://localhost:8080" },
+ Database = "Demo",
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ // Register a converter for each FHIR resource class you store
+ CustomizeJsonSerializer = serializer => serializer.Converters.Add(new FhirResourceConverter())
+ }
+ }
+}.Initialize())
{
- public CustomizedRavenJsonContractResolver(ISerializationConventions conventions) : base(conventions)
+ using (var session = store.OpenSession())
{
+ var patient = new Patient
+ {
+ // The resource ID is used as the document ID;
+ // FHIR IDs may contain only letters, digits, '-', and '.'
+ Id = "pat-1001",
+ Active = true,
+ Name = new List
+ {
+ new HumanName { Family = "Patel", Given = new List { "Sandeep" } }
+ }
+ };
+
+ session.Store(patient);
+ session.SaveChanges();
}
- protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
+ using (var session = store.OpenSession())
{
- throw new CodeOmitted();
+ // Loaded back into a Patient object
+ var patient = session.Load("pat-1001");
}
}
```
----
-
-
-
-## BulkInsert.TrySerializeEntityToJsonStream
+
-* Adjust [Bulk Insert](../../../client-api/bulk-insert/how-to-work-with-bulk-insert-operation.mdx)
- behavior by using the `TrySerializeEntityToJsonStream` convention to register a custom
- serialization implementation.
+
-```csharp
-BulkInsert =
-{
- TrySerializeEntityToJsonStream = (entity, metadata, writer) => throw new CodeOmitted(),
-}
-```
+* The default `JsonContractResolver` convention used by RavenDB will serialize
+ **all** properties and **all** public fields.
+* Change this behavior by providing your own implementation of the `IContractResolver`
+ interface.
+
+ ```csharp
+ Conventions =
+ {
+ Serialization = new NewtonsoftJsonSerializationConventions
+ {
+ JsonContractResolver = new CustomJsonContractResolver()
+ }
+ }
+ ```
+
+ ```csharp
+ public class CustomJsonContractResolver : IContractResolver
+ {
+ public JsonContract ResolveContract(Type type)
+ {
+ throw new CodeOmitted();
+ }
+ }
+ ```
+
+* You can also customize the behavior of the **default resolver** by inheriting
+ from `DefaultRavenContractResolver` and overriding specific methods.
+
+ ```csharp
+ public class CustomizedRavenJsonContractResolver : DefaultRavenContractResolver
+ {
+ public CustomizedRavenJsonContractResolver(ISerializationConventions conventions) : base(conventions)
+ {
+ }
-
+ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
+ {
+ throw new CodeOmitted();
+ }
+ }
+ ```
----
+
-
+
-## IgnoreByRefMembers and IgnoreUnsafeMembers
+* Adjust [Bulk Insert](../../../client-api/bulk-insert/how-to-work-with-bulk-insert-operation.mdx)
+ behavior by using the `TrySerializeEntityToJsonStream` convention to register a custom
+ serialization implementation.
+
+ ```csharp
+ Conventions =
+ {
+ BulkInsert =
+ {
+ TrySerializeEntityToJsonStream = (entity, metadata, writer) => throw new CodeOmitted(),
+ }
+ }
+ ```
+
+* The registered function receives the entity, the entity's metadata, and the writer of the bulk insert stream
+ (a `StreamWriter` object).
+ Return `true` after writing the entity to the writer as a JSON document, with the entity's metadata under the `@metadata` property.
+ To have the client serialize the entity using the default serialization instead, return `false` without writing to the writer.
+
+ ```csharp
+ Conventions =
+ {
+ BulkInsert =
+ {
+ TrySerializeEntityToJsonStream = (entity, metadata, writer) =>
+ {
+ // Let the client serialize entities of other types
+ if (entity is not User)
+ return false;
+
+ // Convert the entity into a JSON document
+ var document = JObject.FromObject(entity);
+
+ // Add the entity's metadata under the @metadata property
+ var metadataObject = new JObject();
+ foreach (var keyValue in metadata)
+ metadataObject.Add(keyValue.Key, new JValue(keyValue.Value));
+ document["@metadata"] = metadataObject;
+
+ // Write the document to the bulk insert stream
+ var jsonWriter = new JsonTextWriter(writer);
+ new JsonSerializer().Serialize(jsonWriter, document);
+ jsonWriter.Flush();
+
+ return true;
+ }
+ }
+ }
+ ```
+
+
+
+
* By default, if you try to store an entity with `ref` or unsafe members,
the Client will throw an exception when [`session.SaveChanges()`](../../../client-api/session/saving-changes.mdx)
@@ -149,4 +394,4 @@ BulkInsert =
* `IgnoreByRefMembers` default value: `false`
* `IgnoreUnsafeMembers` default value: `false`
-
+
diff --git a/versioned_docs/version-7.1/server/kb/numbers-in-ravendb.mdx b/versioned_docs/version-7.1/server/kb/numbers-in-ravendb.mdx
index aaba9fe80c..b1de23415d 100644
--- a/versioned_docs/version-7.1/server/kb/numbers-in-ravendb.mdx
+++ b/versioned_docs/version-7.1/server/kb/numbers-in-ravendb.mdx
@@ -158,9 +158,8 @@ Note that editing documents with numeric data outside of the precision range of
## Numbers in client API
-Numbers in RavenDB clients depend on the limitations of the platforms and the serialization/deserialization mechanisms. See articles in the desired languages:
-
-[Number (de)serialization](../../client-api/configuration/serialization.mdx#working-with-numbers)
+Numbers in RavenDB clients depend on the limitations of the platforms and the serialization/deserialization mechanisms.
+See [Conventions: Deserialization](../../client-api/configuration/deserialization.mdx)