From 9a1df479a3fc2d3ca26bf2139afc0649cdec0eac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Sep 2025 15:48:38 +0000 Subject: [PATCH 1/3] Initial plan From badd44a21ccb11827266983b9b8954ab79fd5a31 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Sep 2025 15:58:00 +0000 Subject: [PATCH 2/3] Add JsonObject Title property migration guidance and code examples Co-authored-by: gewarren <24882762+gewarren@users.noreply.github.com> --- .../system-text-json/extract-schema.md | 9 +++ .../migrate-from-newtonsoft.md | 18 ++++++ .../schema-exporter/JsonObjectTitleExample.cs | 59 +++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 docs/standard/serialization/system-text-json/snippets/schema-exporter/JsonObjectTitleExample.cs diff --git a/docs/standard/serialization/system-text-json/extract-schema.md b/docs/standard/serialization/system-text-json/extract-schema.md index addf82e24d349..80ed327bf929a 100644 --- a/docs/standard/serialization/system-text-json/extract-schema.md +++ b/docs/standard/serialization/system-text-json/extract-schema.md @@ -36,3 +36,12 @@ The following code example generates a schema that incorporates `description` ke :::code language="csharp" source="snippets/schema-exporter/TransformSchema.cs" id="2"::: :::code language="csharp" source="snippets/schema-exporter/TransformSchema.cs" id="Person"::: + +Similarly, you can set a custom title for the schema by modifying the schema node: + +:::code language="csharp" source="snippets/schema-exporter/JsonObjectTitleExample.cs" id="1"::: + +The following code example generates a schema that includes a `title` keyword: + +:::code language="csharp" source="snippets/schema-exporter/JsonObjectTitleExample.cs" id="2"::: +:::code language="csharp" source="snippets/schema-exporter/JsonObjectTitleExample.cs" id="Person"::: diff --git a/docs/standard/serialization/system-text-json/migrate-from-newtonsoft.md b/docs/standard/serialization/system-text-json/migrate-from-newtonsoft.md index a7d6f98e2bfe9..d4fb6792eb5a9 100644 --- a/docs/standard/serialization/system-text-json/migrate-from-newtonsoft.md +++ b/docs/standard/serialization/system-text-json/migrate-from-newtonsoft.md @@ -515,6 +515,24 @@ public class Person } ``` +Finally, consider the following example that uses `Newtonsoft.Json.JsonObjectAttribute` to specify a title for JSON schema generation: + +```csharp +[JsonObject(Title = "PersonTitle")] +public class Person { ... } +``` + +The `Title` property is used for JSON schema metadata and doesn't have a direct equivalent in System.Text.Json. Starting in .NET 9, you can use the to generate JSON schemas and customize the schema title using the delegate: + +:::code language="csharp" source="snippets/schema-exporter/JsonObjectTitleExample.cs" id="1"::: + +The following code example generates a schema that includes the `title` keyword: + +:::code language="csharp" source="snippets/schema-exporter/JsonObjectTitleExample.cs" id="2"::: +:::code language="csharp" source="snippets/schema-exporter/JsonObjectTitleExample.cs" id="Person"::: + +For OpenAPI scenarios, you can also set the schema title using document transformers or by directly manipulating the OpenAPI schema. For more information about JSON schema generation, see [JSON schema exporter](extract-schema.md). + ### TraceWriter `Newtonsoft.Json` lets you debug by using a `TraceWriter` to view logs that are generated by serialization or deserialization. doesn't do logging. diff --git a/docs/standard/serialization/system-text-json/snippets/schema-exporter/JsonObjectTitleExample.cs b/docs/standard/serialization/system-text-json/snippets/schema-exporter/JsonObjectTitleExample.cs new file mode 100644 index 0000000000000..3c6276c73e4bd --- /dev/null +++ b/docs/standard/serialization/system-text-json/snippets/schema-exporter/JsonObjectTitleExample.cs @@ -0,0 +1,59 @@ +using System; +using System.Diagnostics; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Schema; + +class JsonObjectTitleExample +{ + public static void RunIt() + { + // + JsonSchemaExporterOptions exporterOptions = new() + { + TransformSchemaNode = (context, schema) => + { + // Only set title for the root type (not properties) + if (context.PropertyInfo is null && context.TypeInfo.Type == typeof(Person)) + { + if (schema is not JsonObject jObj) + { + // Handle the case where the schema is a Boolean. + JsonValueKind valueKind = schema.GetValueKind(); + Debug.Assert(valueKind is JsonValueKind.True or JsonValueKind.False); + schema = jObj = new JsonObject(); + if (valueKind is JsonValueKind.False) + { + jObj.Add("not", true); + } + } + + // Set the title in the schema + jObj.Insert(0, "title", "PersonTitle"); + } + + return schema; + } + }; + // + + // + JsonSerializerOptions options = JsonSerializerOptions.Default; + JsonNode schema = options.GetJsonSchemaAsNode(typeof(Person), exporterOptions); + Console.WriteLine(schema.ToString()); + //{ + // "title": "PersonTitle", + // "type": ["object", "null"], + // "properties": { + // "Name": { "type": "string" }, + // "Age": { "type": "integer" } + // }, + // "required": ["Name", "Age"] + //} + // + } + + // + public record Person(string Name, int Age); + // +} \ No newline at end of file From a8fbf0ad7fb7dafbb615172748591f9e68d5a994 Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Thu, 4 Sep 2025 14:13:43 -0700 Subject: [PATCH 3/3] respond to feedback --- .../system-text-json/extract-schema.md | 9 --- .../migrate-from-newtonsoft.md | 13 +--- .../schema-exporter/JsonObjectTitleExample.cs | 59 ------------------- 3 files changed, 2 insertions(+), 79 deletions(-) delete mode 100644 docs/standard/serialization/system-text-json/snippets/schema-exporter/JsonObjectTitleExample.cs diff --git a/docs/standard/serialization/system-text-json/extract-schema.md b/docs/standard/serialization/system-text-json/extract-schema.md index 80ed327bf929a..addf82e24d349 100644 --- a/docs/standard/serialization/system-text-json/extract-schema.md +++ b/docs/standard/serialization/system-text-json/extract-schema.md @@ -36,12 +36,3 @@ The following code example generates a schema that incorporates `description` ke :::code language="csharp" source="snippets/schema-exporter/TransformSchema.cs" id="2"::: :::code language="csharp" source="snippets/schema-exporter/TransformSchema.cs" id="Person"::: - -Similarly, you can set a custom title for the schema by modifying the schema node: - -:::code language="csharp" source="snippets/schema-exporter/JsonObjectTitleExample.cs" id="1"::: - -The following code example generates a schema that includes a `title` keyword: - -:::code language="csharp" source="snippets/schema-exporter/JsonObjectTitleExample.cs" id="2"::: -:::code language="csharp" source="snippets/schema-exporter/JsonObjectTitleExample.cs" id="Person"::: diff --git a/docs/standard/serialization/system-text-json/migrate-from-newtonsoft.md b/docs/standard/serialization/system-text-json/migrate-from-newtonsoft.md index d4fb6792eb5a9..cd458b56d5d0d 100644 --- a/docs/standard/serialization/system-text-json/migrate-from-newtonsoft.md +++ b/docs/standard/serialization/system-text-json/migrate-from-newtonsoft.md @@ -463,7 +463,7 @@ In .NET 8 and later versions, you can set your preference for whether to skip or ### JsonObjectAttribute -`Newtonsoft.Json` has an attribute, `JsonObjectAttribute`, that can be applied at the *type level* to control which members are serialized, how `null` values are handled, and whether all members are required. System.Text.Json has no equivalent attribute that can be applied on a type. For some behaviors, such as `null` value handling, you can either configure the same behavior on the global or individually on each property. +`Newtonsoft.Json` has an attribute, `JsonObjectAttribute`, that can be applied at the *type level* to control which members are serialized, how `null` values are handled, and whether all members are required. System.Text.Json has no equivalent attribute that can be applied on a type. For some behaviors, such as `null` value handling, you can configure the same behavior either on the global or individually on each property using . Consider the following example that uses `Newtonsoft.Json.JsonObjectAttribute` to specify that all `null` properties should be ignored: @@ -522,16 +522,7 @@ Finally, consider the following example that uses `Newtonsoft.Json.JsonObjectAtt public class Person { ... } ``` -The `Title` property is used for JSON schema metadata and doesn't have a direct equivalent in System.Text.Json. Starting in .NET 9, you can use the to generate JSON schemas and customize the schema title using the delegate: - -:::code language="csharp" source="snippets/schema-exporter/JsonObjectTitleExample.cs" id="1"::: - -The following code example generates a schema that includes the `title` keyword: - -:::code language="csharp" source="snippets/schema-exporter/JsonObjectTitleExample.cs" id="2"::: -:::code language="csharp" source="snippets/schema-exporter/JsonObjectTitleExample.cs" id="Person"::: - -For OpenAPI scenarios, you can also set the schema title using document transformers or by directly manipulating the OpenAPI schema. For more information about JSON schema generation, see [JSON schema exporter](extract-schema.md). +The `Title` property is used for JSON schema metadata and doesn't have a direct equivalent in System.Text.Json. Starting in .NET 9, you can use the to generate JSON schemas and customize the schema title using the delegate. For an example, see [Transform the generated schema](extract-schema.md#transform-the-generated-schema). ### TraceWriter diff --git a/docs/standard/serialization/system-text-json/snippets/schema-exporter/JsonObjectTitleExample.cs b/docs/standard/serialization/system-text-json/snippets/schema-exporter/JsonObjectTitleExample.cs deleted file mode 100644 index 3c6276c73e4bd..0000000000000 --- a/docs/standard/serialization/system-text-json/snippets/schema-exporter/JsonObjectTitleExample.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Diagnostics; -using System.Text.Json; -using System.Text.Json.Nodes; -using System.Text.Json.Schema; - -class JsonObjectTitleExample -{ - public static void RunIt() - { - // - JsonSchemaExporterOptions exporterOptions = new() - { - TransformSchemaNode = (context, schema) => - { - // Only set title for the root type (not properties) - if (context.PropertyInfo is null && context.TypeInfo.Type == typeof(Person)) - { - if (schema is not JsonObject jObj) - { - // Handle the case where the schema is a Boolean. - JsonValueKind valueKind = schema.GetValueKind(); - Debug.Assert(valueKind is JsonValueKind.True or JsonValueKind.False); - schema = jObj = new JsonObject(); - if (valueKind is JsonValueKind.False) - { - jObj.Add("not", true); - } - } - - // Set the title in the schema - jObj.Insert(0, "title", "PersonTitle"); - } - - return schema; - } - }; - // - - // - JsonSerializerOptions options = JsonSerializerOptions.Default; - JsonNode schema = options.GetJsonSchemaAsNode(typeof(Person), exporterOptions); - Console.WriteLine(schema.ToString()); - //{ - // "title": "PersonTitle", - // "type": ["object", "null"], - // "properties": { - // "Name": { "type": "string" }, - // "Age": { "type": "integer" } - // }, - // "required": ["Name", "Age"] - //} - // - } - - // - public record Person(string Name, int Age); - // -} \ No newline at end of file