Skip to content

Commit 56cba82

Browse files
authored
Add JSON schema exporter article (#43074)
1 parent 97fa15d commit 56cba82

File tree

11 files changed

+290
-77
lines changed

11 files changed

+290
-77
lines changed

docs/fundamentals/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,8 @@ items:
785785
href: ../standard/serialization/system-text-json/converters-how-to.md
786786
- name: Customize contracts
787787
href: ../standard/serialization/system-text-json/custom-contracts.md
788+
- name: Extract JSON schema
789+
href: ../standard/serialization/system-text-json/json-schema-exporter.md
788790
- name: XML and SOAP serialization
789791
items:
790792
- name: Overview

docs/standard/serialization/system-text-json/character-casing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ ms.topic: how-to
1616

1717
# How to enable case-insensitive property name matching with System.Text.Json
1818

19-
In this article, you will learn how to enable case-insensitive property name matching with the `System.Text.Json` namespace.
19+
In this article, you learn how to enable case-insensitive property name matching with the `System.Text.Json` namespace.
2020

2121
## Case-insensitive property matching
2222

docs/standard/serialization/system-text-json/character-encoding.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ By default, the serializer escapes all non-ASCII characters. That is, it replace
2828

2929
## Serialize language character sets
3030

31-
To serialize the character set(s) of one or more languages without escaping, specify [Unicode range(s)](xref:System.Text.Unicode.UnicodeRanges) when creating an instance of <xref:System.Text.Encodings.Web.JavaScriptEncoder?displayProperty=fullName>, as shown in the following example:
31+
To serialize the character sets of one or more languages without escaping, specify [Unicode ranges](xref:System.Text.Unicode.UnicodeRanges) when creating an instance of <xref:System.Text.Encodings.Web.JavaScriptEncoder?displayProperty=fullName>, as shown in the following example:
3232

3333
:::code language="csharp" source="snippets/how-to/csharp/SerializeCustomEncoding.cs" id="Usings":::
3434
:::code language="vb" source="snippets/how-to/vb/SerializeCustomEncoding.vb" id="Usings":::
@@ -86,7 +86,7 @@ Examples of encoder-specific blocked code points include `'<'` and `'&'` for the
8686

8787
## Serialize all characters
8888

89-
To minimize escaping you can use <xref:System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping?displayProperty=nameWithType>, as shown in the following example:
89+
To minimize escaping, you can use <xref:System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping?displayProperty=nameWithType>, as shown in the following example:
9090

9191
:::code language="csharp" source="snippets/how-to/csharp/SerializeCustomEncoding.cs" id="Usings":::
9292
:::code language="vb" source="snippets/how-to/vb/SerializeCustomEncoding.vb" id="Usings":::

docs/standard/serialization/system-text-json/configure-options.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ The following options have different defaults for web apps:
6262
* <xref:System.Text.Json.JsonSerializerOptions.PropertyNamingPolicy> = <xref:System.Text.Json.JsonNamingPolicy.CamelCase>
6363
* <xref:System.Text.Json.JsonSerializerOptions.NumberHandling%2A> = <xref:System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString>
6464

65-
In .NET 9 and later versions, you can use the `JsonSerializerOptions.Web` <!-- <xref:System.Text.Json.JsonSerializerOptions.Web?displayProperty=nameWithType> --> singleton to serialize with the default options that ASP.NET Core uses for web apps. In earlier versions, call the [JsonSerializerOptions constructor](xref:System.Text.Json.JsonSerializerOptions.%23ctor(System.Text.Json.JsonSerializerDefaults)) to create a new instance with the web defaults, as shown in the following example:
65+
In .NET 9 and later versions, you can use the <xref:System.Text.Json.JsonSerializerOptions.Web?displayProperty=nameWithType> singleton to serialize with the default options that ASP.NET Core uses for web apps. In earlier versions, call the [JsonSerializerOptions constructor](xref:System.Text.Json.JsonSerializerOptions.%23ctor(System.Text.Json.JsonSerializerDefaults)) to create a new instance with the web defaults, as shown in the following example:
6666

6767
:::code language="csharp" source="snippets/how-to-contd/csharp/OptionsDefaults.cs" highlight="23":::
6868
:::code language="vb" source="snippets/how-to-contd/vb/OptionsDefaults.vb" :::

docs/standard/serialization/system-text-json/handle-overflow.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ ms.topic: how-to
1616

1717
# How to handle overflow JSON or use JsonElement or JsonNode in System.Text.Json
1818

19-
This article shows how to handle overflow JSON with the [`System.Text.Json`](xref:System.Text.Json) namespace. It also shows how to deserialize into <xref:System.Text.Json.JsonElement> or <xref:System.Text.Json.Nodes.JsonNode>, as an alternative for other scenarios where the target type might not perfectly match all of the JSON being deserialized.
19+
This article shows how to handle overflow JSON with the <xref:System.Text.Json> namespace. It also shows how to deserialize into <xref:System.Text.Json.JsonElement> or <xref:System.Text.Json.Nodes.JsonNode>, as an alternative for other scenarios where the target type might not perfectly match all of the JSON being deserialized.
2020

2121
## Handle overflow JSON
2222

@@ -51,12 +51,12 @@ If you deserialize the JSON shown into the type shown, the `DatesAvailable` and
5151

5252
The following table shows the result of deserializing the JSON shown earlier into this sample type. The extra data becomes key-value pairs of the `ExtensionData` property:
5353

54-
| Property | Value | Notes |
55-
|--|--|--|
56-
| `Date` | `"8/1/2019 12:00:00 AM -07:00"` | |
54+
| Property | Value | Notes |
55+
|-----------|---------------------------------|-------|
56+
| `Date` | `"8/1/2019 12:00:00 AM -07:00"` | |
5757
| `TemperatureCelsius` | `0` | Case-sensitive mismatch (`temperatureCelsius` in the JSON), so the property isn't set. |
58-
| `Summary` | `"Hot"` | |
59-
| `ExtensionData` | `"temperatureCelsius": 25,`<br>`"DatesAvailable": ["2019-08-01T00:00:00-07:00","2019-08-02T00:00:00-07:00"],`<br>`"SummaryWords": ["Cool","Windy","Humid"]`| Since the case didn't match, `temperatureCelsius` is an extra and becomes a key-value pair in the dictionary. <br>Each extra array from the JSON becomes a key-value pair, with an array as the value object.|
58+
| `Summary` | `"Hot"` | |
59+
| `ExtensionData` | `"temperatureCelsius": 25,`<br>`"DatesAvailable": ["2019-08-01T00:00:00-07:00","2019-08-02T00:00:00-07:00"],`<br>`"SummaryWords": ["Cool","Windy","Humid"]` | Since the case didn't match, `temperatureCelsius` is an extra and becomes a key-value pair in the dictionary. <br>Each extra array from the JSON becomes a key-value pair, with an array as the value object. |
6060

6161
When the target object is serialized, the extension data key value pairs become JSON properties just as they were in the incoming JSON:
6262

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
title: JSON schema exporter
3+
description: Learn how to use the JsonSchemaExporter class to extract JSON schema documents from .NET types.
4+
ms.date: 10/15/2024
5+
dev_langs:
6+
- "csharp"
7+
---
8+
9+
# JSON schema exporter
10+
11+
The new <xref:System.Text.Json.Schema.JsonSchemaExporter> class lets you extract [JSON schema](https://json-schema.org/) documents from .NET types using either a <xref:System.Text.Json.JsonSerializerOptions> or <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfo> instance. The resultant schema provides a specification of the JSON serialization contract for the type.
12+
13+
The following code snippet shows an example.
14+
15+
:::code language="csharp" source="snippets/schema-exporter/ExportSchema.cs" id="1":::
16+
17+
As can be seen in this example, the exporter distinguishes between nullable and non-nullable properties, and it populates the `required` keyword by virtue of a constructor parameter being optional or not.
18+
19+
## Configure the schema output
20+
21+
You can influence the schema output by configuration specified in the <xref:System.Text.Json.JsonSerializerOptions> or <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfo> instance that you call the <xref:System.Text.Json.Schema.JsonSchemaExporter.GetJsonSchemaAsNode*> method on. The following example sets the naming policy to <xref:System.Text.Json.JsonNamingPolicy.KebabCaseUpper>, writes numbers as strings, and disallows unmapped properties.
22+
23+
:::code language="csharp" source="snippets/schema-exporter/ExportSchema.cs" id="2":::
24+
25+
You can further control the generated schema using the <xref:System.Text.Json.Schema.JsonSchemaExporterOptions> configuration type. The following example sets the <xref:System.Text.Json.Schema.JsonSchemaExporterOptions.TreatNullObliviousAsNonNullable> property to `true` to mark root-level types as non-nullable.
26+
27+
:::code language="csharp" source="snippets/schema-exporter/ExportSchema.cs" id="3":::
28+
29+
## Transform the generated schema
30+
31+
You can apply your own transformations to generated schema nodes by specifying a <xref:System.Text.Json.Schema.JsonSchemaExporterOptions.TransformSchemaNode> delegate. The following example incorporates text from <xref:System.ComponentModel.DescriptionAttribute> annotations into the generated schema.
32+
33+
:::code language="csharp" source="snippets/schema-exporter/TransformSchema.cs" id="1":::
34+
35+
The following code example generates a schema that incorporates `description` keyword source from <xref:System.ComponentModel.DescriptionAttribute> annotations:
36+
37+
:::code language="csharp" source="snippets/schema-exporter/TransformSchema.cs" id="2":::
38+
:::code language="csharp" source="snippets/schema-exporter/TransformSchema.cs" id="Person":::

docs/standard/serialization/system-text-json/migrate-from-newtonsoft.md

Lines changed: 67 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -29,82 +29,18 @@ The `System.Text.Json` namespace provides functionality for serializing to and d
2929
3030
`System.Text.Json` focuses primarily on performance, security, and standards compliance. It has some key differences in default behavior and doesn't aim to have feature parity with `Newtonsoft.Json`. For some scenarios, `System.Text.Json` currently has no built-in functionality, but there are recommended workarounds. For other scenarios, workarounds are impractical.
3131

32-
We're investing in adding the features that are most often requested. If your application depends on a missing feature, consider [filing an issue](https://github.com/dotnet/runtime/issues/new) in the dotnet/runtime GitHub repository to find out if support for your scenario can be added.
32+
The `System.Text.Json` team is investing in adding the features that are most often requested. If your application depends on a missing feature, consider [filing an issue](https://github.com/dotnet/runtime/issues/new) in the dotnet/runtime GitHub repository to find out if support for your scenario can be added.
3333

3434
Most of this article is about how to use the <xref:System.Text.Json.JsonSerializer> API, but it also includes guidance on how to use the <xref:System.Text.Json.JsonDocument> (which represents the Document Object Model or DOM), <xref:System.Text.Json.Utf8JsonReader>, and <xref:System.Text.Json.Utf8JsonWriter> types.
3535

3636
In Visual Basic, you can't use <xref:System.Text.Json.Utf8JsonReader>, which also means you can't write custom converters. Most of the workarounds presented here require that you write custom converters. You can write a custom converter in C# and register it in a Visual Basic project. For more information, see [Visual Basic support](visual-basic-support.md).
3737

38-
## Use GitHub Copilot to migrate
39-
40-
You can get coding help from GitHub Copilot to convert your code within your IDE.
41-
42-
If you're using [Visual Studio 2022 version 17.8 or later](/visualstudio/releases/2022/release-notes), you can try the AI-driven [GitHub Copilot in Visual Studio](/visualstudio/ide/visual-studio-github-copilot-install-and-states) to help migrate your `Newtonsoft.Json` code to use `System.Text.Json`. Submit your question and the code to convert as a prompt in the copilot chat window, as in the following example.
43-
44-
>[!NOTE]
45-
>GitHub Copilot is powered by AI, so surprises and mistakes are possible. Make sure to verify any generated code or suggestions. For more information about the general use of GitHub Copilot, product impact, human oversight, and privacy, see [GitHub Copilot FAQs](https://github.com/features/copilot#faq).
46-
47-
**Example prompt for Copilot Chat**
48-
49-
```
50-
convert the following code to use System.Text.Json
51-
Product product = new Product();
52-
53-
product.Name = "Apple";
54-
product.ExpiryDate = new DateTime(2024, 08, 08);
55-
product.Price = 3.99M;
56-
product.Sizes = new string[] { "Small", "Medium", "Large" };
57-
58-
string output = JsonConvert.SerializeObject(product);
59-
Console.WriteLine(output);
60-
```
61-
62-
**Example Copilot Chat response**
63-
64-
```output
65-
To convert the code to use System.Text.Json, you can use the JsonSerializer class. Here's the updated code:
66-
using System;
67-
using System.Text.Json;
68-
69-
public class Product
70-
{
71-
public string Name { get; set; }
72-
public DateTime ExpiryDate { get; set; }
73-
public decimal Price { get; set; }
74-
public string[] Sizes { get; set; }
75-
}
76-
77-
public class Program
78-
{
79-
public static void Main()
80-
{
81-
Product product = new Product();
82-
83-
product.Name = "Apple";
84-
product.ExpiryDate = new DateTime(2024, 08, 08);
85-
product.Price = 3.99M;
86-
product.Sizes = new string[] { "Small", "Medium", "Large" };
87-
88-
string output = JsonSerializer.Serialize(product);
89-
Console.WriteLine(output);
90-
}
91-
}
92-
This code uses System.Text.Json.JsonSerializer.Serialize to convert the Product object to a JSON string.
93-
```
94-
95-
Note that your results might be different from what is shown in these example responses. AI models are non-deterministic, which means that they can return different responses when asked the same question. This might be due to additional learning and adaption over time, language variation, changes in context, such as your chat history, and more.
96-
97-
:::image type="content" source="./media/migrate-newtonsoft-json-using-github-copilot.gif" alt-text="Animated screenshot that shows using GitHub Copilot Chat in Visual Studio to migrate from newtonsoft" lightbox="./media/migrate-newtonsoft-json-using-github-copilot.gif":::
98-
99-
You can use chat features, such as [slash commands, references, and threads](/visualstudio/ide/copilot-chat-context), to set intent and get better answers with scoped context.
100-
For example, if your code file `filename` is open in the IDE, you can [reference the file](/visualstudio/ide/copilot-chat-context#reference-a-file) in your prompt to Copilot Chat with "convert `#filename` to use `System.Text.Json`". Or you can [reference the solution](/visualstudio/ide/copilot-chat-context#reference-the-entire-solution) with "convert `@workspace` to use `System.Text.Json`" in the chat window or in inline chat.
101-
10238
## Table of differences
10339

10440
The following table lists `Newtonsoft.Json` features and `System.Text.Json` equivalents. The equivalents fall into the following categories:
10541

106-
* ✔️ Supported by built-in functionality. Getting similar behavior from `System.Text.Json` may require the use of an attribute or global option.
107-
* ⚠️ Not supported, but workaround is possible. The workarounds are [custom converters](converters-how-to.md), which may not provide complete parity with `Newtonsoft.Json` functionality. For some of these, sample code is provided as examples. If you rely on these `Newtonsoft.Json` features, migration will require modifications to your .NET object models or other code changes.
42+
* ✔️ Supported by built-in functionality. Getting similar behavior from `System.Text.Json` might require the use of an attribute or global option.
43+
* ⚠️ Not supported, but workaround is possible. The workarounds are [custom converters](converters-how-to.md), which might not provide complete parity with `Newtonsoft.Json` functionality. For some of these, sample code is provided as examples. If you rely on these `Newtonsoft.Json` features, migration will require modifications to your .NET object models or other code changes.
10844
* ❌ Not supported, and workaround is not practical or possible. If you rely on these `Newtonsoft.Json` features, migration will not be possible without significant changes.
10945

11046
::: zone pivot="dotnet-9-0, dotnet-8-0"
@@ -895,6 +831,70 @@ System.Text.Json sets limits that can't be changed for some values, such as the
895831

896832
Newtonsoft parses `NaN`, `Infinity`, and `-Infinity` JSON string tokens. With System.Text.Json, use <xref:System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals?displayProperty=nameWithType>. For information about how to use this setting, see [Allow or write numbers in quotes](invalid-json.md#allow-or-write-numbers-in-quotes).
897833

834+
## Use GitHub Copilot to migrate
835+
836+
You can get coding help from GitHub Copilot to convert your code within your IDE.
837+
838+
If you're using [Visual Studio 2022 version 17.8 or later](/visualstudio/releases/2022/release-notes), you can try the AI-driven [GitHub Copilot in Visual Studio](/visualstudio/ide/visual-studio-github-copilot-install-and-states) to help migrate your `Newtonsoft.Json` code to use `System.Text.Json`. Submit your question and the code to convert as a prompt in the copilot chat window, as in the following example.
839+
840+
> [!NOTE]
841+
> GitHub Copilot is powered by AI, so surprises and mistakes are possible. Make sure to verify any generated code or suggestions. For more information about the general use of GitHub Copilot, product impact, human oversight, and privacy, see [GitHub Copilot FAQs](https://github.com/features/copilot#faq).
842+
843+
**Example prompt for Copilot Chat**
844+
845+
```
846+
convert the following code to use System.Text.Json
847+
Product product = new Product();
848+
849+
product.Name = "Apple";
850+
product.ExpiryDate = new DateTime(2024, 08, 08);
851+
product.Price = 3.99M;
852+
product.Sizes = new string[] { "Small", "Medium", "Large" };
853+
854+
string output = JsonConvert.SerializeObject(product);
855+
Console.WriteLine(output);
856+
```
857+
858+
**Example Copilot Chat response**
859+
860+
```output
861+
To convert the code to use System.Text.Json, you can use the JsonSerializer class. Here's the updated code:
862+
using System;
863+
using System.Text.Json;
864+
865+
public class Product
866+
{
867+
public string Name { get; set; }
868+
public DateTime ExpiryDate { get; set; }
869+
public decimal Price { get; set; }
870+
public string[] Sizes { get; set; }
871+
}
872+
873+
public class Program
874+
{
875+
public static void Main()
876+
{
877+
Product product = new Product();
878+
879+
product.Name = "Apple";
880+
product.ExpiryDate = new DateTime(2024, 08, 08);
881+
product.Price = 3.99M;
882+
product.Sizes = new string[] { "Small", "Medium", "Large" };
883+
884+
string output = JsonSerializer.Serialize(product);
885+
Console.WriteLine(output);
886+
}
887+
}
888+
This code uses System.Text.Json.JsonSerializer.Serialize to convert the Product object to a JSON string.
889+
```
890+
891+
Note that your results might be different from what is shown in these example responses. AI models are non-deterministic, which means that they can return different responses when asked the same question. This might be due to additional learning and adaption over time, language variation, changes in context, such as your chat history, and more.
892+
893+
:::image type="content" source="./media/migrate-newtonsoft-json-using-github-copilot.gif" alt-text="Animated screenshot that shows using GitHub Copilot Chat in Visual Studio to migrate from newtonsoft" lightbox="./media/migrate-newtonsoft-json-using-github-copilot.gif":::
894+
895+
You can use chat features, such as [slash commands, references, and threads](/visualstudio/ide/copilot-chat-context), to set intent and get better answers with scoped context.
896+
For example, if your code file `filename` is open in the IDE, you can [reference the file](/visualstudio/ide/copilot-chat-context#reference-a-file) in your prompt to Copilot Chat with "convert `#filename` to use `System.Text.Json`". Or you can [reference the solution](/visualstudio/ide/copilot-chat-context#reference-the-entire-solution) with "convert `@workspace` to use `System.Text.Json`" in the chat window or in inline chat.
897+
898898
## Additional resources
899899

900900
* [System.Text.Json overview](overview.md)

0 commit comments

Comments
 (0)