From 5a3ab5de841bcbc6e6db2580e8f894a2efb81154 Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Sun, 31 Aug 2025 00:03:38 +0200 Subject: [PATCH 01/10] Use Net.Http.Json extension method GetFromJsonAsync instead of JsonSerializer --- docs/csharp/tutorials/console-webapiclient.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docs/csharp/tutorials/console-webapiclient.md b/docs/csharp/tutorials/console-webapiclient.md index 442e0c2c7d86c..4a5563cca0024 100644 --- a/docs/csharp/tutorials/console-webapiclient.md +++ b/docs/csharp/tutorials/console-webapiclient.md @@ -121,7 +121,7 @@ Use the class to make HTTP requests. class to deserialize JSON into objects. +The following steps simplify the approach to fetching the data and processing it. You will use the extension method that's part of the [📦 System.Net.Http.Json](https://www.nuget.org/packages/System.Net.Http.Json) NuGet package to fetch and deserialize the JSON results into objects. 1. Create a file named *Repository.cs* and add the following code: @@ -135,21 +135,17 @@ The following steps convert the JSON response into C# objects. You use the in the `ProcessRepositoriesAsync` method with the following lines: +1. Use the method to fetch and convert JSON into C# objects. Replace the call to in the `ProcessRepositoriesAsync` method with the following lines: ```csharp - await using Stream stream = - await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos"); - var repositories = - await JsonSerializer.DeserializeAsync>(stream); + var repositories = await client.GetFromJsonAsync>("https://api.github.com/orgs/dotnet/repos"); ``` - The updated code replaces with . This serializer method uses a stream instead of a string as its source. + The updated code replaces with . This `GetFromJsonAsync` method - The first argument to is an `await` expression. `await` expressions can appear almost anywhere in your code, even though up to now, you've only seen them as part of an assignment statement. The other two parameters, `JsonSerializerOptions` and `CancellationToken`, are optional and are omitted in the code snippet. + The first argument to `GetFromJsonAsync` method is an `await` expression. `await` expressions can appear almost anywhere in your code, even though up to now, you've only seen them as part of an assignment statement. The next parameter, `requestUri` is optional and doesn't have to be provided if was already specified when creating the `client` object. You didn't provide the `client` object with the URI to send request to, so you specified the URI now. The last optional parameter, the `CancellationToken` is omitted in the code snippet. - The `DeserializeAsync` method is [*generic*](../fundamentals/types/generics.md), which means you supply type arguments for what kind of objects should be created from the JSON text. In this example, you're deserializing to a `List`, which is another generic object, a . The `List` class stores a collection of objects. The type argument declares the type of objects stored in the `List`. The type argument is your `Repository` record, because the JSON text represents a collection of repository objects. + The `GetFromJsonAsync` method is [*generic*](../fundamentals/types/generics.md), which means you supply type arguments for what kind of objects should be created from the fetched JSON text. In this example, you're deserializing to a `List`, which is another generic object, a . The `List` class stores a collection of objects. The type argument declares the type of objects stored in the `List`. The type argument is your `Repository` record, because the JSON text represents a collection of repository objects. 1. Add code to display the name of each repository. Replace the lines that read: @@ -168,7 +164,7 @@ The following steps convert the JSON response into C# objects. You use the Date: Sun, 31 Aug 2025 00:08:59 +0200 Subject: [PATCH 02/10] Remove configuring the deserialization --- docs/csharp/tutorials/console-webapiclient.md | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/docs/csharp/tutorials/console-webapiclient.md b/docs/csharp/tutorials/console-webapiclient.md index 4a5563cca0024..be890e09bd507 100644 --- a/docs/csharp/tutorials/console-webapiclient.md +++ b/docs/csharp/tutorials/console-webapiclient.md @@ -175,33 +175,6 @@ The following steps simplify the approach to fetching the data and processing it The output is a list of the names of the repositories that are part of the .NET Foundation. -## Configure deserialization - -1. In *Repository.cs*, replace the file contents with the following C#. - - ```csharp - using System.Text.Json.Serialization; - - public record class Repository( - [property: JsonPropertyName("name")] string Name); - ``` - - This code: - - * Changes the name of the `name` property to `Name`. - * Adds the to specify how this property appears in the JSON. - -1. In *Program.cs*, update the code to use the new capitalization of the `Name` property: - - ```csharp - foreach (var repo in repositories) - Console.Write(repo.Name); - ``` - -1. Run the app. - - The output is the same. - ## Refactor the code The `ProcessRepositoriesAsync` method can do the async work and return a collection of the repositories. Change that method to return `Task>`, and move the code that writes to the console near its caller. From ab528a4ab9227e15417d983670b57dfea58b63ef Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Sun, 31 Aug 2025 00:12:55 +0200 Subject: [PATCH 03/10] Capitalize the Name property --- docs/csharp/tutorials/console-webapiclient.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/docs/csharp/tutorials/console-webapiclient.md b/docs/csharp/tutorials/console-webapiclient.md index be890e09bd507..d05a85f1a857b 100644 --- a/docs/csharp/tutorials/console-webapiclient.md +++ b/docs/csharp/tutorials/console-webapiclient.md @@ -126,14 +126,14 @@ The following steps simplify the approach to fetching the data and processing it 1. Create a file named *Repository.cs* and add the following code: ```csharp - public record class Repository(string name); + public record class Repository(string Name); ``` The preceding code defines a class to represent the JSON object returned from the GitHub API. You'll use this class to display a list of repository names. - The JSON for a repository object contains dozens of properties, but only the `name` property will be deserialized. The serializer automatically ignores JSON properties for which there is no match in the target class. This feature makes it easier to create types that work with only a subset of fields in a large JSON packet. + The JSON for a repository object contains dozens of properties, but only the `Name` property will be deserialized. The serializer automatically ignores JSON properties for which there is no match in the target class. This feature makes it easier to create types that work with only a subset of fields in a large JSON packet. - The C# convention is to [capitalize the first letter of property names](../../standard/design-guidelines/capitalization-conventions.md), but the `name` property here starts with a lowercase letter because that matches exactly what's in the JSON. Later you'll see how to use C# property names that don't match the JSON property names. + The C# convention is to [capitalize the first letter of property names](../../standard/design-guidelines/capitalization-conventions.md). 1. Use the method to fetch and convert JSON into C# objects. Replace the call to in the `ProcessRepositoriesAsync` method with the following lines: @@ -157,7 +157,7 @@ The following steps simplify the approach to fetching the data and processing it ```csharp foreach (var repo in repositories ?? Enumerable.Empty()) - Console.Write(repo.name); + Console.Write(repo.Name); ``` 1. The following `using` directives should be present at the top of the file: @@ -188,10 +188,7 @@ The `ProcessRepositoriesAsync` method can do the async work and return a collect 1. Return the repositories after processing the JSON response: ```csharp - await using Stream stream = - await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos"); - var repositories = - await JsonSerializer.DeserializeAsync>(stream); + var repositories = await client.GetFromJsonAsync>("https://api.github.com/orgs/dotnet/repos"); return repositories ?? new(); ``` From 29948883ff1debf8faeb943a04794516323fabb2 Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Sun, 31 Aug 2025 00:16:56 +0200 Subject: [PATCH 04/10] Update Repository class --- docs/csharp/tutorials/console-webapiclient.md | 12 +++++++----- .../tutorials/snippets/WebAPIClient/Program.cs | 9 +++------ .../snippets/WebAPIClient/Repository.cs | 17 ++++++++--------- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/docs/csharp/tutorials/console-webapiclient.md b/docs/csharp/tutorials/console-webapiclient.md index d05a85f1a857b..8669ab4ebe6b7 100644 --- a/docs/csharp/tutorials/console-webapiclient.md +++ b/docs/csharp/tutorials/console-webapiclient.md @@ -217,11 +217,13 @@ The following steps add code to process more of the properties in the received J using System.Text.Json.Serialization; public record class Repository( - [property: JsonPropertyName("name")] string Name, - [property: JsonPropertyName("description")] string Description, - [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl, - [property: JsonPropertyName("homepage")] Uri Homepage, - [property: JsonPropertyName("watchers")] int Watchers); + string Name, + string Description, + Uri GitHubHomeUrl, + Uri Homepage, + int Watchers, + DateTime LastPushUtc + ); ``` The and `int` types have built-in functionality to convert to and from string representation. No extra code is needed to deserialize from JSON string format to those target types. If the JSON packet contains data that doesn't convert to a target type, the serialization action throws an exception. diff --git a/docs/csharp/tutorials/snippets/WebAPIClient/Program.cs b/docs/csharp/tutorials/snippets/WebAPIClient/Program.cs index 141266bb4e36d..eee777bdc50cf 100644 --- a/docs/csharp/tutorials/snippets/WebAPIClient/Program.cs +++ b/docs/csharp/tutorials/snippets/WebAPIClient/Program.cs @@ -1,5 +1,5 @@ using System.Net.Http.Headers; -using System.Text.Json; +using System.Net.Http.Json; using HttpClient client = new(); client.DefaultRequestHeaders.Accept.Clear(); @@ -22,9 +22,6 @@ static async Task> ProcessRepositoriesAsync(HttpClient client) { - await using Stream stream = - await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos"); - var repositories = - await JsonSerializer.DeserializeAsync>(stream); - return repositories ?? new(); + var repositories = await client.GetFromJsonAsync>("https://api.github.com/orgs/dotnet/repos"); + return repositories ?? new List(); } diff --git a/docs/csharp/tutorials/snippets/WebAPIClient/Repository.cs b/docs/csharp/tutorials/snippets/WebAPIClient/Repository.cs index 2ecb2c67a721d..cd2d4e559dc29 100644 --- a/docs/csharp/tutorials/snippets/WebAPIClient/Repository.cs +++ b/docs/csharp/tutorials/snippets/WebAPIClient/Repository.cs @@ -1,12 +1,11 @@ -using System.Text.Json.Serialization; - -public record class Repository( - [property: JsonPropertyName("name")] string Name, - [property: JsonPropertyName("description")] string Description, - [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl, - [property: JsonPropertyName("homepage")] Uri Homepage, - [property: JsonPropertyName("watchers")] int Watchers, - [property: JsonPropertyName("pushed_at")] DateTime LastPushUtc) +public record class Repository( + string Name, + string Description, + Uri GitHubHomeUrl, + Uri Homepage, + int Watchers, + DateTime LastPushUtc +) { public DateTime LastPush => LastPushUtc.ToLocalTime(); } From 52b1bfcf2a6c6c747f1cc89f2b1d190d534515d1 Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Sun, 31 Aug 2025 00:17:55 +0200 Subject: [PATCH 05/10] Remove unused Text.Json.Serialization --- docs/csharp/tutorials/console-webapiclient.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/csharp/tutorials/console-webapiclient.md b/docs/csharp/tutorials/console-webapiclient.md index 8669ab4ebe6b7..0f295bc09dbae 100644 --- a/docs/csharp/tutorials/console-webapiclient.md +++ b/docs/csharp/tutorials/console-webapiclient.md @@ -214,8 +214,6 @@ The following steps add code to process more of the properties in the received J 1. Replace the contents of `Repository` class, with the following `record` definition: ```csharp - using System.Text.Json.Serialization; - public record class Repository( string Name, string Description, From bb708ace22ec7a1c8234e2c481ffb0a08a897a5d Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Sun, 31 Aug 2025 00:19:45 +0200 Subject: [PATCH 06/10] Correct the orders of points --- docs/csharp/tutorials/console-webapiclient.md | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/csharp/tutorials/console-webapiclient.md b/docs/csharp/tutorials/console-webapiclient.md index 0f295bc09dbae..33d8fc1e60ff9 100644 --- a/docs/csharp/tutorials/console-webapiclient.md +++ b/docs/csharp/tutorials/console-webapiclient.md @@ -27,7 +27,7 @@ If you prefer to follow along with the [final sample](/samples/dotnet/samples/co 1. Open a command prompt and create a new directory for your app. Make that the current directory. -1. Enter the following command in a console window: +2. Enter the following command in a console window: ```dotnetcli dotnet new console --name WebAPIClient @@ -35,7 +35,7 @@ directory. This command creates the starter files for a basic "Hello World" app. The project name is "WebAPIClient". -1. Navigate into the "WebAPIClient" directory, and run the app. +3. Navigate into the "WebAPIClient" directory, and run the app. ```dotnetcli cd WebAPIClient @@ -69,7 +69,7 @@ Use the class to make HTTP requests. to handle requests and responses, by replacing the content with the following C#. +2. In the `Program` class, use an to handle requests and responses, by replacing the content with the following C#. ```csharp using System.Net.Http.Headers; @@ -94,7 +94,7 @@ Use the class to make HTTP requests. class to make HTTP requests. method. This method sends an HTTP GET request to the specified URI. The body of the response is returned as a , which is available when the task completes. * The response string `json` is printed to the console. -1. Build the app and run it. +4. Build the app and run it. ```dotnetcli dotnet run @@ -135,7 +135,7 @@ The following steps simplify the approach to fetching the data and processing it The C# convention is to [capitalize the first letter of property names](../../standard/design-guidelines/capitalization-conventions.md). -1. Use the method to fetch and convert JSON into C# objects. Replace the call to in the `ProcessRepositoriesAsync` method with the following lines: +2. Use the method to fetch and convert JSON into C# objects. Replace the call to in the `ProcessRepositoriesAsync` method with the following lines: ```csharp var repositories = await client.GetFromJsonAsync>("https://api.github.com/orgs/dotnet/repos"); @@ -147,7 +147,7 @@ The following steps simplify the approach to fetching the data and processing it The `GetFromJsonAsync` method is [*generic*](../fundamentals/types/generics.md), which means you supply type arguments for what kind of objects should be created from the fetched JSON text. In this example, you're deserializing to a `List`, which is another generic object, a . The `List` class stores a collection of objects. The type argument declares the type of objects stored in the `List`. The type argument is your `Repository` record, because the JSON text represents a collection of repository objects. -1. Add code to display the name of each repository. Replace the lines that read: +3. Add code to display the name of each repository. Replace the lines that read: ```csharp Console.Write(json); @@ -160,14 +160,14 @@ The following steps simplify the approach to fetching the data and processing it Console.Write(repo.Name); ``` -1. The following `using` directives should be present at the top of the file: +4. The following `using` directives should be present at the top of the file: ```csharp using System.Net.Http.Headers; using System.Net.Http.Json; ``` -1. Run the app. +5. Run the app. ```dotnetcli dotnet run @@ -185,7 +185,7 @@ The `ProcessRepositoriesAsync` method can do the async work and return a collect static async Task> ProcessRepositoriesAsync(HttpClient client) ``` -1. Return the repositories after processing the JSON response: +2. Return the repositories after processing the JSON response: ```csharp var repositories = await client.GetFromJsonAsync>("https://api.github.com/orgs/dotnet/repos"); @@ -194,7 +194,7 @@ The `ProcessRepositoriesAsync` method can do the async work and return a collect The compiler generates the `Task` object for the return value because you've marked this method as `async`. -1. Modify the *Program.cs* file, replacing the call to `ProcessRepositoriesAsync` with the following to capture the results and write each repository name to the console. +3. Modify the *Program.cs* file, replacing the call to `ProcessRepositoriesAsync` with the following to capture the results and write each repository name to the console. ```csharp var repositories = await ProcessRepositoriesAsync(client); @@ -203,7 +203,7 @@ The `ProcessRepositoriesAsync` method can do the async work and return a collect Console.Write(repo.Name); ``` -1. Run the app. +4. Run the app. The output is the same. @@ -226,7 +226,7 @@ The following steps add code to process more of the properties in the received J The and `int` types have built-in functionality to convert to and from string representation. No extra code is needed to deserialize from JSON string format to those target types. If the JSON packet contains data that doesn't convert to a target type, the serialization action throws an exception. -1. Update the `foreach` loop in the *Program.cs* file to display the property values: +2. Update the `foreach` loop in the *Program.cs* file to display the property values: ```csharp foreach (var repo in repositories) @@ -240,7 +240,7 @@ The following steps add code to process more of the properties in the received J } ``` -1. Run the app. +3. Run the app. The list now includes the additional properties. @@ -262,18 +262,18 @@ To get a date and time represented in your time zone, you have to write a custom The `LastPush` property is defined using an *expression-bodied member* for the `get` accessor. There's no `set` accessor. Omitting the `set` accessor is one way to define a *read-only* property in C#. (Yes, you can create *write-only* properties in C#, but their value is limited.) -1. Add another output statement in *Program.cs*: +2. Add another output statement in *Program.cs*: again: ```csharp Console.WriteLine($"Last push: {repo.LastPush}"); ``` -1. The complete app should resemble the following *Program.cs* file: +3. The complete app should resemble the following *Program.cs* file: :::code source="snippets/WebAPIClient/Program.cs"::: -1. Run the app. +4. Run the app. The output includes the date and time of the last push to each repository. From 2c933046181ece52a637d758cadd75c6d67e1aec Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Sun, 31 Aug 2025 00:20:38 +0200 Subject: [PATCH 07/10] WriteLine instead of Write in early phase to improve output readability --- docs/csharp/tutorials/console-webapiclient.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/csharp/tutorials/console-webapiclient.md b/docs/csharp/tutorials/console-webapiclient.md index 33d8fc1e60ff9..e6eaf1a4d253a 100644 --- a/docs/csharp/tutorials/console-webapiclient.md +++ b/docs/csharp/tutorials/console-webapiclient.md @@ -157,7 +157,7 @@ The following steps simplify the approach to fetching the data and processing it ```csharp foreach (var repo in repositories ?? Enumerable.Empty()) - Console.Write(repo.Name); + Console.WriteLine(repo.Name); ``` 4. The following `using` directives should be present at the top of the file: @@ -200,7 +200,7 @@ The `ProcessRepositoriesAsync` method can do the async work and return a collect var repositories = await ProcessRepositoriesAsync(client); foreach (var repo in repositories) - Console.Write(repo.Name); + Console.WriteLine(repo.Name); ``` 4. Run the app. From 69fb854c8f1d468bdcbc1ddeb8abc9d9195e0ba4 Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Tue, 2 Sep 2025 20:59:01 +0200 Subject: [PATCH 08/10] Revert "Correct the orders of points" This reverts commit bb708ace22ec7a1c8234e2c481ffb0a08a897a5d. --- docs/csharp/tutorials/console-webapiclient.md | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/csharp/tutorials/console-webapiclient.md b/docs/csharp/tutorials/console-webapiclient.md index e6eaf1a4d253a..911ed2065ed84 100644 --- a/docs/csharp/tutorials/console-webapiclient.md +++ b/docs/csharp/tutorials/console-webapiclient.md @@ -27,7 +27,7 @@ If you prefer to follow along with the [final sample](/samples/dotnet/samples/co 1. Open a command prompt and create a new directory for your app. Make that the current directory. -2. Enter the following command in a console window: +1. Enter the following command in a console window: ```dotnetcli dotnet new console --name WebAPIClient @@ -35,7 +35,7 @@ directory. This command creates the starter files for a basic "Hello World" app. The project name is "WebAPIClient". -3. Navigate into the "WebAPIClient" directory, and run the app. +1. Navigate into the "WebAPIClient" directory, and run the app. ```dotnetcli cd WebAPIClient @@ -69,7 +69,7 @@ Use the class to make HTTP requests. to handle requests and responses, by replacing the content with the following C#. +1. In the `Program` class, use an to handle requests and responses, by replacing the content with the following C#. ```csharp using System.Net.Http.Headers; @@ -94,7 +94,7 @@ Use the class to make HTTP requests. class to make HTTP requests. method. This method sends an HTTP GET request to the specified URI. The body of the response is returned as a , which is available when the task completes. * The response string `json` is printed to the console. -4. Build the app and run it. +1. Build the app and run it. ```dotnetcli dotnet run @@ -135,7 +135,7 @@ The following steps simplify the approach to fetching the data and processing it The C# convention is to [capitalize the first letter of property names](../../standard/design-guidelines/capitalization-conventions.md). -2. Use the method to fetch and convert JSON into C# objects. Replace the call to in the `ProcessRepositoriesAsync` method with the following lines: +1. Use the method to fetch and convert JSON into C# objects. Replace the call to in the `ProcessRepositoriesAsync` method with the following lines: ```csharp var repositories = await client.GetFromJsonAsync>("https://api.github.com/orgs/dotnet/repos"); @@ -147,7 +147,7 @@ The following steps simplify the approach to fetching the data and processing it The `GetFromJsonAsync` method is [*generic*](../fundamentals/types/generics.md), which means you supply type arguments for what kind of objects should be created from the fetched JSON text. In this example, you're deserializing to a `List`, which is another generic object, a . The `List` class stores a collection of objects. The type argument declares the type of objects stored in the `List`. The type argument is your `Repository` record, because the JSON text represents a collection of repository objects. -3. Add code to display the name of each repository. Replace the lines that read: +1. Add code to display the name of each repository. Replace the lines that read: ```csharp Console.Write(json); @@ -160,14 +160,14 @@ The following steps simplify the approach to fetching the data and processing it Console.WriteLine(repo.Name); ``` -4. The following `using` directives should be present at the top of the file: +1. The following `using` directives should be present at the top of the file: ```csharp using System.Net.Http.Headers; using System.Net.Http.Json; ``` -5. Run the app. +1. Run the app. ```dotnetcli dotnet run @@ -185,7 +185,7 @@ The `ProcessRepositoriesAsync` method can do the async work and return a collect static async Task> ProcessRepositoriesAsync(HttpClient client) ``` -2. Return the repositories after processing the JSON response: +1. Return the repositories after processing the JSON response: ```csharp var repositories = await client.GetFromJsonAsync>("https://api.github.com/orgs/dotnet/repos"); @@ -194,7 +194,7 @@ The `ProcessRepositoriesAsync` method can do the async work and return a collect The compiler generates the `Task` object for the return value because you've marked this method as `async`. -3. Modify the *Program.cs* file, replacing the call to `ProcessRepositoriesAsync` with the following to capture the results and write each repository name to the console. +1. Modify the *Program.cs* file, replacing the call to `ProcessRepositoriesAsync` with the following to capture the results and write each repository name to the console. ```csharp var repositories = await ProcessRepositoriesAsync(client); @@ -203,7 +203,7 @@ The `ProcessRepositoriesAsync` method can do the async work and return a collect Console.WriteLine(repo.Name); ``` -4. Run the app. +1. Run the app. The output is the same. @@ -226,7 +226,7 @@ The following steps add code to process more of the properties in the received J The and `int` types have built-in functionality to convert to and from string representation. No extra code is needed to deserialize from JSON string format to those target types. If the JSON packet contains data that doesn't convert to a target type, the serialization action throws an exception. -2. Update the `foreach` loop in the *Program.cs* file to display the property values: +1. Update the `foreach` loop in the *Program.cs* file to display the property values: ```csharp foreach (var repo in repositories) @@ -240,7 +240,7 @@ The following steps add code to process more of the properties in the received J } ``` -3. Run the app. +1. Run the app. The list now includes the additional properties. @@ -262,18 +262,18 @@ To get a date and time represented in your time zone, you have to write a custom The `LastPush` property is defined using an *expression-bodied member* for the `get` accessor. There's no `set` accessor. Omitting the `set` accessor is one way to define a *read-only* property in C#. (Yes, you can create *write-only* properties in C#, but their value is limited.) -2. Add another output statement in *Program.cs*: +1. Add another output statement in *Program.cs*: again: ```csharp Console.WriteLine($"Last push: {repo.LastPush}"); ``` -3. The complete app should resemble the following *Program.cs* file: +1. The complete app should resemble the following *Program.cs* file: :::code source="snippets/WebAPIClient/Program.cs"::: -4. Run the app. +1. Run the app. The output includes the date and time of the last push to each repository. From 65d0c7b17f6d57e84d9b297c38ce608433b0c664 Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Tue, 2 Sep 2025 21:08:10 +0200 Subject: [PATCH 09/10] Remove leftover sentence --- docs/csharp/tutorials/console-webapiclient.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/console-webapiclient.md b/docs/csharp/tutorials/console-webapiclient.md index 911ed2065ed84..4daedeca29773 100644 --- a/docs/csharp/tutorials/console-webapiclient.md +++ b/docs/csharp/tutorials/console-webapiclient.md @@ -141,7 +141,7 @@ The following steps simplify the approach to fetching the data and processing it var repositories = await client.GetFromJsonAsync>("https://api.github.com/orgs/dotnet/repos"); ``` - The updated code replaces with . This `GetFromJsonAsync` method + The updated code replaces with . The first argument to `GetFromJsonAsync` method is an `await` expression. `await` expressions can appear almost anywhere in your code, even though up to now, you've only seen them as part of an assignment statement. The next parameter, `requestUri` is optional and doesn't have to be provided if was already specified when creating the `client` object. You didn't provide the `client` object with the URI to send request to, so you specified the URI now. The last optional parameter, the `CancellationToken` is omitted in the code snippet. From 9dbc288cc178ab2c3062054362153a89c1f4dfa6 Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Tue, 2 Sep 2025 21:19:13 +0200 Subject: [PATCH 10/10] Mention that GetFromJsonAsync is case-insensitive This is mentioned in two places - with the C# naming convention, where it's worth to mention why we keep on having uppercase, and in the Repository class defining, where we would normally had to make a conversion, but now we don't because we have case-insensitive method as a tool. --- docs/csharp/tutorials/console-webapiclient.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/csharp/tutorials/console-webapiclient.md b/docs/csharp/tutorials/console-webapiclient.md index 4daedeca29773..a5a8972cf4b69 100644 --- a/docs/csharp/tutorials/console-webapiclient.md +++ b/docs/csharp/tutorials/console-webapiclient.md @@ -133,7 +133,7 @@ The following steps simplify the approach to fetching the data and processing it The JSON for a repository object contains dozens of properties, but only the `Name` property will be deserialized. The serializer automatically ignores JSON properties for which there is no match in the target class. This feature makes it easier to create types that work with only a subset of fields in a large JSON packet. - The C# convention is to [capitalize the first letter of property names](../../standard/design-guidelines/capitalization-conventions.md). + Although the `GetFromJsonAsync` method you will use in the next point has a benefit of being case-insensitive when it comes to property names, the C# convention is to [capitalize the first letter of property names](../../standard/design-guidelines/capitalization-conventions.md). 1. Use the method to fetch and convert JSON into C# objects. Replace the call to in the `ProcessRepositoriesAsync` method with the following lines: @@ -226,6 +226,8 @@ The following steps add code to process more of the properties in the received J The and `int` types have built-in functionality to convert to and from string representation. No extra code is needed to deserialize from JSON string format to those target types. If the JSON packet contains data that doesn't convert to a target type, the serialization action throws an exception. + JSON most often uses lowercase for names of it's objects, however we don't need to make any conversion and can keep the uppercase of the fields names, because, like mentioned in one of previous points, the `GetFromJsonAsync` extension method is case-insensitive when it comes to property names. + 1. Update the `foreach` loop in the *Program.cs* file to display the property values: ```csharp