Skip to content

Commit e5b3610

Browse files
committed
Additional samples, ddoc and screenshot update to lukekaese's PR
1 parent 4238c47 commit e5b3610

File tree

16 files changed

+319
-156
lines changed

16 files changed

+319
-156
lines changed

aspnetcore/tutorials/first-web-api.md

Lines changed: 66 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ author: wadepickett
44
description: Learn how to build a web API with ASP.NET Core.
55
ms.author: wpickett
66
ms.custom: mvc, engagement-fy24
7-
ms.date: 08/04/2024
7+
ms.date: 02/13/2025
88
uid: tutorials/first-web-api
99
---
1010

@@ -38,15 +38,15 @@ The following diagram shows the design of the app.
3838

3939
# [Visual Studio](#tab/visual-studio)
4040

41-
[!INCLUDE[](~/includes/net-prereqs-vs-8.0.md)]
41+
[!INCLUDE[](~/includes/net-prereqs-vs-9.0.md)]
4242

4343
# [Visual Studio Code](#tab/visual-studio-code)
4444

45-
[!INCLUDE[](~/includes/net-prereqs-vsc-8.0.md)]
45+
[!INCLUDE[](~/includes/net-prereqs-vsc-9.0.md)]
4646

4747
---
4848

49-
## Create a web project
49+
## Create a Web API project
5050

5151
# [Visual Studio](#tab/visual-studio)
5252

@@ -55,19 +55,25 @@ The following diagram shows the design of the app.
5555
* Select the **ASP.NET Core Web API** template and select **Next**.
5656
* In the **Configure your new project dialog**, name the project *TodoApi* and select **Next**.
5757
* In the **Additional information** dialog:
58-
* Confirm the **Framework** is **.NET 8.0 (Long Term Support)**.
59-
* Confirm the checkbox for **Use controllers(uncheck to use minimal APIs)** is checked.
58+
* Confirm the **Framework** is **.NET 9.0 (Standard Term Support)**.
6059
* Confirm the checkbox for **Enable OpenAPI support** is checked.
60+
* Confirm the checkbox for **Use controllers** is checked.
6161
* Select **Create**.
6262

63-
## Add a NuGet package
63+
## Add NuGet packages
6464

65-
A NuGet package must be added to support the database used in this tutorial.
65+
This tutorial uses the following additional NuGet packages:
66+
* `Microsoft.EntityFrameworkCore.InMemory`: Enables Entity Framework Core to work with an in-memory database rather than an external one, simplifying this tutorial.
67+
* `Swashbuckle.AspNetCore.SwaggerUI`: Provides a user interface for exploring and testing API endpoints interactively through Swagger.
68+
69+
Add the following NuGet packages used in this tutorial.
6670

6771
* From the **Tools** menu, select **NuGet Package Manager > Manage NuGet Packages for Solution**.
6872
* Select the **Browse** tab.
6973
* Enter **Microsoft.EntityFrameworkCore.InMemory** in the search box, and then select `Microsoft.EntityFrameworkCore.InMemory`.
7074
* Select the **Project** checkbox in the right pane and then select **Install**.
75+
* Enter **Swashbuckle.AspNetCore.SwaggerUI** in the search box, and then select `Swashbuckle.AspNetCore.SwaggerUI`.
76+
* Select the **Project** checkbox in the right pane and then select **Install**.
7177

7278
# [Visual Studio Code](#tab/visual-studio-code)
7379

@@ -79,13 +85,16 @@ A NuGet package must be added to support the database used in this tutorial.
7985
dotnet new webapi --use-controllers -o TodoApi
8086
cd TodoApi
8187
dotnet add package Microsoft.EntityFrameworkCore.InMemory
88+
dotnet add package Swashbuckle.AspNetCore.SwaggerUI
8289
code -r ../TodoApi
8390
```
8491

8592
These commands:
8693

8794
* Create a new web API project and open it in Visual Studio Code.
88-
* Add a NuGet package that is needed for the next section.
95+
* Adds NuGet packages that are used in this tutorial:
96+
* `Microsoft.EntityFrameworkCore.InMemory`: Enables Entity Framework Core to work with an in-memory database so a real database won't be required for this tutorial.
97+
* `Swashbuckle.AspNetCore.SwaggerUI`: Provides a user interface for exploring and testing API endpoints interactively through Swagger.
8998
* Open the *TodoApi* folder in the current instance of Visual Studio Code.
9099

91100
[!INCLUDE[](~/includes/vscode-trust-authors-add-assets.md)]
@@ -94,17 +103,40 @@ A NuGet package must be added to support the database used in this tutorial.
94103

95104
[!INCLUDE[](~/includes/package-reference.md)]
96105

97-
### Test the project
106+
### Test the Project
107+
108+
The project template:
109+
110+
* Creates a `WeatherForecast` API using controllers.
111+
* Adds the `Microsoft.AspNetCore.OpenApi` package for OpenAPI support as a reference in the project file **TodoApi.csproj**.
112+
* Adds OpenAPI services in **Project.cs** to automatically generate OpenAPI JSON documentation for the `WeatherForecast` API.
113+
114+
You can access the OpenAPI JSON documentation for the `WeatherForecast` API while the project is running by navigating your browser to `https://localhost:<port>/openapi/v1.json`, where `<port>` is a randomly chosen port number set during project creation.
98115

99-
The project template creates a `WeatherForecast` API with support for [Swagger](xref:tutorials/web-api-help-pages-using-swagger).
116+
#### Configure the Swagger UI endpoint for the OpenAPI documentation
117+
118+
To configure [Swagger](xref:tutorials/web-api-help-pages-using-swagger) UI for testing the API, add the following highlighted code to the `Program.cs` file in the **TodoAPI** project:
119+
120+
[!code-csharp[](~/tutorials/first-web-api/samples/9.0/TodoApi/Program.cs?name=snippet_First_Add_SwaggerUI&highlight=16-19)]
121+
122+
The previously highlighted code:
123+
124+
* Adds the Swagger UI as a service to the app with `app.UseSwaggerUI()`.
125+
* Sets the `SwaggerEndpoint()` option to the location of the OpenAPI documentation for this project.
126+
* Ensures the Swagger UI is only available in the app development environment to limit information disclosure and security vulnerability.
100127

101128
# [Visual Studio](#tab/visual-studio)
102129

103130
Press Ctrl+F5 to run without the debugger.
104131

105132
[!INCLUDE[](~/includes/trustCertVS.md)]
106133

107-
Visual Studio launches the default browser and navigates to `https://localhost:<port>/swagger/index.html`, where `<port>` is a randomly chosen port number set at the project creation.
134+
Visual Studio output pane shows messages similar to the following, indicating that the app is running and awaiting requests:
135+
136+
```output
137+
Microsoft.Hosting.Lifetime: Information: Now listening on: https://localhost:{port number}
138+
Microsoft.Hosting.Lifetime: Information: Now listening on: http://localhost:5071{port number}
139+
```
108140

109141
# [Visual Studio Code](#tab/visual-studio-code)
110142

@@ -123,19 +155,25 @@ Run the app:
123155
```output
124156
...
125157
info: Microsoft.Hosting.Lifetime[14]
126-
Now listening on: https://localhost:{port}
158+
Now listening on: https://localhost:{port number}
127159
...
128160
```
129161

130162
* <kbd>Ctrl</kbd>+*click* the HTTPS URL in the output to test the web app in a browser.
131163

132-
* The default browser is launched to `https://localhost:<port>/swagger/index.html`, where `<port>` is the randomly chosen port number displayed in the output. There's no endpoint at `https://localhost:<port>`, so the browser returns [HTTP 404 Not Found](https://developer.mozilla.org/docs/Web/HTTP/Status/404). Append `/swagger` to the URL, `https://localhost:<port>/swagger`.
133-
134164
After testing the web app in the following instruction, press <kbd>Ctrl</kbd>+<kbd>C</kbd> in the integrated terminal to shut it down.
135165

136166
---
137167

138-
The Swagger page `/swagger/index.html` is displayed. Select **GET** > **Try it out** > **Execute**. The page displays:
168+
#### View the Swagger UI
169+
170+
* Navigate a browser to `https://localhost:<port>/swagger/index.html`, where `<port>` is a randomly chosen port number set in **Properties/launchSettings.json** and displayed in the output.
171+
172+
The Swagger page `/swagger/index.html` is displayed.
173+
174+
* Select **GET** > **Try it out** > **Execute**.
175+
176+
The page displays:
139177

140178
* The [Curl](https://curl.haxx.se/) command to test the WeatherForecast API.
141179
* The URL to test the WeatherForecast API.
@@ -144,8 +182,6 @@ The Swagger page `/swagger/index.html` is displayed. Select **GET** > **Try it o
144182

145183
If the Swagger page doesn't appear, see [this GitHub issue](https://github.com/dotnet/AspNetCore.Docs/issues/21647).
146184

147-
Swagger is used to generate useful documentation and help pages for web APIs. This tutorial uses Swagger to test the app. For more information on Swagger, see <xref:tutorials/web-api-help-pages-using-swagger>.
148-
149185
Copy and paste the **Request URL** in the browser: `https://localhost:<port>/weatherforecast`
150186

151187
JSON similar to the following example is returned:
@@ -232,13 +268,13 @@ In ASP.NET Core, services such as the DB context must be registered with the [de
232268

233269
Update `Program.cs` with the following highlighted code:
234270

235-
[!code-csharp[](~/tutorials/first-web-api/samples/9.0/TodoApi/Program.cs?highlight=1-2,7-8)]
271+
[!code-csharp[](~/tutorials/first-web-api/samples/9.0/TodoApi/Program.cs?nameFinal_Add_DBContext=&highlight=1-2,9-10)]
236272

237273
The preceding code:
238274

239275
* Adds `using` directives.
240276
* Adds the database context to the DI container.
241-
* Specifies that the database context will use an in-memory database.
277+
* Specifies that the database context uses an in-memory database.
242278

243279
## Scaffold a controller
244280

@@ -312,7 +348,7 @@ When the `[action]` token isn't in the route template, the [action](xref:mvc/con
312348

313349
## Update the PostTodoItem create method
314350

315-
Update the return statement in the `PostTodoItem` to use the [nameof](/dotnet/csharp/language-reference/operators/nameof) operator:
351+
In **Controllers/TodoItemsController.cs** update the return statement in the `PostTodoItem` to use the [nameof](/dotnet/csharp/language-reference/operators/nameof) operator:
316352

317353
[!code-csharp[](~/tutorials/first-web-api/samples/9.0/TodoApi/Controllers/TodoItemsController.cs?name=snippet_Create)]
318354

@@ -343,7 +379,7 @@ The <xref:Microsoft.AspNetCore.Mvc.ControllerBase.CreatedAtAction%2A> method:
343379

344380
* Select **Execute**
345381

346-
![Swagger POST](~/tutorials/first-web-api/_static/7/post.png)
382+
![Swagger POST](~/tutorials/first-web-api/_static/9/post.png)
347383

348384
### Test the location header URI
349385

@@ -375,10 +411,11 @@ The [`[HttpGet]`](xref:Microsoft.AspNetCore.Mvc.HttpGetAttribute) attribute deno
375411

376412
* Start with the template string in the controller's `Route` attribute:
377413

378-
[!code-csharp[](~/tutorials/first-web-api/samples/6.0/TodoApi/Controllers/TodoItemsController.cs?name=snippet_Route&highlight=1)]
414+
[!code-csharp[](~/tutorials/first-web-api/samples/9.0/TodoApi/Controllers/TodoItemsController.cs?name=snippet_Route&highlight=1)]
379415

380416
* Replace `[controller]` with the name of the controller, which by convention is the controller class name minus the "Controller" suffix. For this sample, the controller class name is **TodoItems**Controller, so the controller name is "TodoItems". ASP.NET Core [routing](xref:mvc/controllers/routing) is case insensitive.
381-
* If the `[HttpGet]` attribute has a route template (for example, `[HttpGet("products")]`), append that to the path. This sample doesn't use a template. For more information, see [Attribute routing with Http[Verb] attributes](xref:mvc/controllers/routing#verb).
417+
418+
This sample doesn't use a route template with the [HttpGet] attribute. However in applications where an `[HttpGet]` attribute has a route template (for example, `[HttpGet("products")]`), append that to the path. For more information, see [Attribute routing with Http[Verb] attributes](xref:mvc/controllers/routing#verb).
382419

383420
In the following `GetTodoItem` method, `"{id}"` is a placeholder variable for the unique identifier of the to-do item. When `GetTodoItem` is invoked, the value of `"{id}"` in the URL is provided to the method in its `id` parameter.
384421

@@ -397,7 +434,7 @@ The return type of the `GetTodoItems` and `GetTodoItem` methods is [ActionResult
397434

398435
Examine the `PutTodoItem` method:
399436

400-
[!code-csharp[](~/tutorials/first-web-api/samples/9.0/TodoApi/Controllers/TodoItemsController.cs?name=snippet_Update)]
437+
[!code-csharp[](~/tutorials/first-web-api/samples/9.0/TodoApi/Controllers/TodoItemsController.cs?name=snippet_PutTodoItem)]
401438

402439
`PutTodoItem` is similar to `PostTodoItem`, except it uses `HTTP PUT`. The response is [204 (No Content)](https://www.rfc-editor.org/rfc/rfc9110#status.204). According to the HTTP specification, a `PUT` request requires the client to send the entire updated entity, not just the changes. To support partial updates, use [HTTP PATCH](xref:Microsoft.AspNetCore.Mvc.HttpPatchAttribute).
403440

@@ -447,19 +484,19 @@ A DTO may be used to:
447484

448485
To demonstrate the DTO approach, update the `TodoItem` class to include a secret field:
449486

450-
[!code-csharp[](~/tutorials/first-web-api/samples/6.0/TodoApiDTO/Models/TodoItem.cs?highlight=8)]
487+
[!code-csharp[](~/tutorials/first-web-api/samples/9.0/TodoApiDTO/Models/TodoItem.cs?highlight=8)]
451488

452489
The secret field needs to be hidden from this app, but an administrative app could choose to expose it.
453490

454491
Verify you can post and get the secret field.
455492

456-
Create a DTO model:
493+
Create a DTO model in a **Models/TodoItemsDTO.cs** file:
457494

458495
[!code-csharp[](~/tutorials/first-web-api/samples/9.0/TodoApiDTO/Models/TodoItemDTO.cs)]
459496

460497
Update the `TodoItemsController` to use `TodoItemDTO`:
461498

462-
[!code-csharp[](~/tutorials/first-web-api/samples/9.0/TodoApiDTO/Controllers/TodoItemsController.cs)]
499+
[!code-csharp[](~/tutorials/first-web-api/samples/9.0/TodoApiDTO/Controllers/TodoItemsController.cs?highlight=25,28,34,43,49,51,62,63,89,93,94,100,124-130)]
463500

464501
Verify you can't post or get the secret field.
465502

@@ -491,6 +528,7 @@ For more information, see the following resources:
491528

492529
* <xref:web-api/index>
493530
* <xref:tutorials/min-web-api>
531+
( <xref:fundamentals/openapi/using-openapi-documents>
494532
* <xref:tutorials/web-api-help-pages-using-swagger>
495533
* <xref:data/ef-rp/intro>
496534
* <xref:mvc/controllers/routing>
144 KB
Loading

aspnetcore/tutorials/first-web-api/samples/9.0/TodoApi/Controllers/TodoItemsController.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Http;
16
using Microsoft.AspNetCore.Mvc;
27
using Microsoft.EntityFrameworkCore;
38
using TodoApi.Models;
49

510
namespace TodoApi.Controllers
611
{
12+
// <snippet_Route>
713
[Route("api/[controller]")]
814
[ApiController]
915
public class TodoItemsController : ControllerBase
16+
// </snippet_Route>
1017
{
1118
private readonly TodoContext _context;
1219

@@ -40,7 +47,7 @@ public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
4047

4148
// PUT: api/TodoItems/5
4249
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
43-
// <snippet_Update>
50+
// <snippet_PutTodoItem>
4451
[HttpPut("{id}")]
4552
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
4653
{
@@ -69,7 +76,7 @@ public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
6976

7077
return NoContent();
7178
}
72-
// </snippet_Update>
79+
// </snippet_PutTodoItem>
7380

7481
// POST: api/TodoItems
7582
// To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
@@ -86,6 +93,7 @@ public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
8693
// </snippet_Create>
8794

8895
// DELETE: api/TodoItems/5
96+
// <snippet_Delete>
8997
[HttpDelete("{id}")]
9098
public async Task<IActionResult> DeleteTodoItem(long id)
9199
{
@@ -100,6 +108,7 @@ public async Task<IActionResult> DeleteTodoItem(long id)
100108

101109
return NoContent();
102110
}
111+
// </snippet_Delete>
103112

104113
private bool TodoItemExists(long id)
105114
{

aspnetcore/tutorials/first-web-api/samples/9.0/TodoApi/Models/TodoContext.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Microsoft.EntityFrameworkCore;
1+
using Microsoft.EntityFrameworkCore;
22

33
namespace TodoApi.Models;
44

@@ -10,4 +10,4 @@ public TodoContext(DbContextOptions<TodoContext> options)
1010
}
1111

1212
public DbSet<TodoItem> TodoItems { get; set; } = null!;
13-
}
13+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
namespace TodoApi.Models;
1+
namespace TodoApi.Models;
22

33
public class TodoItem
44
{
55
public long Id { get; set; }
66
public string? Name { get; set; }
77
public bool IsComplete { get; set; }
8-
}
8+
}

0 commit comments

Comments
 (0)