Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .openpublishing.redirection.json
Original file line number Diff line number Diff line change
Expand Up @@ -1683,6 +1683,11 @@
"source_path": "aspnetcore/security/authorization/razor-pages-authorization.md",
"redirect_url": "/aspnet/core/razor-pages/security/authorization/conventions",
"redirect_document_id": false
},
{
"source_path": "aspnetcore/security/authorization/resourcebased.md",
"redirect_url": "/aspnet/core/security/authorization/resource-based",
"redirect_document_id": false
}
]
}
9 changes: 6 additions & 3 deletions aspnetcore/blazor/blazor-with-dotnet-on-web-workers.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ uid: blazor/blazor-web-workers

-->

Modern Blazor WebAssembly apps often handle CPU-intensive work alongside rich UI updates. Tasks such as image processing, document parsing, or data crunching can easily freeze the browser's main thread. Web Workers let you push that work to a background thread. Combined with the .NET WebAssembly runtime, you can keep writing C# while the UI stays responsive.
Modern Blazor WebAssembly apps often handle CPU-intensive work alongside rich UI updates. Tasks such as image processing, document parsing, or data crunching can easily freeze the browser's main thread. Web Workers let you push that work to a background thread. Combined with the .NET WebAssembly runtime, you can execute C# code in the background while the UI stays responsive.

:::moniker range=">= aspnetcore-11.0"

The Blazor Web Worker project template (`dotnet new blazorwebworker`) provides built-in scaffolding for running .NET code in a Web Worker in a Blazor WebAssembly app. The template generates the required JavaScript worker scripts, a C# `WebWorkerClient` class, and a starter `WorkerMethods.cs` file, which removes the need to write the interop layer manually. To learn about Web Workers with React, see <xref:client-side/dotnet-on-webworkers>.
The Blazor Web Worker project template (`blazorwebworker`) contains a Web Worker client for Blazor WebAssembly apps. The template generates the required JavaScript worker scripts, a C# `WebWorkerClient` class, and a starter `WorkerMethods.cs` file, which removes the need to write the interop layer manually. To learn about Web Workers with React or other custom JavaScript frontends, see <xref:client-side/dotnet-on-webworkers>.

> [!NOTE]
> In .NET 11 and later, the Blazor Web Worker template (`blazorwebworker`) is intended for Blazor WebAssembly scenarios. For React or other custom JavaScript frontends, use the manual approach in <xref:client-side/dotnet-on-webworkers>.
> Use of a Web Worker is primarily useful with Blazor WebAssembly apps to improve performance but can be implemented for the client-side project (`.Client`) of a Blazor Web App. Typically, a Blazor Web App performs demanding work server-side, where the server can handle the work faster than the client and the app avoids the small delay setting up a Web Worker. However, use of a Web Worker via the Blazor Web Worker template client-side in a Blazor Web App is supported.

## Create the projects

Expand Down Expand Up @@ -224,6 +224,9 @@ public sealed class WebWorkerClient : IAsyncDisposable

The guidance in this article mirrors the concepts from the React-focused *.NET on Web Workers* walkthrough, but adapts every step to a Blazor frontend. It highlights the same QR-code generation scenario implemented in this repository. To learn about Web Workers with React, see <xref:client-side/dotnet-on-webworkers>.

> [!NOTE]
> Use of a Web Worker is primarily useful with Blazor WebAssembly apps to improve performance but can be implemented for the client-side project (`.Client`) of a Blazor Web App. Typically, a Blazor Web App performs demanding work server-side, where the server can handle the work faster than the client and the app avoids the small delay setting up a Web Worker. However, use of a Web Worker client-side in a Blazor Web App is supported.

## Sample app

Explore a complete working implementation in the [Blazor samples GitHub repository](https://github.com/dotnet/blazor-samples). The sample is available for .NET 10 or later and named `DotNetOnWebWorkersBlazorWebAssembly`.
Expand Down
4 changes: 2 additions & 2 deletions aspnetcore/blazor/tooling.md
Original file line number Diff line number Diff line change
Expand Up @@ -624,11 +624,11 @@ For more information on template options, see the following resources:

## Service defaults library for Blazor WebAssembly apps

The `blazor-wasm-servicedefaults` project template creates a service defaults library for Blazor WebAssembly apps with .NET Aspire integration.
The `blazor-wasm-servicedefaults` project template creates a service defaults library for Blazor WebAssembly apps with [Aspire](/dotnet/aspire/get-started/aspire-overview) integration.

The template features:

* [OpenTelemetry](https://github.com/open-telemetry/opentelemetry-dotnet) support: Logging, metrics, and tracing with standard OTLP exporter.
* [OpenTelemetry (OTEL)](https://opentelemetry.io/) ([OpenTelemetry .NET](https://github.com/open-telemetry/opentelemetry-dotnet)) support: Logging, metrics, and tracing with standard OTEL Protocol (OTLP) exporter.
* Service discovery integration via the [`Microsoft.Extensions.ServiceDiscovery` NuGet package](https://www.nuget.org/packages/Microsoft.Extensions.ServiceDiscovery).
* HTTP resilience using the standard resilience handler via the [`Microsoft.Extensions.Http.Resilience` NuGet package](https://www.nuget.org/packages/Microsoft.Extensions.Http.Resilience).

Expand Down
9 changes: 4 additions & 5 deletions aspnetcore/fundamentals/servers/yarp/distributed-tracing.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@ title: YARP Distributed tracing
description: YARP Distributed tracing
author: tdykstra
ms.author: tdykstra
ms.date: 04/24/2025
ms.date: 05/15/2026
ms.topic: concept-article
content_well_notification: AI-contribution
ai-usage: ai-assisted
---

# YARP Distributed tracing

As an ASP.NET Core component, YARP can easily integrate into different tracing systems the same as any other ASP.NET Core application.

.NET has built-in configurable support for distributed tracing that YARP takes advantage of to enable such scenarios out-of-the-box.

## Using Open Telemetry
## Using OpenTelemetry (OTEL)

YARP supports distributed tracing using Open Telemetry (OTEL). When a request comes in, and there is a listener for Activities, then ASP.NET Core will propagate the [Trace Context](https://www.w3.org/TR/trace-context) trace-id, or create one if necessary, and create new spans/activities for the work performed.
YARP supports distributed tracing using [OpenTelemetry (OTEL)](https://opentelemetry.io/). When a request comes in, and there is a listener for Activities, then ASP.NET Core will propagate the [Trace Context](https://www.w3.org/TR/trace-context) trace-id, or create one if necessary, and create new spans/activities for the work performed.
In addition YARP can create activities for:

* Forwarding Requests
Expand All @@ -28,7 +27,7 @@ These will only be created if there is a listener for the [`ActivitySource`](/do

### Example: Application Insights

For example, to monitor the traces with Application Insights, the proxy application needs to use the [Open Telemetry](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry) and [Azure Monitor](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore) SDKs.
For example, to monitor the traces with Application Insights, the proxy application needs to use the [OpenTelemetry .NET](https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry) and [Azure Monitor](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore) SDKs.

`application.csproj`:

Expand Down
8 changes: 4 additions & 4 deletions aspnetcore/migration/80-to-90.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: Migrate from ASP.NET Core in .NET 8 to ASP.NET Core in .NET 9
author: wadepickett
description: Learn how to migrate an ASP.NET Core in .NET 8 to ASP.NET Core in .NET 9.
ms.author: wpickett
ms.date: 2/11/2024
ms.date: 05/06/2026
uid: migration/80-to-90
---
# Migrate from ASP.NET Core in .NET 8 to ASP.NET Core in .NET 9
Expand Down Expand Up @@ -78,7 +78,7 @@ Optimize the handling of static files in your web apps by replacing <xref:Micros
+ app.MapStaticAssets();
```

In MVC & Razor Pages apps you additionally need to chain a call to `.WithStaticAssets` after `MapRazorPages` or `MapControllerRoute` in `Program.cs`. For an example, see the <xref:fundamentals/static-files?view=aspnetcore-9.0&preserve-view=true>.
In MVC & Razor Pages apps, you additionally need to chain a call to `.WithStaticAssets` after `MapRazorPages` or `MapControllerRoute` in `Program.cs`. For an example, see the <xref:fundamentals/static-files?view=aspnetcore-9.0&preserve-view=true>.

ASP.NET Core automatically fingerprints and precompresses your static files at build and publish time, and then <xref:Microsoft.AspNetCore.Builder.StaticAssetsEndpointRouteBuilderExtensions.MapStaticAssets%2A> surfaces the optimized files as endpoints using endpoint routing with appropriate caching headers.

Expand All @@ -94,7 +94,7 @@ To resolve the fingerprinted file names from your app:

* In MVC & Razor Pages apps, the script and link tag helpers will automatically resolve the fingerprinted file names.

To resolve the fingerprinted file names when importing JavaScript modules, add a generated [import map](https://developer.mozilla.org/docs/Web/HTML/Element/script/type/importmap):
To resolve the fingerprinted file names when importing JavaScript modules, add a generated [import map](https://developer.mozilla.org/docs/Web/HTML/Reference/Elements/script/type/importmap):

* In Blazor apps, add the (<xref:Microsoft.AspNetCore.Components.ImportMap>) component to the `<head>` content of the app's root component, typically in the `App` component (`App.razor`):

Expand All @@ -103,7 +103,7 @@ To resolve the fingerprinted file names when importing JavaScript modules, add a
```

* In MVC & Razor pages apps, add `<script type="importmap"></script>` to the head of the main layout file, which is updated by the Import Map Tag Helper.

For more information, see the following resources:

* <xref:aspnetcore-9#static-asset-delivery-optimization>
Expand Down
162 changes: 162 additions & 0 deletions aspnetcore/mvc/security/authorization/resource-based.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
---
title: Resource-based authorization in ASP.NET Core MVC
ai-usage: ai-assisted
author: wadepickett
description: Learn how to implement resource-based authorization in an ASP.NET Core MVC app when an [Authorize] attribute doesn't suffice.
ms.author: wpickett
ms.custom: mvc
ms.date: 05/20/2026
uid: mvc/security/authorization/resource-based
---
# Resource-based authorization in ASP.NET Core MVC

This article describes how to authorize users for access to app resources.

In an app, a *resource* is typically represented by a C# class that includes data stored in a collection, such as a [`byte[]` array](xref:System.Byte). The class usually contains additional metadata pertaining to the resource, such as a unique resource identifier, dates, authors, source information, and a friendly name for display in a UI. The collection that holds resource data is usually loaded from physical file content, a cloud storage object, an in-memory object, or data from a database.

Resource-based authorization requires special attention in ASP.NET Core apps. Attribute evaluation occurs before data binding and before execution of an action that loads a resource. Declarative authorization with an `[Authorize]` attribute doesn't suffice for resource-based authorization. Instead, the app must invoke a custom authorization method&mdash;an approach known as *imperative authorization*.

[View or download sample code](https://github.com/dotnet/AspNetCore.Docs.Samples/tree/main/security/authorization/resource-based) ([how to download](xref:fundamentals/index#how-to-download-a-sample)).

<xref:security/authorization/secure-data> contains a sample app that uses resource-based authorization.

Examples in this article use *primary constructors*, available in C# 12 (.NET 8) or later. For more information, see [Declare primary constructors for classes and structs (C# documentation tutorial)](/dotnet/csharp/whats-new/tutorials/primary-constructors) and [Primary constructors (C# Guide)](/dotnet/csharp/programming-guide/classes-and-structs/instance-constructors#primary-constructors). Sample apps that accompany the article that target versions of .NET earlier than .NET 8 use constructor injection.

## Use imperative authorization

Authorization is implemented as an <xref:Microsoft.AspNetCore.Authorization.IAuthorizationService>, which is registered in the service collection at app startup *by the ASP.NET Core framework*. The service is made available to classes and actions via [dependency injection](xref:fundamentals/dependency-injection). The following controller also injects a document repository, which the developer creates and registers in the service container to manage document operations:

```csharp
public class DocumentController(IAuthorizationService authorizationService,
IDocumentRepository documentRepository) : Controller
{
private readonly IAuthorizationService _authorizationService;
private readonly IDocumentRepository _documentRepository;

public DocumentController(IAuthorizationService authorizationService,
IDocumentRepository documentRepository)
{
_authorizationService = authorizationService;
_documentRepository = documentRepository;
}

...
}
```

<xref:Microsoft.AspNetCore.Authorization.IAuthorizationService> has two <xref:Microsoft.AspNetCore.Authorization.IAuthorizationService.AuthorizeAsync%2A> method overloads. One of the overloads accepts a resource and policy name:

```csharp
Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user,
object resource,
string policyName);
```

The other overload accepts a resource and collection of requirements (<xref:Microsoft.AspNetCore.Authorization.IAuthorizationRequirement>) to evaluate:

```csharp
Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user,
object resource,
IEnumerable<IAuthorizationRequirement> requirements);
```

In the following example, the secured resource is loaded into a custom `Document` object. An <xref:Microsoft.AspNetCore.Authorization.IAuthorizationService.AuthorizeAsync%2A> overload is invoked to determine whether the current user is allowed to edit the document via a custom "`EditPolicy`" authorization policy. If [`authorizationResult.Succeeded`](xref:Microsoft.AspNetCore.Authorization.AuthorizationResult.Succeeded%2A) is `true`, the user is authorized for the document because they authored the document (`Document.Author` matches the user's <xref:System.Security.Principal.IIdentity.Name%2A>).

> [!NOTE]
> The following example assumes successful authentication with the `User` property set.

```csharp
[HttpGet]
public async Task<IActionResult> Edit(Guid documentId)
{
Document document = _documentRepository.Find(documentId);

...

var authorizationResult = await _authorizationService
.AuthorizeAsync(User, document, "EditPolicy");

...
}
```

## Create a resource-based handler

Creating a resource-based authorization handler is similar to [creating a plain requirements handler](xref:security/authorization/policies#security-authorization-policies-based-authorization-handler). Create a custom requirement class and implement a requirement handler class. For more information on creating a requirement class, see the [Policy-based authorization: Requirements](xref:security/authorization/policies#requirements).

The handler class specifies the requirement and resource type. The following example demonstrates a handler utilizing a `SameAuthorRequirement` requirement and a `Document` resource:

:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/resource-based/3.0/ResourceBasedAuthApp2/Services/DocumentAuthorizationHandler.cs" id="snippet_HandlerAndRequirement":::

In the preceding example, imagine that `SameAuthorRequirement` is a special case of a more generic `SpecificAuthorRequirement` class. The `SpecificAuthorRequirement` class (not shown) contains a `Name` property representing the name of the author. The `Name` property could be set to the current user.

:::moniker range=">= aspnetcore-6.0"

Register the requirement and handler in `Program.cs`:

```csharp
builder.Services.AddAuthorizationBuilder()
.AddPolicy("EditPolicy", policy =>
policy.Requirements.Add(new SameAuthorRequirement()));

builder.Services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
```

:::moniker-end

:::moniker range="< aspnetcore-6.0"

Register the requirement and handler in `Startup.ConfigureServices`:

```csharp
services.AddAuthorization(options =>
{
options.AddPolicy("EditPolicy", policy =>
policy.Requirements.Add(new SameAuthorRequirement()));
});

services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
```

:::moniker-end

For more information on creating authorization policies, see <xref:security/authorization/policies>.

### Operational requirements

To make decisions based on the outcomes of CRUD (Create, Read, Update, Delete) operations, use the <xref:Microsoft.AspNetCore.Authorization.Infrastructure.OperationAuthorizationRequirement> helper class. This class enables you to write a single handler instead of an individual class for each operation type. To use it, provide some operation names:

:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/resource-based/3.0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs" id="snippet_OperationsClass":::

The handler is implemented as follows, using an <xref:Microsoft.AspNetCore.Authorization.Infrastructure.OperationAuthorizationRequirement> requirement and a `Document` resource:

:::code language="csharp" source="~/../AspNetCore.Docs.Samples/security/authorization/resource-based/3.0/ResourceBasedAuthApp2/Services/DocumentAuthorizationCrudHandler.cs" id="snippet_Handler":::

The preceding handler validates the operation using the resource, the user's identity, and the requirement's `Name` property.

## Challenge and forbid with an operational resource handler

This section shows how the challenge and forbid action results are processed and how challenge and forbid differ.

When authorization fails but the user is authenticated, the app can return a <xref:Microsoft.AspNetCore.Mvc.ForbidResult>, which informs authentication middleware that authorization failed. Return a <xref:Microsoft.AspNetCore.Mvc.ChallengeResult> for unauthenticated users. For interactive browser clients, it may be appropriate to redirect the user to a login page.

> [!NOTE]
> The following example assumes successful authentication with the `User` property set.

```csharp
if ((await _authorizationService
.AuthorizeAsync(User, document, Operations.Read)).Succeeded)
{
return View(document);
}
else if (User.Identity?.IsAuthenticated ?? false)
{
return new ForbidResult();
}
else
{
return new ChallengeResult();
}
```
Loading
Loading