diff --git a/aspnetcore/fundamentals/openapi/_static/screenshot.png b/aspnetcore/fundamentals/openapi/_static/screenshot.png new file mode 100644 index 000000000000..05e5a06f7fd5 Binary files /dev/null and b/aspnetcore/fundamentals/openapi/_static/screenshot.png differ diff --git a/aspnetcore/fundamentals/openapi/openapi-comments.md b/aspnetcore/fundamentals/openapi/openapi-comments.md new file mode 100644 index 000000000000..407d868ebc06 --- /dev/null +++ b/aspnetcore/fundamentals/openapi/openapi-comments.md @@ -0,0 +1,192 @@ +--- +title: ASP.NET Core OpenAPI XML documentation comment support in ASP.NET Core +author: captainsafia +description: Learn how to integrate XML documentation comments on types by OpenAPI document generation in ASP.NET Core. +ms.author: safia +monikerRange: '>= aspnetcore-10.0' +ms.custom: mvc +ms.date: 4/12/2025 +uid: fundamentals/openapi/aspnet-openapi-xml +--- + +# OpenAPI XML documentation comment support in ASP.NET Core + +ASP.NET Core XML documentation processing extracts code comments automatically to populate API documentation, ensuring the code and documentation remain synchronized. Metadata from XML documentation comments is included in the generated OpenAPI document without requiring changes to the app code, as long as the project is configured to generate the XML documentation file. XML documentation comments are automatically detected in the application assembly and referenced assemblies with XML documentation enabled. + +ASP.NET Core processes [XML documentation tags](https://learn.microsoft.com/dotnet/csharp/language-reference/xmldoc/recommended-tags) like: ``, ``, ``, ``, ``, ``, ``, and ``. For XML documentation tags that use references to other elements, like ``, the implementation strips out the XML tag and maps the reference to plain text for inclusion in the OpenAPI document. + +ASP.NET Core XML documentation processing doesn't affect runtime performance. The source generator processes XML documentation at compile time and caches the results, with minimal runtime overhead when rendering the OpenAPI documentation. Furthermore, the OpenAPI document can be cached at runtime using [output-caching](/aspnet/core/performance/caching/overview#output-caching) to further optimize performance. + +This article includes a [sample app](#download10) that demonstrates the [`Microsoft.AspNetCore.OpenApi`](https://www.nuget.org/packages/Microsoft.AspNetCore.OpenApi) package's ability to integrate XML documentation comments on types into OpenAPI documents. The sample app is a minimal ASP.NET Core Web API project to generate OpenAPI documents. The XML documentation comments are used to populate summaries, descriptions, parameter information, and response details in the generated OpenAPI document. + +The following image shows the Scalar UI with XML documentation comments integrated into the OpenAPI document of the sample app: + +![screenshot of app with XML comments in sclaar UI](~/fundamentals/openapi/_static/screenshot.png) + +### Supported XML documentation tags + +* [``](/dotnet/csharp/language-reference/xmldoc/recommended-tags#summary) +* [``](/dotnet/csharp/language-reference/xmldoc/recommended-tags#remarks) +* [``](/dotnet/csharp/language-reference/xmldoc/recommended-tags#param) +* [``](/dotnet/csharp/language-reference/xmldoc/recommended-tags#returns) +* [``](/dotnet/csharp/language-reference/xmldoc/recommended-tags#response) +* [``](/dotnet/csharp/language-reference/xmldoc/recommended-tags#example) +* [``](/dotnet/csharp/language-reference/xmldoc/recommended-tags#deprecated) +* [``](/dotnet/csharp/language-reference/xmldoc/recommended-tags#inheritdoc) + +### Document HTTP responses + +Document HTTP responses with the `` tag and the `code` attribute: + +:::code language="csharp" source="~/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/ProjectBoardApis.cs" id="snippet_1" highlight="6-7"::: + + + +### Add examples + +To add examples to documentation, use the [``](/dotnet/csharp/language-reference/xmldoc/recommended-tags#example) tag for types or the `example` attribute for parameters: + +```csharp +/// {"name":"Sample","value":42} +/// The unique identifier +``` + +## Customizing XML documentation behavior + +The following sections describe how to enable and customize XML documentation support. + +### Enable XML documentation in an ASP.NET Core API project + +1. Enable XML documentation in the project file: + + :::code language="xml" source="~/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/Models.csproj" highlight="7"::: + +2. Use the [AddOpenApi](xref:Microsoft.Extensions.DependencyInjection.OpenApiServiceCollectionExtensions.AddOpenApi*) method in the service configuration. No configuration is needed, the source generator handles the rest. + + :::code language="csharp" source="~/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Program.cs" highlight="6"::: + +The source generator detects all standard overloads: + +* [`AddOpenApi()`](xref:Microsoft.Extensions.DependencyInjection.OpenApiServiceCollectionExtensions.AddOpenApi(Microsoft.Extensions.DependencyInjection.IServiceCollection)) +* [`AddOpenApi("v1")`](xref:Microsoft.Extensions.DependencyInjection.OpenApiServiceCollectionExtensions.AddOpenApi(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.String)) +* [`AddOpenApi(options => {})`](xref:Microsoft.Extensions.DependencyInjection.OpenApiServiceCollectionExtensions.AddOpenApi(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Action{Microsoft.AspNetCore.OpenApi.OpenApiOptions})) +* [`AddOpenApi("v1", options => {})`](xref:Microsoft.Extensions.DependencyInjection.OpenApiServiceCollectionExtensions.AddOpenApi(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.String,System.Action{Microsoft.AspNetCore.OpenApi.OpenApiOptions})) + +Each overload is intercepted to automatically include the XML documentation transformers. The source generator doesn't handle overloads where the `documentName` parameter isn't a literal string expression. For example, the transformer isn't registered in the following scenarios: + +```csharp +var documentName = "v1"; +builder.Services.AddOpenApi(documentName); // No XML support +``` + +### Add XML documentation sources + +The [`Microsoft.AspNetCore.OpenApi`](https://www.nuget.org/packages/Microsoft.AspNetCore.OpenApi) NuGet package automatically resolves XML documentation comments from: + +* The application assembly, when the `GenerateDocumentationFile` property is set. In the [sample app](#download10), the `API` project. + + :::code language="xml" source="~/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/Models.csproj" highlight="7"::: + +* Any projects referenced via `ProjectReferences` that have the `GenerateDocumentationFile` property set. In the sample app, the `Models` project: + + :::code language="xml" source="~/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Api.csproj" highlight="7,16"::: + +The implementation discovers XML files statically at compile-time. The `AdditionalFiles` item group specifies additional sources for XML files: + + :::code language="xml" source="~/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/AdditionalFiles.xml" highlight="7"::: + +To include XML documentation files from referenced assemblies, add them as `AdditionalFiles` in the project: + +```xml + + + +``` + +#### Disabling XML documentation support + +To turn off XML documentation integration, remove the source generator from the `Analyzers` item group. Removing the source generator prevents it from being used during compilation. + +:::code language="xml" source="~/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Api-remove.csproj.xml" highlight="7,19-23"::: + + + +## Source generator implementation + +The XML documentation feature is implemented as a source generator. The source generator analyzes XML documentation comments at compile time and injects code that translates these comments into OpenAPI metadata. The [`XmlCommentGenerator`](https://source.dot.net/#Microsoft.AspNetCore.OpenApi.SourceGenerators/XmlCommentGenerator.cs,30eb0aa73ef6306a) extracts XML comments from two sources: + +* XML documentation files passed as `AdditionalFiles` via a [`ParseXmlFile`](https://source.dot.net/#Microsoft.AspNetCore.OpenApi.SourceGenerators/XmlCommentGenerator.Parser.cs,f7dff3af661aebc2) implementation. +* XML comments from the target assembly's own code via a [`ParseCompilation`](https://source.dot.net/#Microsoft.AspNetCore.OpenApi.SourceGenerators/XmlCommentGenerator.Parser.cs,45358a4d0fff76ac) implementation. + +The distinction between these two sources is important. XML documentation files passed as `AdditionalFiles` are static. XML comments from the target assembly come from Roslyn's [XML documentation comments provider](https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/Portable/MetadataReference/PortableExecutableReference.cs#L48-L62). The XML documentation comments provider enhances functionality for connecting an XML comment to the compilation symbol's that it's associated with. This has implications for the way `` resolution happens in the implementation, discussed in the next section. + +XML comments are parsed into structured `XmlComment` objects with: + +* Summary, description, remarks, returns, value sections. +* Parameter documentation with name, description, examples. +* Response documentation with status codes and descriptions. +* Support for examples and deprecated markers. + +### `` + +The generator supports [``](/dotnet/csharp/language-reference/xmldoc/recommended-tags#inheritdoc) tags, which inherit documentation *as long as they exist in the compilation assembly*. `` tags indicate that comments must be resolved from: + +* Base classes +* Implemented interfaces +* Base methods for overrides + +When `` is placed on a symbol, The source generator: + +* Uses its knowledge of the symbol in the compilation to discover base classes and interfaces associated with the symbol. +* Supports resolving them automatically +* Substitutes generic type parameters in inherited documentation comments, preserving type references across inheritance boundaries. + +The automatic resolution behavior is currently available for XML documentation comments that exist in the assembly under compilation, and ***not*** XML documentation tags that are in referenced projects or packages. In the later scenario, XML documentation comments: + +* Are only presented as text. +* Don't provide a trivial strategy for: + * Associating the text content to compilation symbols. + * Developing an understanding of the inheritance hierarchy associated with the types. + +XML documentation comments from `ProjectReferences` are automatically resolved and don't require additional configuration. + + + +## Download and run the API sample + + +Download the [sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/openapi/samples) for this article. + +To run the sample, navigate to the `api` directory and enter `dotnet run`. + +```dotnetcli +cd api +dotnet run +``` + +Output similar to the following is displayed: + +```dotnetcli +Building... +info: Microsoft.Hosting.Lifetime[14] + Now listening on: http://localhost:5052 +info: Microsoft.Hosting.Lifetime[0] + Application started. Press Ctrl+C to shut down. +info: Microsoft.Hosting.Lifetime[0] + Hosting environment: Development +info: Microsoft.Hosting.Lifetime[0] + Content root path: ~/git/aspnet-openapi-xml/api +``` + +Navigate to [http://localhost:5052/](http://localhost:5052/) to view the Scalar UI for interacting with the app. The Scalar UI includes summaries and descriptions on various elements sourced from XML documentation comments. + +## Additional resources + +* [Source generator implementation notes](https://github.com/captainsafia/aspnet-openapi-xml#implementation-notes) +* The source generator implementation can be found in the [ASP.NET Core repository](https://github.com/dotnet/aspnetcore/tree/main/src/OpenApi/gen). +* +* +* diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/AdditionalFiles.xml b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/AdditionalFiles.xml new file mode 100644 index 000000000000..c320a477b4a3 --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/AdditionalFiles.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Api-remove.csproj.xml b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Api-remove.csproj.xml new file mode 100644 index 000000000000..dcac4167bbff --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Api-remove.csproj.xml @@ -0,0 +1,26 @@ + + + + net10.0 + enable + enable + true + + + + + + + + + + + + + + + + + + + diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Api.csproj b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Api.csproj new file mode 100644 index 000000000000..a01535c1ee80 --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Api.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + enable + enable + true + + + + + + + + + + + + diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Api.http b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Api.http new file mode 100644 index 000000000000..c9bb55fff877 --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Api.http @@ -0,0 +1,73 @@ +@Api_HostAddress = http://localhost:5052 + +GET {{Api_HostAddress}}/weatherforecast/ +Accept: application/json + +### Project Board Endpoints ### + +### Get all project boards +GET {{Api_HostAddress}}/api/projectboards +Accept: application/json + +### Get project board by ID +GET {{Api_HostAddress}}/api/projectboards/1 +Accept: application/json + +### Create a new project board +POST {{Api_HostAddress}}/api/projectboards +Content-Type: application/json + +{ + "name": "Website Redesign", + "description": "Tasks for redesigning the company website" +} + +### Update a project board +PUT {{Api_HostAddress}}/api/projectboards/1 +Content-Type: application/json + +{ + "name": "Website Redesign v2", + "description": "Updated tasks for redesigning the company website" +} + +### Delete a project board +DELETE {{Api_HostAddress}}/api/projectboards/1 + + +### Todo Endpoints ### + +### Get all todos for a project board +GET {{Api_HostAddress}}/api/projectboards/1/todos +Accept: application/json + +### Get a specific todo by ID +GET {{Api_HostAddress}}/api/projectboards/1/todos/1 +Accept: application/json + +### Create a new todo +POST {{Api_HostAddress}}/api/projectboards/1/todos +Content-Type: application/json + +{ + "title": "Design new homepage", + "description": "Create wireframes for the new homepage design", + "isComplete": false, + "priority": 2, + "dueDate": "2025-03-20T00:00:00Z" +} + +### Update a todo +PUT {{Api_HostAddress}}/api/projectboards/1/todos/1 +Content-Type: application/json + +{ + "title": "Design new homepage with feedback", + "description": "Update wireframes based on stakeholder feedback", + "isComplete": true, + "priority": 3, + "dueDate": "2025-03-25T00:00:00Z" +} + +### Delete a todo +DELETE {{Api_HostAddress}}/api/projectboards/1/todos/1 diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Program.cs b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Program.cs new file mode 100644 index 000000000000..0ab21806164f --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/Program.cs @@ -0,0 +1,20 @@ +using Api; +using Scalar.AspNetCore; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddOpenApi(); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.MapOpenApi(); + app.MapScalarApiReference(); +} + +app.Map("/", () => Results.Redirect("/scalar/v1")); +app.MapProjectBoardApis(); +app.MapTodoApis(); + +app.Run(); diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/ProjectBoardApis.cs b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/ProjectBoardApis.cs new file mode 100644 index 000000000000..2039da1e50b4 --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/ProjectBoardApis.cs @@ -0,0 +1,120 @@ +using Models; +using Microsoft.AspNetCore.Http.HttpResults; +using System.ComponentModel.DataAnnotations; + +namespace Api; + +/// +/// Extension methods for mapping ProjectBoard-related API endpoints. +/// +public static class ProjectBoardApis +{ + // In-memory storage for demo purposes + internal static readonly List Boards = new(); + private static int _nextBoardId = 1; + + /// + /// Maps all ProjectBoard related API endpoints to the application. + /// + /// The endpoint route builder. + public static void MapProjectBoardApis(this IEndpointRouteBuilder app) + { + var boardGroup = app.MapGroup("/api/projectboards") + .WithTags("Project Boards") + .WithOpenApi(); + + // Project Board endpoints + boardGroup.MapGet("/", GetAllProjectBoards); + boardGroup.MapGet("/{id}", GetProjectBoardById); + boardGroup.MapPost("/", CreateProjectBoard); + boardGroup.MapPut("/{id}", UpdateProjectBoard); + boardGroup.MapDelete("/{id}", DeleteProjectBoard); + } + + /// + /// Retrieves all project boards. + /// + /// A collection of all project boards. + /// Returns the list of project boards. + public static IResult GetAllProjectBoards() + { + return Results.Ok(Boards); + } + + // + /// + /// Retrieves a specific project board by ID. + /// + /// The ID of the project board to retrieve. + /// The requested project board. + /// Returns the requested project board. + /// If the project board is not found. + public static IResult GetProjectBoardById(int id) + { + var board = Boards.FirstOrDefault(b => b.Id == id); + if (board == null) + { + return Results.NotFound(); + } + return Results.Ok(board); + } + // + + /// + /// Creates a new project board. + /// + /// The project board to create. + /// The newly created project board. + /// Returns the newly created project board. + /// If the project board data is invalid. + public static IResult CreateProjectBoard(ProjectBoard board) + { + board.Id = _nextBoardId++; + board.CreatedAt = DateTime.UtcNow; + Boards.Add(board); + + return Results.Created($"/api/projectboards/{board.Id}", board); + } + + /// + /// Updates an existing project board. + /// + /// The ID of the project board to update. + /// The updated project board data. + /// No content if successful. + /// If the update was successful. + /// If the project board data is invalid. + /// If the project board is not found. + public static IResult UpdateProjectBoard(int id, ProjectBoard updatedBoard) + { + var board = Boards.FirstOrDefault(b => b.Id == id); + if (board == null) + { + return Results.NotFound(); + } + + board.Name = updatedBoard.Name; + board.Description = updatedBoard.Description; + + return Results.NoContent(); + } + + /// + /// Deletes a project board. + /// + /// The ID of the project board to delete. + /// No content if successful. + /// If the deletion was successful. + /// If the project board is not found. + public static IResult DeleteProjectBoard(int id) + { + var board = Boards.FirstOrDefault(b => b.Id == id); + if (board == null) + { + return Results.NotFound(); + } + + Boards.Remove(board); + return Results.NoContent(); + } +} diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/TodoApis.cs b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/TodoApis.cs new file mode 100644 index 000000000000..30883c86eae0 --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/TodoApis.cs @@ -0,0 +1,158 @@ +using Models; +using Microsoft.AspNetCore.Http.HttpResults; +using System.ComponentModel.DataAnnotations; + +namespace Api; + +/// +/// Extension methods for mapping Todo-related API endpoints. +/// +public static class TodoApis +{ + private static int _nextTodoId = 1; + + /// + /// Maps all ProjectBoard related API endpoints to the application. + /// + /// The endpoint route builder. + public static void MapTodoApis(this IEndpointRouteBuilder app) + { + // Todo endpoints + var todoGroup = app.MapGroup("/api/projectboards/{boardId}/todos") + .WithTags("Todos"); + + todoGroup.MapGet("/", GetAllTodos); + todoGroup.MapGet("/{id}", GetTodoById); + todoGroup.MapPost("/", CreateTodo); + todoGroup.MapPut("/{id}", UpdateTodo); + todoGroup.MapDelete("/{id}", DeleteTodo); + } + + /// + /// Retrieves all todos for a specific project board. + /// + /// The ID of the project board. + /// A collection of todos for the specified project board. + /// Returns the list of todos. + /// If the project board is not found. + public static IResult GetAllTodos(int boardId) + { + var board = ProjectBoardApis.Boards.FirstOrDefault(b => b.Id == boardId); + if (board == null) + { + return Results.NotFound("Project board not found"); + } + + return Results.Ok(board.Todos); + } + + /// + /// Retrieves a specific todo by ID within a project board. + /// + /// The ID of the project board. + /// The ID of the todo to retrieve. + /// The requested todo. + /// Returns the requested todo. + /// If the project board or todo is not found. + public static IResult GetTodoById(int boardId, int id) + { + var board = ProjectBoardApis.Boards.FirstOrDefault(b => b.Id == boardId); + if (board == null) + { + return Results.NotFound("Project board not found"); + } + + var todo = board.Todos.FirstOrDefault(t => t.Id == id); + if (todo == null) + { + return Results.NotFound("Todo not found"); + } + + return Results.Ok(todo); + } + + /// + /// Creates a new todo within a project board. + /// + /// The ID of the project board. + /// The todo to create. + /// The newly created todo. + /// Returns the newly created todo. + /// If the todo data is invalid. + /// If the project board is not found. + public static IResult CreateTodo(int boardId, Todo todo) + { + var board = ProjectBoardApis.Boards.FirstOrDefault(b => b.Id == boardId); + if (board == null) + { + return Results.NotFound("Project board not found"); + } + + todo.Id = _nextTodoId++; + todo.ProjectBoardId = boardId; + todo.CreatedAt = DateTime.UtcNow; + + board.Todos.Add(todo); + + return Results.Created($"/api/projectboards/{boardId}/todos/{todo.Id}", todo); + } + + /// + /// Updates an existing todo within a project board. + /// + /// The ID of the project board. + /// The ID of the todo to update. + /// The updated todo data. + /// No content if successful. + /// If the update was successful. + /// If the todo data is invalid. + /// If the project board or todo is not found. + public static IResult UpdateTodo(int boardId, int id, Todo updatedTodo) + { + var board = ProjectBoardApis.Boards.FirstOrDefault(b => b.Id == boardId); + if (board == null) + { + return Results.NotFound("Project board not found"); + } + + var todo = board.Todos.FirstOrDefault(t => t.Id == id); + if (todo == null) + { + return Results.NotFound("Todo not found"); + } + + todo.Title = updatedTodo.Title; + todo.Description = updatedTodo.Description; + todo.IsComplete = updatedTodo.IsComplete; + todo.Priority = updatedTodo.Priority; + todo.DueDate = updatedTodo.DueDate; + + return Results.NoContent(); + } + + /// + /// Deletes a todo from a project board. + /// + /// The ID of the project board. + /// The ID of the todo to delete. + /// No content if successful. + /// If the deletion was successful. + /// If the project board or todo is not found. + public static IResult DeleteTodo(int boardId, int id) + { + var board = ProjectBoardApis.Boards.FirstOrDefault(b => b.Id == boardId); + if (board == null) + { + return Results.NotFound("Project board not found"); + } + + var todo = board.Todos.FirstOrDefault(t => t.Id == id); + if (todo == null) + { + return Results.NotFound("Todo not found"); + } + + board.Todos.Remove(todo); + return Results.NoContent(); + } +} \ No newline at end of file diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/appsettings.Development.json b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/appsettings.Development.json new file mode 100644 index 000000000000..0c208ae9181e --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/appsettings.json b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/appsettings.json new file mode 100644 index 000000000000..10f68b8c8b4f --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/api/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/aspnet-openapi-xml.sln b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/aspnet-openapi-xml.sln new file mode 100644 index 000000000000..983afa54fd35 --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/aspnet-openapi-xml.sln @@ -0,0 +1,56 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "api", "api", "{D82C56D6-B2CD-F611-9E31-04638F7EC30E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Api", "api\Api.csproj", "{CA8C523E-275A-4315-B784-20AE102810EB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "models", "models", "{7E5E3D99-03B0-3438-6A3D-D9E8D97DA366}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Models", "models\Models.csproj", "{951E9171-FE43-4DDF-B296-553992898447}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CA8C523E-275A-4315-B784-20AE102810EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA8C523E-275A-4315-B784-20AE102810EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA8C523E-275A-4315-B784-20AE102810EB}.Debug|x64.ActiveCfg = Debug|Any CPU + {CA8C523E-275A-4315-B784-20AE102810EB}.Debug|x64.Build.0 = Debug|Any CPU + {CA8C523E-275A-4315-B784-20AE102810EB}.Debug|x86.ActiveCfg = Debug|Any CPU + {CA8C523E-275A-4315-B784-20AE102810EB}.Debug|x86.Build.0 = Debug|Any CPU + {CA8C523E-275A-4315-B784-20AE102810EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA8C523E-275A-4315-B784-20AE102810EB}.Release|Any CPU.Build.0 = Release|Any CPU + {CA8C523E-275A-4315-B784-20AE102810EB}.Release|x64.ActiveCfg = Release|Any CPU + {CA8C523E-275A-4315-B784-20AE102810EB}.Release|x64.Build.0 = Release|Any CPU + {CA8C523E-275A-4315-B784-20AE102810EB}.Release|x86.ActiveCfg = Release|Any CPU + {CA8C523E-275A-4315-B784-20AE102810EB}.Release|x86.Build.0 = Release|Any CPU + {951E9171-FE43-4DDF-B296-553992898447}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {951E9171-FE43-4DDF-B296-553992898447}.Debug|Any CPU.Build.0 = Debug|Any CPU + {951E9171-FE43-4DDF-B296-553992898447}.Debug|x64.ActiveCfg = Debug|Any CPU + {951E9171-FE43-4DDF-B296-553992898447}.Debug|x64.Build.0 = Debug|Any CPU + {951E9171-FE43-4DDF-B296-553992898447}.Debug|x86.ActiveCfg = Debug|Any CPU + {951E9171-FE43-4DDF-B296-553992898447}.Debug|x86.Build.0 = Debug|Any CPU + {951E9171-FE43-4DDF-B296-553992898447}.Release|Any CPU.ActiveCfg = Release|Any CPU + {951E9171-FE43-4DDF-B296-553992898447}.Release|Any CPU.Build.0 = Release|Any CPU + {951E9171-FE43-4DDF-B296-553992898447}.Release|x64.ActiveCfg = Release|Any CPU + {951E9171-FE43-4DDF-B296-553992898447}.Release|x64.Build.0 = Release|Any CPU + {951E9171-FE43-4DDF-B296-553992898447}.Release|x86.ActiveCfg = Release|Any CPU + {951E9171-FE43-4DDF-B296-553992898447}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {CA8C523E-275A-4315-B784-20AE102810EB} = {D82C56D6-B2CD-F611-9E31-04638F7EC30E} + {951E9171-FE43-4DDF-B296-553992898447} = {7E5E3D99-03B0-3438-6A3D-D9E8D97DA366} + EndGlobalSection +EndGlobal diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/global.json b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/global.json new file mode 100644 index 000000000000..e66d411f46b5 --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "10.0.100-preview.2.25163.38" + } +} \ No newline at end of file diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/Models.csproj b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/Models.csproj new file mode 100644 index 000000000000..8c5021ca97e6 --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/Models.csproj @@ -0,0 +1,10 @@ + + + + net10.0 + enable + enable + true + + + diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/ProjectBoard.cs b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/ProjectBoard.cs new file mode 100644 index 000000000000..cf5a10323f69 --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/ProjectBoard.cs @@ -0,0 +1,32 @@ +namespace Models; + +/// +/// Represents a project board containing todos and related information. +/// +public class ProjectBoard +{ + /// + /// Unique identifier for the project board. + /// + public int Id { get; set; } + + /// + /// The name of the project board. + /// + public string Name { get; set; } = string.Empty; + + /// + /// A description of the project board and its purpose. + /// + public string? Description { get; set; } + + /// + /// The date when the project board was created. + /// + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + + /// + /// The collection of todos associated with this project board. + /// + public List Todos { get; set; } = new(); +} diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/Todo.cs b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/Todo.cs new file mode 100644 index 000000000000..b98bfcb0eb15 --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/Todo.cs @@ -0,0 +1,47 @@ +namespace Models; + +/// +/// Represents a todo item within a project board. +/// +public class Todo +{ + /// + /// Unique identifier for the todo item. + /// + public int Id { get; set; } + + /// + /// The title or brief description of the todo. + /// + public string Title { get; set; } = string.Empty; + + /// + /// A detailed description of the todo item. + /// + public string? Description { get; set; } + + /// + /// Indicates whether the todo has been completed. + /// + public bool IsComplete { get; set; } + + /// + /// The priority level of the todo item. + /// + public TodoPriority Priority { get; set; } = TodoPriority.Medium; + + /// + /// The date when the todo was created. + /// + public DateTime CreatedAt { get; set; } = DateTime.UtcNow; + + /// + /// The date when the todo is due to be completed. + /// + public DateTime? DueDate { get; set; } + + /// + /// The ID of the project board this todo belongs to. + /// + public int ProjectBoardId { get; set; } +} \ No newline at end of file diff --git a/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/TodoPriority.cs b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/TodoPriority.cs new file mode 100644 index 000000000000..914c64320942 --- /dev/null +++ b/aspnetcore/fundamentals/openapi/samples/10.x/aspnet-openapi-xml/models/TodoPriority.cs @@ -0,0 +1,27 @@ +namespace Models; + +/// +/// Represents the priority level of a todo item. +/// +public enum TodoPriority +{ + /// + /// Low priority items that can be addressed later. + /// + Low = 0, + + /// + /// Medium priority items that should be addressed in a reasonable timeframe. + /// + Medium = 1, + + /// + /// High priority items that should be addressed soon. + /// + High = 2, + + /// + /// Critical items that require immediate attention. + /// + Critical = 3 +} \ No newline at end of file diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index b726bc67fafb..9f8364503095 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -874,6 +874,8 @@ items: uid: fundamentals/openapi/aspnetcore-openapi - name: Include OpenAPI metadata uid: fundamentals/openapi/include-metadata + - name: XML doc comment support + uid: fundamentals/openapi/aspnet-openapi-xml - name: Customize OpenAPI documents uid: fundamentals/openapi/customize-openapi - name: Use OpenAPI documents