diff --git a/aspnetcore/blazor/fundamentals/signalr.md b/aspnetcore/blazor/fundamentals/signalr.md index fea583074ea0..b933c78577e7 100644 --- a/aspnetcore/blazor/fundamentals/signalr.md +++ b/aspnetcore/blazor/fundamentals/signalr.md @@ -316,25 +316,43 @@ app.MapBlazorHub(options => }); ``` - + -Configuring the hub used by with fails with an `AmbiguousMatchException`: +Configuring the hub used by with fails with an : > :::no-loc text="Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints."::: -To workaround the problem for apps targeting .NET 8, give the custom-configured Blazor hub higher precedence using the method: +To workaround the problem for apps targeting .NET 8/9, take the following approach. + +At the top of the `Program` file, add a `using` statement for : ```csharp -app.MapBlazorHub(options => -{ - options.CloseOnAuthenticationExpiration = true; -}).WithOrder(-1); +using Microsoft.AspNetCore.Http.Connections; +``` + +Where is called, chain the following endpoint convention to the : + +```csharp +app.MapRazorComponents() + .AddInteractiveServerRenderMode() + .Add(e => + { + var metadata = e.Metadata; + var dispatcherOptions = metadata.OfType().FirstOrDefault(); + + if (dispatcherOptions != null) + { + dispatcherOptions.CloseOnAuthenticationExpiration = true; + } + }); ``` For more information, see the following resources: * [MapBlazorHub configuration in NET8 throws a The request matched multiple endpoints exception (`dotnet/aspnetcore` #51698)](https://github.com/dotnet/aspnetcore/issues/51698#issuecomment-1984340954) * [Attempts to map multiple blazor entry points with MapBlazorHub causes Ambiguous Route Error. This worked with net7 (`dotnet/aspnetcore` #52156)](https://github.com/dotnet/aspnetcore/issues/52156#issuecomment-1984503178) +* [[Blazor] Provide access to the underlying SignalR HttpConnectionDispatcherOptions in AddInteractiveServerRenderMode (`dotnet/aspnetcore` #63520)](https://github.com/dotnet/aspnetcore/issues/63520) :::moniker-end diff --git a/aspnetcore/blazor/security/includes/redirecttologin-component.md b/aspnetcore/blazor/security/includes/redirecttologin-component.md index dd068389fa03..e7d0848fe0e1 100644 --- a/aspnetcore/blazor/security/includes/redirecttologin-component.md +++ b/aspnetcore/blazor/security/includes/redirecttologin-component.md @@ -7,4 +7,29 @@ The `RedirectToLogin` component (`RedirectToLogin.razor`): Inspect the `RedirectToLogin` component in [reference source](https://github.com/dotnet/aspnetcore/tree/main/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp). The location of the component changed over time, so use GitHub search tools to locate the component. +The login path can be customized by the app (, [framework defaults (`dotnet/aspnetcore` reference source)](https://github.com/dotnet/aspnetcore/blob/main/src/Components/WebAssembly/WebAssembly.Authentication/src/RemoteAuthenticationDefaults.cs)). The project template's `RedirectToLogin` component uses the default login path of `authentication/login`. + [!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] + +If an app [customizes the login path](xref:blazor/security/webassembly/additional-scenarios#customize-app-routes), take either of the following approaches: + +* Match the path in the hard-coded string in the `RedirectToLogin` component. +* Inject to obtain the configured value. For example, take this approach when you customize the path with . + Add the following directives at the top of the `RedirectToLogin` component: + + ```razor + @using Microsoft.Extensions.Options + @inject IOptionsSnapshot> RemoteOptions + ``` + + Modify the component's redirect in the `OnInitialized` method: + + ```diff + - Navigation.NavigateToLogin("authentication/login"); + + Navigation.NavigateToLogin(RemoteOptions.Get(Options.DefaultName) + + .AuthenticationPaths.LogInPath); + ``` + + > [!NOTE] + > If other paths differ from the project template's paths or [framework's default paths](https://github.com/dotnet/aspnetcore/blob/main/src/Components/WebAssembly/WebAssembly.Authentication/src/RemoteAuthenticationDefaults.cs), they should managed in the same fashion. + diff --git a/aspnetcore/fundamentals/error-handling.md b/aspnetcore/fundamentals/error-handling.md index 0b8c43977ade..c1844501a9ed 100644 --- a/aspnetcore/fundamentals/error-handling.md +++ b/aspnetcore/fundamentals/error-handling.md @@ -12,7 +12,7 @@ uid: fundamentals/error-handling [!INCLUDE[](~/includes/not-latest-version.md)] -:::moniker range=">= aspnetcore-9.0" +:::moniker range=">= aspnetcore-10.0" This article covers common approaches to handling errors in ASP.NET Core web apps. See also . @@ -343,8 +343,10 @@ An alternative approach to generate problem details is to use the third-party Nu * * * +* [Breaking change: Exception diagnostics are suppressed when `IExceptionHandler.TryHandleAsync` returns true](https://github.com/aspnet/Announcements/issues/524) :::moniker-end +[!INCLUDE[](~/fundamentals/error-handling/includes/error-handling9.md)] [!INCLUDE[](~/fundamentals/error-handling/includes/error-handling8.md)] [!INCLUDE[](~/fundamentals/error-handling/includes/error-handling3-7.md)] diff --git a/aspnetcore/fundamentals/error-handling/includes/error-handling9.md b/aspnetcore/fundamentals/error-handling/includes/error-handling9.md new file mode 100644 index 000000000000..a9ba47d51781 --- /dev/null +++ b/aspnetcore/fundamentals/error-handling/includes/error-handling9.md @@ -0,0 +1,333 @@ +:::moniker range="= aspnetcore-9.0" + +This article covers common approaches to handling errors in ASP.NET Core web apps. See also . + +For Blazor error handling guidance, which adds to or supersedes the guidance in this article, see . + +## Developer exception page + +[!INCLUDE [](../../../includes/developer-exception-page.md)] + +## Exception handler page + +To configure a custom error handling page for the [Production environment](xref:fundamentals/environments), call . This exception handling middleware: + +* Catches and logs unhandled exceptions. +* Re-executes the request in an alternate pipeline using the path indicated. The request isn't re-executed if the response has started. The template-generated code re-executes the request using the `/Error` path. + +> [!WARNING] +> If the alternate pipeline throws an exception of its own, Exception Handling Middleware rethrows the original exception. + +Since this middleware can re-execute the request pipeline: + +* Middlewares need to handle reentrancy with the same request. This normally means either cleaning up their state after calling `_next` or caching their processing on the `HttpContext` to avoid redoing it. When dealing with the request body, this either means buffering or caching the results like the Form reader. +* For the overload that is used in templates, only the request path is modified, and the route data is cleared. Request data such as headers, method, and items are all reused as-is. +* Scoped services remain the same. + +In the following example, adds the exception handling middleware in non-Development environments: + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Program.cs" id="snippet_UseExceptionHandler" highlight="3,5"::: + +The Razor Pages app template provides an Error page (`.cshtml`) and class (`ErrorModel`) in the *Pages* folder. For an MVC app, the project template includes an `Error` action method and an Error view for the Home controller. + +The exception handling middleware re-executes the request using the *original* HTTP method. If an error handler endpoint is restricted to a specific set of HTTP methods, it runs only for those HTTP methods. For example, an MVC controller action that uses the `[HttpGet]` attribute runs only for GET requests. To ensure that *all* requests reach the custom error handling page, don't restrict them to a specific set of HTTP methods. + +To handle exceptions differently based on the original HTTP method: + +* For Razor Pages, create multiple handler methods. For example, use `OnGet` to handle GET exceptions and use `OnPost` to handle POST exceptions. +* For MVC, apply HTTP verb attributes to multiple actions. For example, use `[HttpGet]` to handle GET exceptions and use `[HttpPost]` to handle POST exceptions. + +To allow unauthenticated users to view the custom error handling page, ensure that it supports anonymous access. + +### Access the exception + +Use to access the exception and the original request path in an error handler. The following example uses `IExceptionHandlerPathFeature` to get more information about the exception that was thrown: + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Pages/Error.cshtml.cs" id="snippet_Class" highlight="15-27"::: + +> [!WARNING] +> Do **not** serve sensitive error information to clients. Serving errors is a security risk. + +## Exception handler lambda + +An alternative to a [custom exception handler page](#exception-handler-page) is to provide a lambda to . Using a lambda allows access to the error before returning the response. + +The following code uses a lambda for exception handling: + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Snippets/Program.cs" id="snippet_UseExceptionHandlerInline" highlight="5-29"::: + +Another way to use a lambda is to set the status code based on the exception type, as in the following example: + +:::code language="csharp" source="~/fundamentals/error-handling/samples/9.x/ErrorHandlingSample/Program.cs" id="snippet_lambda" highlight="2,6-11"::: + +> [!WARNING] +> Do **not** serve sensitive error information to clients. Serving errors is a security risk. + +## IExceptionHandler + +[IExceptionHandler](/dotnet/api/microsoft.aspnetcore.diagnostics.iexceptionhandler) is an interface that gives the developer a callback for handling known exceptions in a central location. + +`IExceptionHandler` implementations are registered by calling [`IServiceCollection.AddExceptionHandler`](/dotnet/api/microsoft.extensions.dependencyinjection.exceptionhandlerservicecollectionextensions.addexceptionhandler). The lifetime of an `IExceptionHandler` instance is singleton. Multiple implementations can be added, and they're called in the order registered. + +If an exception handler handles a request, it can return `true` to stop processing. If an exception isn't handled by any exception handler, then control falls back to the default behavior and options from the middleware. Different metrics and logs are emitted for handled versus unhandled exceptions. + +The following example shows an `IExceptionHandler` implementation: + +:::code language="csharp" source="~/fundamentals/error-handling/samples/8.x/ErrorHandlingSample/CustomExceptionHandler.cs"::: + +The following example shows how to register an `IExceptionHandler` implementation for dependency injection: + +:::code language="csharp" source="~/fundamentals/error-handling/samples/8.x/ErrorHandlingSample/Program.cs" id="snippet_RegisterIExceptionHandler" highlight="7"::: + +When the preceding code runs in the Development environment: + +* The `CustomExceptionHandler` is called first to handle an exception. +* After logging the exception, the `TryHandleAsync` method returns `false`, so the [developer exception page](#developer-exception-page) is shown. + +In other environments: + +* The `CustomExceptionHandler` is called first to handle an exception. +* After logging the exception, the `TryHandleAsync` method returns `false`, so the [`/Error` page](#exception-handler-page) is shown. + + + + +## UseStatusCodePages + +By default, an ASP.NET Core app doesn't provide a status code page for HTTP error status codes, such as *404 - Not Found*. When the app sets an HTTP 400-599 error status code that doesn't have a body, it returns the status code and an empty response body. To enable default text-only handlers for common error status codes, call in `Program.cs`: + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Snippets/Program.cs" id="snippet_UseStatusCodePages" highlight="9"::: + +Call `UseStatusCodePages` before request handling middleware. For example, call `UseStatusCodePages` before the Static File Middleware and the Endpoints Middleware. + +When `UseStatusCodePages` isn't used, navigating to a URL without an endpoint returns a browser-dependent error message indicating the endpoint can't be found. When `UseStatusCodePages` is called, the browser returns the following response: + +```console +Status Code: 404; Not Found +``` + +`UseStatusCodePages` isn't typically used in production because it returns a message that isn't useful to users. + +> [!NOTE] +> The status code pages middleware does **not** catch exceptions. To provide a custom error handling page, use the [exception handler page](#exception-handler-page). + +### UseStatusCodePages with format string + +To customize the response content type and text, use the overload of that takes a content type and format string: + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Snippets/Program.cs" id="snippet_UseStatusCodePagesContent" highlight="10"::: + +In the preceding code, `{0}` is a placeholder for the error code. + +`UseStatusCodePages` with a format string isn't typically used in production because it returns a message that isn't useful to users. + +### UseStatusCodePages with lambda + +To specify custom error-handling and response-writing code, use the overload of that takes a lambda expression: + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Snippets/Program.cs" id="snippet_UseStatusCodePagesInline" highlight="9-16"::: + +`UseStatusCodePages` with a lambda isn't typically used in production because it returns a message that isn't useful to users. + +### UseStatusCodePagesWithRedirects + +The extension method: + +* Sends a [302 - Found](https://developer.mozilla.org/docs/Web/HTTP/Status/302) status code to the client. +* Redirects the client to the error handling endpoint provided in the URL template. The error handling endpoint typically displays error information and returns HTTP 200. + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Snippets/Program.cs" id="snippet_UseStatusCodePagesRedirect" highlight="9"::: + +The URL template can include a `{0}` placeholder for the status code, as shown in the preceding code. If the URL template starts with `~` (tilde), the `~` is replaced by the app's `PathBase`. When specifying an endpoint in the app, create an MVC view or Razor page for the endpoint. + +This method is commonly used when the app: + +* Should redirect the client to a different endpoint, usually in cases where a different app processes the error. For web apps, the client's browser address bar reflects the redirected endpoint. +* Shouldn't preserve and return the original status code with the initial redirect response. + +### UseStatusCodePagesWithReExecute + +The extension method: + +* Generates the response body by re-executing the request pipeline using an alternate path. +* Does not alter the status code before or after re-executing the pipeline. + +The new pipeline execution may alter the response's status code, as the new pipeline has full control of the status code. If the new pipeline does not alter the status code, the original status code will be sent to the client. + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Snippets/Program.cs" id="snippet_UseStatusCodePagesReExecute" highlight="9"::: + +If an endpoint within the app is specified, create an MVC view or Razor page for the endpoint. + +This method is commonly used when the app should: + +* Process the request without redirecting to a different endpoint. For web apps, the client's browser address bar reflects the originally requested endpoint. +* Preserve and return the original status code with the response. + +The URL template must start with `/` and may include a placeholder `{0}` for the status code. To pass the status code as a query-string parameter, pass a second argument into `UseStatusCodePagesWithReExecute`. For example: + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Snippets/Program.cs" id="snippet_UseStatusCodePagesReExecuteQueryString"::: + +The endpoint that processes the error can get the original URL that generated the error, as shown in the following example: + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Pages/StatusCode.cshtml.cs" id="snippet_Class" highlight="12-21"::: + +Since this middleware can re-execute the request pipeline: + +* Middlewares need to handle reentrancy with the same request. This normally means either cleaning up their state after calling `_next` or caching their processing on the `HttpContext` to avoid redoing it. When dealing with the request body, this either means buffering or caching the results like the Form reader. +* Scoped services remain the same. + +## Disable status code pages + +To disable status code pages for an MVC controller or action method, use the [[SkipStatusCodePages]](xref:Microsoft.AspNetCore.Mvc.SkipStatusCodePagesAttribute) attribute. + +To disable status code pages for specific requests in a Razor Pages handler method or in an MVC controller, use : + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Snippets/Pages/Index.cshtml.cs" id="snippet_OnGet"::: + +## Exception-handling code + +Code in exception handling pages can also throw exceptions. Production error pages should be tested thoroughly and take extra care to avoid throwing exceptions of their own. + +### Response headers + +Once the headers for a response are sent: + +* The app can't change the response's status code. +* Any exception pages or handlers can't run. The response must be completed or the connection aborted. + +## Server exception handling + +In addition to the exception handling logic in an app, the [HTTP server implementation](xref:fundamentals/servers/index) can handle some exceptions. If the server catches an exception before response headers are sent, the server sends a `500 - Internal Server Error` response without a response body. If the server catches an exception after response headers are sent, the server closes the connection. Requests that aren't handled by the app are handled by the server. Any exception that occurs when the server is handling the request is handled by the server's exception handling. The app's custom error pages, exception handling middleware, and filters don't affect this behavior. + +## Startup exception handling + +Only the hosting layer can handle exceptions that take place during app startup. The host can be configured to [capture startup errors](xref:fundamentals/host/web-host#capture-startup-errors) and [capture detailed errors](xref:fundamentals/host/web-host#detailed-errors). + +The hosting layer can show an error page for a captured startup error only if the error occurs after host address/port binding. If binding fails: + +* The hosting layer logs a critical exception. +* The dotnet process crashes. +* No error page is displayed when the HTTP server is [Kestrel](xref:fundamentals/servers/kestrel). + +When running on [IIS](/iis) (or Azure App Service) or [IIS Express](/iis/extensions/introduction-to-iis-express/iis-express-overview), a *502.5 - Process Failure* is returned by the [ASP.NET Core Module](xref:host-and-deploy/aspnet-core-module) if the process can't start. For more information, see . + +## Database error page + +The Database developer page exception filter captures database-related exceptions that can be resolved by using Entity Framework Core migrations. When these exceptions occur, an HTML response is generated with details of possible actions to resolve the issue. This page is enabled only in the Development environment. The following code adds the Database developer page exception filter: + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Program.cs" id="snippet_AddDatabaseDeveloperPageExceptionFilter" highlight="3"::: + +## Exception filters + +In MVC apps, exception filters can be configured globally or on a per-controller or per-action basis. In Razor Pages apps, they can be configured globally or per page model. These filters handle any unhandled exceptions that occur during the execution of a controller action or another filter. For more information, see . + +Exception filters are useful for trapping exceptions that occur within MVC actions, but they're not as flexible as the built-in [exception handling middleware](https://github.com/dotnet/aspnetcore/blob/main/src/Middleware/Diagnostics/src/ExceptionHandler/ExceptionHandlerMiddleware.cs), . We recommend using `UseExceptionHandler`, unless you need to perform error handling differently based on which MVC action is chosen. + +## Model state errors + +For information about how to handle model state errors, see [Model binding](xref:mvc/models/model-binding) and [Model validation](xref:mvc/models/validation). + + + +## Problem details + +[!INCLUDE[](~/includes/problem-details-service.md)] + +The following code configures the app to generate a problem details response for all HTTP client and server error responses that ***don't have body content yet***: + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Snippets/Program.cs" id="snippet_AddProblemDetails" highlight="1"::: + +The next section shows how to customize the problem details response body. + + + +### Customize problem details + +The automatic creation of a `ProblemDetails` can be customized using any of the following options: + +1. Use [`ProblemDetailsOptions.CustomizeProblemDetails`](#customizeproblemdetails-operation) +2. Use a custom [`IProblemDetailsWriter`](#custom-iproblemdetailswriter) +3. Call the [`IProblemDetailsService` in a middleware](#problem-details-from-middleware) + +#### `CustomizeProblemDetails` operation + +The generated problem details can be customized using , and the customizations are applied to all auto-generated problem details. + +The following code uses to set : + +:::code language="csharp" source="~/fundamentals/error-handling/samples/7.x/ErrorHandlingSample/Snippets/Program.cs" id="snippet_CustomizeProblemDetails" highlight="1-3"::: + +For example, an [`HTTP Status 400 Bad Request`](https://developer.mozilla.org/docs/Web/HTTP/Status/400) endpoint result produces the following problem details response body: + +```json +{ + "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1", + "title": "Bad Request", + "status": 400, + "nodeId": "my-machine-name" +} +``` + +#### Custom `IProblemDetailsWriter` + +An implementation can be created for advanced customizations. + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/fundamentals/middleware/problem-details-service/SampleProblemDetailsWriter.cs" ::: + +***Note:*** When using a custom `IProblemDetailsWriter`, the custom `IProblemDetailsWriter` must be registered before calling , , , or : + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/fundamentals/middleware/problem-details-service/Program.cs" id="snippet_sampleproblemdetailswriter" ::: + +#### Problem details from Middleware + +An alternative approach to using with is to set the in middleware. A problem details response can be written by calling [`IProblemDetailsService.WriteAsync`](/dotnet/api/microsoft.aspnetcore.http.iproblemdetailsservice.writeasync?view=aspnetcore-7.0&preserve-view=true): + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/fundamentals/middleware/problem-details-service/Program.cs" id="snippet_middleware" highlight="5,19-40"::: + +In the preceding code, the minimal API endpoints `/divide` and `/squareroot` return the expected custom problem response on error input. + +The API controller endpoints return the default problem response on error input, not the custom problem response. The default problem response is returned because the API controller has written to the response stream, [Problem details for error status codes](/aspnet/core/web-api/#problem-details-for-error-status-codes), before [`IProblemDetailsService.WriteAsync`](https://github.com/dotnet/aspnetcore/blob/ce2db7ea0b161fc5eb35710fca6feeafeeac37bc/src/Http/Http.Extensions/src/ProblemDetailsService.cs#L24) is called and the response is **not** written again. + +The following `ValuesController` returns , which writes to the response stream and therefore prevents the custom problem response from being returned. + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/fundamentals/middleware/problem-details-service/Controllers/ValuesController.cs" id="snippet" highlight="9-17,27-35"::: + +The following `Values3Controller` returns [`ControllerBase.Problem`](/dotnet/api/microsoft.aspnetcore.mvc.controllerbase.problem) so the expected custom problem result is returned: + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/fundamentals/middleware/problem-details-service/Controllers/ValuesController.cs" id="snippet3" highlight="16-21"::: + +## Produce a ProblemDetails payload for exceptions + +Consider the following app: + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/fundamentals/middleware/problem-details-service/Program.cs" id="snippet_apishort" highlight="4,8"::: + +In non-development environments, when an exception occurs, the following is a standard [ProblemDetails response](https://datatracker.ietf.org/doc/html/rfc7807) that is returned to the client: + +```json +{ +"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1", +"title":"An error occurred while processing your request.", +"status":500,"traceId":"00-b644-00" +} +``` + +For most apps, the preceding code is all that's needed for exceptions. However, the following section shows how to get more detailed problem responses. + +An alternative to a [custom exception handler page](xref:fundamentals/error-handling#exception-handler-page) is to provide a lambda to . Using a lambda allows access to the error and writing a problem details response with [`IProblemDetailsService.WriteAsync`](/dotnet/api/microsoft.aspnetcore.http.iproblemdetailsservice.writeasync?view=aspnetcore-7.0&preserve-view=true): + +:::code language="csharp" source="~/../AspNetCore.Docs.Samples/fundamentals/middleware/problem-details-service/Program.cs" id="snippet_lambda" ::: + +> [!WARNING] +> Do **not** serve sensitive error information to clients. Serving errors is a security risk. + +An alternative approach to generate problem details is to use the third-party NuGet package [Hellang.Middleware.ProblemDetails](https://www.nuget.org/packages/Hellang.Middleware.ProblemDetails/) that can be used to map exceptions and client errors to problem details. + +## Additional resources + +* [View or download sample code](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/fundamentals/error-handling/samples) ([how to download](xref:fundamentals/index#how-to-download-a-sample)) +* +* +* + +:::moniker-end diff --git a/aspnetcore/fundamentals/openapi/includes/using-openapi-documents-9.md b/aspnetcore/fundamentals/openapi/includes/using-openapi-documents-9.md index cc1d7cf21ae9..577f5a8fb51a 100644 --- a/aspnetcore/fundamentals/openapi/includes/using-openapi-documents-9.md +++ b/aspnetcore/fundamentals/openapi/includes/using-openapi-documents-9.md @@ -31,16 +31,16 @@ To automatically launch the app at the Swagger UI URL using the `https` profile [!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_openapiwithscalar)] -Launch the app and navigate to `https://localhost:/scalar/v1` to view the Scalar UI. +Launch the app and navigate to `https://localhost:/scalar` to view the Scalar UI. To automatically launch the app at the Scalar UI URL using the `https` profile of `Properties/launchSettings.json`: * Confirm that `launchBrowser` is enabled (`true`). -* Set the `launchUrl` to `scalar/v1`. +* Set the `launchUrl` to `scalar`. ```json "launchBrowser": true, -"launchUrl": "scalar/v1", +"launchUrl": "scalar", ``` ## Lint generated OpenAPI documents with Spectral diff --git a/aspnetcore/fundamentals/openapi/openapi-comments.md b/aspnetcore/fundamentals/openapi/openapi-comments.md index f7692621b3e3..7ee21722e654 100644 --- a/aspnetcore/fundamentals/openapi/openapi-comments.md +++ b/aspnetcore/fundamentals/openapi/openapi-comments.md @@ -1,14 +1,14 @@ --- title: ASP.NET Core OpenAPI XML documentation comment support in ASP.NET Core +ai-usage: ai-assisted 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.author: safia ms.custom: mvc -ms.date: 04/15/2025 +ms.date: 08/25/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. @@ -106,6 +106,21 @@ To include XML documentation files from referenced assemblies, add them as `Addi ``` +XML doc comment processing can be configured to access XML comments in other assemblies. This is useful for generating documentation for types that are defined outside the current assembly, such as the `ProblemDetails` type in the `Microsoft.AspNetCore.Http` namespace. This configuration is done with directives in the project build file. The following example shows how to configure the XML comment generator to access XML comments for types in the `Microsoft.AspNetCore.Http` assembly, which includes the `ProblemDetails` class: + +```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. @@ -130,6 +145,14 @@ XML comments are parsed into structured `XmlComment` objects with: * Response documentation with status codes and descriptions. * Support for examples and deprecated markers. +### Handling of complex types + +XML comment processing produces accurate and complete OpenApi descriptions for a wide range of types and supports complex scenarios. But if an error is encountered when processing a complex types, the process bypasses the type gracefully. + +In this way, scenarios that might have resulted in build errors now simply result in missing metadata, helping to avoid build failures. + +XML documentation comments from referenced assemblies are correctly merged even when their documentation IDs include return type suffixes. As a result, all valid XML comments are reliably included in generated OpenAPI documentation, improving documentation accuracy and completeness for APIs using referenced assemblies. + ### `` 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: diff --git a/aspnetcore/fundamentals/openapi/using-openapi-documents.md b/aspnetcore/fundamentals/openapi/using-openapi-documents.md index 3a60fa9a9d7e..b07ab2643cba 100644 --- a/aspnetcore/fundamentals/openapi/using-openapi-documents.md +++ b/aspnetcore/fundamentals/openapi/using-openapi-documents.md @@ -43,16 +43,16 @@ To automatically launch the app at the Swagger UI URL using the `https` profile [!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_openapiwithscalar)] -Launch the app and navigate to `https://localhost:/scalar/v1` to view the Scalar UI. +Launch the app and navigate to `https://localhost:/scalar` to view the Scalar UI. To automatically launch the app at the Scalar UI URL using the `https` profile of `Properties/launchSettings.json`: * Confirm that `launchBrowser` is enabled (`true`). -* Set the `launchUrl` to `scalar/v1`. +* Set the `launchUrl` to `scalar`. ```json "launchBrowser": true, -"launchUrl": "scalar/v1", +"launchUrl": "scalar", ``` ## Lint generated OpenAPI documents with Spectral diff --git a/aspnetcore/migration/fx-to-core/inc/blazor.md b/aspnetcore/migration/fx-to-core/inc/blazor.md index b506652dbf63..ef15e7314f57 100644 --- a/aspnetcore/migration/fx-to-core/inc/blazor.md +++ b/aspnetcore/migration/fx-to-core/inc/blazor.md @@ -5,12 +5,12 @@ description: Learn how to enable ASP.NET Core Blazor Server support with Yarp in monikerRange: '>= aspnetcore-6.0 < aspnetcore-8.0' ms.author: tasou ms.custom: "mvc" -ms.date: 07/17/2025 +ms.date: 09/04/2025 uid: migration/fx-to-core/inc/blazor --- # Enable ASP.NET Core Blazor Server support with Yarp in incremental migration -When adding Yarp to a Blazor Server app, both attempt to act as fallback routes for the app's request routing. Either Blazor or Yarp handles routing arbitrarily, which means that scenarios such as deep linking in Blazor may fail. This will be fixed in the .NET 8 release later this year. For migration to ASP.NET Core in .NET 6 and .NET 7, map Blazor's endpoints to achieve correct request routing by following the guidance in this article. +When adding Yarp to a Blazor Server app, both attempt to act as fallback routes for the app's request routing. Either Blazor or Yarp handles routing arbitrarily, which means that scenarios such as deep linking in Blazor may fail. This is [fixed in .NET 8](xref:migration/70-to-80#drop-blazor-server-with-yarp-routing-workaround). For migration to ASP.NET Core in .NET 6 and .NET 7, map Blazor's endpoints to achieve correct request routing by following the guidance in this article. Add the following route builder extensions class to the project. diff --git a/aspnetcore/performance/caching/hybrid.md b/aspnetcore/performance/caching/hybrid.md index 8b2900610650..3bd3313fc1a5 100644 --- a/aspnetcore/performance/caching/hybrid.md +++ b/aspnetcore/performance/caching/hybrid.md @@ -210,7 +210,7 @@ Because much `HybridCache` usage will be adapted from existing `IDistributedCach * They're immutable types. * The code doesn't modify them. -In such cases, inform `HybridCache` that it's safe to reuse instances by making at least one of the following changes: +In such cases, inform `HybridCache` that it's safe to reuse instances by making both of the following changes: * Marking the type as `sealed`. The `sealed` keyword in C# means that the class can't be inherited. * Applying the `[ImmutableObject(true)]` attribute to the type. The `[ImmutableObject(true)]` attribute indicates that the object's state can't be changed after it's created. diff --git a/aspnetcore/razor-pages/index.md b/aspnetcore/razor-pages/index.md index e449954a0f0f..8f12068b9124 100644 --- a/aspnetcore/razor-pages/index.md +++ b/aspnetcore/razor-pages/index.md @@ -1,14 +1,14 @@ --- -title: Introduction to Razor Pages in ASP.NET Core +title: Razor Pages architecture and concepts in ASP.NET Core author: tdykstra -description: Explains how Razor Pages in ASP.NET Core makes coding page-focused scenarios easier and more productive than using MVC. +description: Learn the architecture, concepts, and patterns of Razor Pages in ASP.NET Core for building page-focused web applications. monikerRange: '>= aspnetcore-3.1' ms.author: tdykstra -ms.date: 8/28/2023 +ms.date: 08/27/2025 uid: razor-pages/index --- -# Introduction to Razor Pages in ASP.NET Core +# Razor Pages architecture and concepts in ASP.NET Core By [Rick Anderson](https://twitter.com/RickAndMSFT), [Dave Brock](https://twitter.com/daveabrock), and [Kirk Larkin](https://twitter.com/serpent5) @@ -19,7 +19,7 @@ Razor Pages can make coding page-focused scenarios easier and more productive th If you're looking for a tutorial that uses the Model-View-Controller approach, see [Get started with ASP.NET Core MVC](xref:tutorials/first-mvc-app/start-mvc). -This document provides an introduction to Razor Pages. It's not a step by step tutorial. If you find some of the sections too advanced, see [Get started with Razor Pages](xref:tutorials/razor-pages/razor-pages-start). For an overview of ASP.NET Core, see the [Introduction to ASP.NET Core](xref:index). +This article covers the architecture, concepts, and patterns that make Razor Pages effective for building page-focused web applications. It explains how Razor Pages work, their key components, and best practices for implementation. If you prefer hands-on learning with step-by-step instructions, see [Tutorial: Create a Razor Pages web app with ASP.NET Core](xref:tutorials/razor-pages/index). For an overview of ASP.NET Core, see the [Introduction to ASP.NET Core](xref:index). ## Prerequisites diff --git a/aspnetcore/release-notes/aspnetcore-9/includes/hybrid-cache.md b/aspnetcore/release-notes/aspnetcore-9/includes/hybrid-cache.md index 6a288d263745..23023b4f5050 100644 --- a/aspnetcore/release-notes/aspnetcore-9/includes/hybrid-cache.md +++ b/aspnetcore/release-notes/aspnetcore-9/includes/hybrid-cache.md @@ -114,7 +114,7 @@ Because a lot of `HybridCache` usage will be adapted from existing `IDistributed * If the types being cached are immutable. * If the code doesn't modify them. -In such cases, inform `HybridCache` that it's safe to reuse instances by: +In such cases, inform `HybridCache` that it's safe to reuse instances by making both of the following changes: * Marking the type as `sealed`. The `sealed` keyword in C# means that the class can't be inherited. * Applying the `[ImmutableObject(true)]` attribute to it. The `[ImmutableObject(true)]` attribute indicates that the object's state can't be changed after it's created. diff --git a/aspnetcore/security/data-protection/implementation/key-storage-providers.md b/aspnetcore/security/data-protection/implementation/key-storage-providers.md index 1b81c5535747..1bbce5c8a8e1 100644 --- a/aspnetcore/security/data-protection/implementation/key-storage-providers.md +++ b/aspnetcore/security/data-protection/implementation/key-storage-providers.md @@ -50,7 +50,7 @@ Configure Azure Blob Storage to maintain data protection keys: * We recommend using Azure Managed Identity and role-based access control (RBAC) to access the key storage blob. ***You don't need to create a key file and upload it to the container of the storage account.*** The framework creates the file for you. To inspect the contents of a key file, use the context menu's **View/edit** command at the end of a key row in the portal. -> ![NOTE] +> [!NOTE] > If you plan to use a blob URI with a shared access signature (SAS) instead of a Managed Identity, use a text editor to create an XML key file on your local machine: > > ```xml diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 38098e309a9b..e0cdf8f5a8c4 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -326,7 +326,7 @@ items: uid: tutorials/choose-web-ui - name: Razor Pages items: - - name: Introduction + - name: Architecture and concepts uid: razor-pages/index - name: Tutorial items: