Skip to content

Commit ae0051e

Browse files
max-lancasterwadepickettguardrex
authored
OpenAPI Controllers Sample with XML Comments (#36770)
* Ignore Rider .idea/ in .gitignore Add a comment for Rider and include .idea/ in .gitignore so JetBrains Rider project files are ignored by Git. * Bump OpenApi to 10.0.3 and silence ASPDEPR002 Update Microsoft.AspNetCore.OpenApi from a preview version to 10.0.3 in the sample Api.csproj. In ProjectBoardApis.cs, wrap the MapGroup call with #pragma warning disable/restore for ASPDEPR002 to suppress the deprecation warning in the sample code and keep builds clean. Changes affect only the openapi XML sample files. * Add OpenAPI XML controllers sample Add a new sample under aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml-controllers. Includes an API project and a models project, controllers for ProjectBoards and Todos with XML documentation and OpenAPI tags, Program.cs wiring OpenAPI and Scalar, appsettings and global.json, and an Api.http file with example requests. Also includes AdditionalFiles.xml to demonstrate adding external XML docs and Api-remove.csproj showing how to disable the compile-time OpenAPI source generator analyzer. This sample demonstrates using XML documentation with OpenAPI in .NET 10. * Apply suggestions from code review Adding suggestions from guardrex Co-authored-by: Luke Latham <1622880+guardrex@users.noreply.github.com> * Apply suggestion from @wadepickett Reverting global gitignore change for Properties/ * Refactor ProjectBoardApis to remove warning suppression Removed deprecated warning suppression for OpenAPI mapping. * Delete aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml-controllers/api/Properties/launchSettings.json Deleting launchSetting.json which we are not including for this article. * Delete aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Properties/launchSettings.json Deleting added launchSettings.json which we are not including for the samples in this area. --------- Co-authored-by: Wade Pickett <wpickett@microsoft.com> Co-authored-by: Luke Latham <1622880+guardrex@users.noreply.github.com>
1 parent f6cdc6e commit ae0051e

File tree

17 files changed

+566
-3
lines changed

17 files changed

+566
-3
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,6 @@ __pycache__/
227227

228228
# Windows thumbnail cache files
229229
Thumbs.db
230+
231+
# Rider
232+
.idea/
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<ItemGroup>
2+
<PackageReference Include="Some.Package" Version="10.0.0"
3+
GeneratePathProperty="true" />
4+
</ItemGroup>
5+
6+
<ItemGroup>
7+
<AdditionalFiles Include="$(PkgSome_Package)/lib/net10.0/Some.Package.xml" />
8+
</ItemGroup>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
12+
<PackageReference Include="Scalar.AspNetCore" Version="2.0.30" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\models\Models.csproj" />
17+
</ItemGroup>
18+
19+
<Target Name="DisableCompileTimeOpenApiXmlGenerator" BeforeTargets="CoreCompile">
20+
<ItemGroup>
21+
<Analyzer Remove="$(PkgMicrosoft_AspNetCore_OpenApi)/analyzers/dotnet/cs/Microsoft.AspNetCore.OpenApi.SourceGenerators.dll" />
22+
</ItemGroup>
23+
</Target>
24+
25+
</Project>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
12+
<PackageReference Include="Scalar.AspNetCore" Version="2.0.30" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\models\Models.csproj" />
17+
</ItemGroup>
18+
19+
</Project>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
@Api_HostAddress = http://localhost:5052
2+
3+
GET {{Api_HostAddress}}/weatherforecast/
4+
Accept: application/json
5+
6+
### Project Board Endpoints ###
7+
8+
### Get all project boards
9+
GET {{Api_HostAddress}}/api/projectboards
10+
Accept: application/json
11+
12+
### Get project board by ID
13+
GET {{Api_HostAddress}}/api/projectboards/1
14+
Accept: application/json
15+
16+
### Create a new project board
17+
POST {{Api_HostAddress}}/api/projectboards
18+
Content-Type: application/json
19+
20+
{
21+
"name": "Website Redesign",
22+
"description": "Tasks for redesigning the company website"
23+
}
24+
25+
### Update a project board
26+
PUT {{Api_HostAddress}}/api/projectboards/1
27+
Content-Type: application/json
28+
29+
{
30+
"name": "Website Redesign v2",
31+
"description": "Updated tasks for redesigning the company website"
32+
}
33+
34+
### Delete a project board
35+
DELETE {{Api_HostAddress}}/api/projectboards/1
36+
37+
38+
### Todo Endpoints ###
39+
40+
### Get all todos for a project board
41+
GET {{Api_HostAddress}}/api/projectboards/1/todos
42+
Accept: application/json
43+
44+
### Get a specific todo by ID
45+
GET {{Api_HostAddress}}/api/projectboards/1/todos/1
46+
Accept: application/json
47+
48+
### Create a new todo
49+
POST {{Api_HostAddress}}/api/projectboards/1/todos
50+
Content-Type: application/json
51+
52+
{
53+
"title": "Design new homepage",
54+
"description": "Create wireframes for the new homepage design",
55+
"isComplete": false,
56+
"priority": 2,
57+
"dueDate": "2025-03-20T00:00:00Z"
58+
}
59+
60+
### Update a todo
61+
PUT {{Api_HostAddress}}/api/projectboards/1/todos/1
62+
Content-Type: application/json
63+
64+
{
65+
"title": "Design new homepage with feedback",
66+
"description": "Update wireframes based on stakeholder feedback",
67+
"isComplete": true,
68+
"priority": 3,
69+
"dueDate": "2025-03-25T00:00:00Z"
70+
}
71+
72+
### Delete a todo
73+
DELETE {{Api_HostAddress}}/api/projectboards/1/todos/1
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using Models;
3+
4+
namespace Api.Controllers;
5+
6+
/// <summary>
7+
/// API controller for managing project boards.
8+
/// </summary>
9+
[ApiController]
10+
[Route("api/[controller]")]
11+
[Tags("Project Boards")]
12+
public class ProjectBoardsController : ControllerBase
13+
{
14+
// In-memory storage for demo purposes
15+
internal static readonly List<ProjectBoard> Boards = new();
16+
private static int _nextBoardId = 1;
17+
18+
/// <summary>
19+
/// Retrieves all project boards.
20+
/// </summary>
21+
/// <returns>A collection of all project boards.</returns>
22+
/// <response code="200">Returns the list of project boards.</response>
23+
[HttpGet]
24+
[ProducesResponseType(StatusCodes.Status200OK)]
25+
public ActionResult<IEnumerable<ProjectBoard>> GetAllProjectBoards()
26+
{
27+
return Ok(Boards);
28+
}
29+
30+
// <snippet_1>
31+
/// <summary>
32+
/// Retrieves a specific project board by ID.
33+
/// </summary>
34+
/// <param name="id">The ID of the project board to retrieve.</param>
35+
/// <returns>The requested project board.</returns>
36+
/// <response code="200">Returns the requested project board.</response>
37+
/// <response code="404">If the project board is not found.</response>
38+
[HttpGet("{id}")]
39+
[ProducesResponseType(StatusCodes.Status200OK)]
40+
[ProducesResponseType(StatusCodes.Status404NotFound)]
41+
public ActionResult<ProjectBoard> GetProjectBoardById(int id)
42+
{
43+
var board = Boards.FirstOrDefault(b => b.Id == id);
44+
if (board == null)
45+
{
46+
return NotFound();
47+
}
48+
return Ok(board);
49+
}
50+
// </snippet_1>
51+
52+
/// <summary>
53+
/// Creates a new project board.
54+
/// </summary>
55+
/// <param name="board">The project board to create.</param>
56+
/// <returns>The newly created project board.</returns>
57+
/// <response code="201">Returns the newly created project board.</response>
58+
/// <response code="400">If the project board data is invalid.</response>
59+
[HttpPost]
60+
[ProducesResponseType(StatusCodes.Status201Created)]
61+
[ProducesResponseType(StatusCodes.Status400BadRequest)]
62+
public ActionResult<ProjectBoard> CreateProjectBoard(ProjectBoard board)
63+
{
64+
board.Id = _nextBoardId++;
65+
board.CreatedAt = DateTime.UtcNow;
66+
Boards.Add(board);
67+
68+
return CreatedAtAction(nameof(GetProjectBoardById), new { id = board.Id }, board);
69+
}
70+
71+
/// <summary>
72+
/// Updates an existing project board.
73+
/// </summary>
74+
/// <param name="id">The ID of the project board to update.</param>
75+
/// <param name="updatedBoard">The updated project board data.</param>
76+
/// <returns>No content if successful.</returns>
77+
/// <response code="204">If the update was successful.</response>
78+
/// <response code="400">If the project board data is invalid.</response>
79+
/// <response code="404">If the project board is not found.</response>
80+
[HttpPut("{id}")]
81+
[ProducesResponseType(StatusCodes.Status204NoContent)]
82+
[ProducesResponseType(StatusCodes.Status400BadRequest)]
83+
[ProducesResponseType(StatusCodes.Status404NotFound)]
84+
public IActionResult UpdateProjectBoard(int id, ProjectBoard updatedBoard)
85+
{
86+
var board = Boards.FirstOrDefault(b => b.Id == id);
87+
if (board == null)
88+
{
89+
return NotFound();
90+
}
91+
92+
board.Name = updatedBoard.Name;
93+
board.Description = updatedBoard.Description;
94+
95+
return NoContent();
96+
}
97+
98+
/// <summary>
99+
/// Deletes a project board.
100+
/// </summary>
101+
/// <param name="id">The ID of the project board to delete.</param>
102+
/// <returns>No content if successful.</returns>
103+
/// <response code="204">If the deletion was successful.</response>
104+
/// <response code="404">If the project board is not found.</response>
105+
[HttpDelete("{id}")]
106+
[ProducesResponseType(StatusCodes.Status204NoContent)]
107+
[ProducesResponseType(StatusCodes.Status404NotFound)]
108+
public IActionResult DeleteProjectBoard(int id)
109+
{
110+
var board = Boards.FirstOrDefault(b => b.Id == id);
111+
if (board == null)
112+
{
113+
return NotFound();
114+
}
115+
116+
Boards.Remove(board);
117+
return NoContent();
118+
}
119+
}

0 commit comments

Comments
 (0)