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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions aspnetcore/blazor/components/event-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ For event handling:
:::moniker range=">= aspnetcore-8.0"

* Delegate event handlers in Blazor Web Apps are only called in components that adopt an interactive render mode. The examples throughout this article assume that the app adopts an interactive render mode globally in the app's root component, typically the `App` component. For more information, see <xref:blazor/components/render-modes#apply-a-render-mode-to-the-entire-app>.
* Asynchronous delegate event handlers that return a <xref:System.Threading.Tasks.Task> are supported.
* Asynchronous delegate event handlers that return a <xref:System.Threading.Tasks.Task> (`async Task`) are supported by Blazor and adopted by Blazor Web App and Blazor WebAssembly documentation examples.
* Delegate event handlers automatically trigger a UI render, so there's no need to manually call [`StateHasChanged`](xref:blazor/components/lifecycle#state-changes-statehaschanged).
* Exceptions are logged.

:::moniker-end

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

* Asynchronous delegate event handlers that return a <xref:System.Threading.Tasks.Task> are supported.
* Asynchronous delegate event handlers that return a <xref:System.Threading.Tasks.Task> (`async Task`) are supported by Blazor and adopted by Blazor Server and Blazor WebAssembly documentation examples.
* Delegate event handlers automatically trigger a UI render, so there's no need to manually call [`StateHasChanged`](xref:blazor/components/lifecycle#state-changes-statehaschanged).
* Exceptions are logged.

Expand Down
2 changes: 1 addition & 1 deletion aspnetcore/blazor/includes/js-interop/js-collocation.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ The following `JsCollocation2` component's `OnAfterRenderAsync` method loads a J
}
}

public async void ShowPrompt()
public async Task ShowPrompt()
{
if (module is not null)
{
Expand Down
2 changes: 1 addition & 1 deletion aspnetcore/blazor/security/blazor-web-app-with-oidc.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ Inspect the sample app for the following features:

* Automatic non-interactive token refresh with the help of a custom cookie refresher (`CookieOidcRefresher.cs`).
* The server project calls <xref:Microsoft.Extensions.DependencyInjection.WebAssemblyRazorComponentsBuilderExtensions.AddAuthenticationStateSerialization%2A> to add a server-side authentication state provider that uses <xref:Microsoft.AspNetCore.Components.PersistentComponentState> to flow the authentication state to the client. The client calls <xref:Microsoft.Extensions.DependencyInjection.WebAssemblyAuthenticationServiceCollectionExtensions.AddAuthenticationStateDeserialization%2A> to deserialize and use the authentication state passed by the server. The authentication state is fixed for the lifetime of the WebAssembly application.
* An example requests to the Blazor Web App for weather data is handled by a Minimal API endpoint (`/weather-forecast`) in the `Program` file (`Program.cs`). The endpoint requires authorization by calling <xref:Microsoft.AspNetCore.Builder.AuthorizationEndpointConventionBuilderExtensions.RequireAuthorization%2A>. For any controllers that you add to the project, add the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) to the controller or action.
* An example requests to the Blazor Web App for weather data is handled by a Minimal API endpoint (`/weather-forecast`) in the `Program` file (`Program.cs`). The endpoint requires authorization by calling <xref:Microsoft.AspNetCore.Builder.AuthorizationEndpointConventionBuilderExtensions.RequireAuthorization%2A>. For any controllers that you add to the project, add the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) to the controller or action. For more information on requiring authorization across the app via an [authorization policy](xref:security/authorization/policies) and opting out of authorization at a subset of public endpoints, see the [Razor Pages OIDC guidance](xref:security/authentication/configure-oidc-web-authentication#force-authorization).
* The app securely calls a (web) API in the server project for weather data:
* When rendering the `Weather` component on the server, the component uses the `ServerWeatherForecaster` on the server to obtain weather data directly (not via a web API call).
* When the component is rendered on the client, the component uses the `ClientWeatherForecaster` service implementation, which uses a preconfigured <xref:System.Net.Http.HttpClient> (in the client project's `Program` file) to make a web API call to the server project. A Minimal API endpoint (`/weather-forecast`) defined in the server project's `Program` file obtains the weather data from the `ServerWeatherForecaster` and returns the data to the client.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ There's no limit on the number of connections per user for an app. If the app re
* Require authentication to connect to the app and keep track of the active sessions per user.
* Reject new sessions upon reaching a limit.
* Proxy WebSocket connections to an app through the use of a proxy, such as the [Azure SignalR Service](/azure/azure-signalr/signalr-overview) that multiplexes connections from clients to an app. This provides an app with greater connection capacity than a single client can establish, preventing a client from exhausting the connections to the server.
* Server level
* Use a proxy/gateway in front of the app. For example, [Azure Application Gateway](/azure/application-gateway/overview) is a web traffic (OSI layer 7) load balancer that enables you to manage traffic to your web applications. For more information, see [Overview of WebSocket support in Application Gateway](/azure/application-gateway/application-gateway-websocket).
* Although Long Polling is supported for Blazor apps, which would permit the adoption of [Azure Front Door](/azure/frontdoor/front-door-overview), [WebSockets is the recommended transport protocol](xref:blazor/host-and-deploy/server#azure-signalr-service). As of September, 2024, [Azure Front Door](/azure/frontdoor/front-door-overview) doesn't support WebSockets, but support for WebSockets is under consideration. For more information, see [Support WebSocket connections on Azure Front Door](https://feedback.azure.com/d365community/idea/c8b1d257-8a26-ec11-b6e6-000d3a4f0789).
* Server level: Use a proxy/gateway in front of the app.
* [Azure Application Gateway](/azure/application-gateway/overview) is a web traffic (OSI layer 7) load balancer that enables you to manage traffic to your web applications. For more information, see [Overview of WebSocket support in Application Gateway](/azure/application-gateway/application-gateway-websocket).
* [Azure Front Door](/azure/frontdoor/front-door-overview) is a load-balancing service for distributing your workloads across multiple computing resources.

:::moniker-end

Expand Down
143 changes: 71 additions & 72 deletions aspnetcore/blazor/webassembly-native-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,64 +36,62 @@ Prebuilt dependencies typically must be built using the same version of Emscript

## Use native code

Add a simple native C function to a Blazor WebAssembly app:
This section demonstrates how to add a simple native C function to a Blazor WebAssembly app.

1. Create a new Blazor WebAssembly project.
1. Add a `Test.c` file to the project.
1. Add a C function for computing factorials.
Create a new Blazor WebAssembly project.

`Test.c`:
Add a `Test.c` file to the project with a C function for computing factorials.

```c
int fact(int n)
{
if (n == 0) return 1;
return n * fact(n - 1);
}
```
`Test.c`:

1. Add a `NativeFileReference` for `Test.c` in the app's project file:
```c
int fact(int n)
{
if (n == 0) return 1;
return n * fact(n - 1);
}
```

```xml
<ItemGroup>
<NativeFileReference Include="Test.c" />
</ItemGroup>
```
Add a `NativeFileReference` MS Build item for `Test.c` in the app's project file (`.csproj`):

1. In a Razor component, add a <xref:System.Runtime.InteropServices.DllImportAttribute> for the `fact` function in the generated `Test` library and call the `fact` method from .NET code in the component.
```xml
<ItemGroup>
<NativeFileReference Include="Test.c" />
</ItemGroup>
```

`Pages/NativeCTest.razor`:
In a Razor component, add a [`[DllImport]` attribute](xref:System.Runtime.InteropServices.DllImportAttribute) for the `fact` function in the generated `Test` library and call the `fact` method from .NET code in the component.

```razor
@page "/native-c-test"
@using System.Runtime.InteropServices
`Pages/NativeCTest.razor`:

<PageTitle>Native C</PageTitle>
```razor
@page "/native-c-test"
@using System.Runtime.InteropServices

<h1>Native C Test</h1>
<PageTitle>Native C</PageTitle>

<p>
@@fact(3) result: @fact(3)
</p>
<h1>Native C Test</h1>

@code {
[DllImport("Test")]
static extern int fact(int n);
}
```
<p>
@@fact(3) result: @fact(3)
</p>

@code {
[DllImport("Test")]
static extern int fact(int n);
}
```

When you build the app with the .NET WebAssembly build tools installed, the native C code is compiled and linked into the .NET WebAssembly runtime (`dotnet.wasm`). After the app is built, run the app to see the rendered factorial value.

## C++ managed method callbacks

Label managed methods that are passed to C++ with the `[UnmanagedCallersOnly]` attribute.

The method marked with the `[UnmanagedCallersOnly]` attribute must be `static`. To call an instance method in a Razor component, pass a `GCHandle` for the instance to C++ and then pass it back to native. Alternatively, use some other method to identify the instance of the component.
Label managed methods that are passed to C++ with the [`[UnmanagedCallersOnly]` attribute](xref:System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute). The method marked with the attribute must be `static`. To call an instance method in a Razor component, pass a <xref:System.Runtime.InteropServices.GCHandle> for the instance to C++ and then pass it back to native. Alternatively, use some other method to identify the instance of the component.

The method marked with `[DllImport]` must use a C# 9.0 function pointer rather than a delegate type for the callback argument.
The method marked with the [`[DllImport]` attribute](xref:System.Runtime.InteropServices.DllImportAttribute) must use a [function pointer (C# 9.0 or later)](/dotnet/csharp/language-reference/proposals/csharp-9.0/function-pointers) rather than a delegate type for the callback argument.

> [!NOTE]
> For C# function pointer types in `[DllImport]` methods, use `IntPtr` in the method signature on the managed side instead of `delegate *unmanaged<int, void>`. For more information, see [[WASM] callback from native code to .NET: Parsing function pointer types in signatures is not supported (dotnet/runtime #56145)](https://github.com/dotnet/runtime/issues/56145).
> For C# function pointer types in [`[DllImport]`](xref:System.Runtime.InteropServices.DllImportAttribute) methods, use <xref:System.IntPtr> in the method signature on the managed side instead of `delegate *unmanaged<int, void>`. For more information, see [[WASM] callback from native code to .NET: Parsing function pointer types in signatures is not supported (`dotnet/runtime` #56145)](https://github.com/dotnet/runtime/issues/56145).

## Package native dependencies in a NuGet package

Expand All @@ -103,55 +101,56 @@ NuGet packages can contain native dependencies for use on WebAssembly. These lib

[SkiaSharp](https://github.com/mono/SkiaSharp) is a cross-platform 2D graphics library for .NET based on the native [Skia graphics library](https://skia.org/) with support for Blazor WebAssembly.

To use SkiaSharp in a Blazor WebAssembly app:
The section demonstrates how to implement SkiaSharp in a Blazor WebAssembly app.

1. Add a package reference to the [`SkiaSharp.Views.Blazor`](https://www.nuget.org/packages/SkiaSharp.Views.Blazor) package in a Blazor WebAssembly project. Use Visual Studio's process for adding packages to an app (**Manage NuGet Packages** with **Include prerelease** selected) or execute the [`dotnet add package`](/dotnet/core/tools/dotnet-add-package) command in a command shell:
Add a package reference to the [`SkiaSharp.Views.Blazor`](https://www.nuget.org/packages/SkiaSharp.Views.Blazor) package in a Blazor WebAssembly project. Use Visual Studio's process for adding packages to an app (**Manage NuGet Packages** with **Include prerelease** selected) or execute the [`dotnet add package`](/dotnet/core/tools/dotnet-add-package) command in a command shell with the `--prerelease` option:

```dotnetcli
dotnet add package –-prerelease SkiaSharp.Views.Blazor
```
```dotnetcli
dotnet add package –-prerelease SkiaSharp.Views.Blazor
```

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

1. Add a `SKCanvasView` component to the app with the following:
Add a `SKCanvasView` component to the app with the following:

* `SkiaSharp` and `SkiaSharp.Views.Blazor` namespaces.
* Logic to draw in the SkiaSharp Canvas View component (`SKCanvasView`).
* `SkiaSharp` and `SkiaSharp.Views.Blazor` namespaces.
* Logic to draw in the SkiaSharp Canvas View component (`SKCanvasView`).

`Pages/NativeDependencyExample.razor`:
`Pages/NativeDependencyExample.razor`:

```razor
@page "/native-dependency-example"
@using SkiaSharp
@using SkiaSharp.Views.Blazor
```razor
@page "/native-dependency-example"
@using SkiaSharp
@using SkiaSharp.Views.Blazor

<PageTitle>Native dependency</PageTitle>
<PageTitle>Native dependency</PageTitle>

<h1>Native dependency example with SkiaSharp</h1>
<h1>Native dependency example with SkiaSharp</h1>

<SKCanvasView OnPaintSurface="OnPaintSurface" />
<SKCanvasView OnPaintSurface="OnPaintSurface" />

@code {
private void OnPaintSurface(SKPaintSurfaceEventArgs e)
{
var canvas = e.Surface.Canvas;
@code {
private void OnPaintSurface(SKPaintSurfaceEventArgs e)
{
var canvas = e.Surface.Canvas;

canvas.Clear(SKColors.White);
canvas.Clear(SKColors.White);

using var paint = new SKPaint
{
Color = SKColors.Black,
IsAntialias = true,
TextSize = 24
};
using var paint = new SKPaint
{
Color = SKColors.Black,
IsAntialias = true,
TextSize = 24
};

canvas.DrawText("SkiaSharp", 0, 24, paint);
}
}
```
canvas.DrawText("SkiaSharp", 0, 24, paint);
}
}
```

1. Build the app, which might take several minutes. Run the app and navigate to the `NativeDependencyExample` component at `/native-dependency-example`.
Build the app, which might take several minutes. Run the app and navigate to the `NativeDependencyExample` component at `/native-dependency-example`.

## Additional resources

[.NET WebAssembly build tools](xref:blazor/tooling/webassembly)
* [.NET WebAssembly build tools](xref:blazor/tooling/webassembly)
* [Mono/WebAssembly MSBuild properties and targets (`WasmApp.targets`, `dotnet/runtime` GitHub repository)](https://github.com/dotnet/runtime/blob/main/src/mono/wasm/build/WasmApp.Common.targets)
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ builder.Services.AddAuthorizationBuilder()
.SetFallbackPolicy(requireAuthPolicy);
```

Opt out of authorization at public endpoints by applying the [`[AllowAnonymous]` attribute](xref:Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute) to the public endpoints. For examples, see the [Add a new `Logout.cshtml` and `SignedOut.cshtml` Razor pages to the project](#add-a-new-logoutcshtml-and-signedoutcshtml-razor-pages-to-the-project) and [Implement `Login` page](#implement-login-page) sections.

### Add a new `Logout.cshtml` and `SignedOut.cshtml` Razor pages to the project

A logout is required to sign out both the cookie session and the OpenID Connect session. The whole app needs to redirect to the OpenID Connect server to sign out. After a successful sign out, the app opens the `RedirectUri` route.
Expand Down Expand Up @@ -194,7 +196,7 @@ public class SignedOutModel : PageModel
}
```

### Implement `Login` page
### Implement `Login` page

A `Login` Razor page can also be implemented to call the `ChallengeAsync` directly with the required `AuthProperties`. This isn't required if the web app requires authentication and the default challenge is used.

Expand Down
4 changes: 2 additions & 2 deletions aspnetcore/security/authorization/roles.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ Access to an action can be limited by applying additional role authorization att

In the preceding `ControlAllPanelController` controller:

* Members of the `Administrator` role or the `PowerUser` role can access the controller and the `ShutDown` action.
* Only members of the `Administrator` role can access the `SetTime` action.
* Members of the `Administrator` role or the `PowerUser` role can access the controller and the `SetTime` action.
* Only members of the `Administrator` role can access the `ShutDown` action.

A controller can be secured but allow anonymous, unauthenticated access to individual actions:

Expand Down
2 changes: 1 addition & 1 deletion aspnetcore/web-api/advanced/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Conventions don't compose; each action may be associated with exactly one conven
[ProducesResponseType(StatusCodes.Status400BadRequest)]
```

For more information on `[ProducesDefaultResponseType]`, see [Default Response](https://swagger.io/docs/specification/describing-responses/#default).
For more information on `[ProducesDefaultResponseType]`, see [Default Response](https://swagger.io/docs/specification/describing-responses/#default-response).

1. `Microsoft.AspNetCore.Mvc.ApiConventionTypeAttribute` applied to a controller &mdash; Applies the specified convention type to all actions on the controller. A convention method is marked with hints that determine the actions to which the convention method applies. For more information on hints, see [Create web API conventions](#create-web-api-conventions)).

Expand Down
Loading