diff --git a/.github/workflows/quest-bulk.yml b/.github/workflows/quest-bulk.yml index 17ad8a49fe80..75c7724668b0 100644 --- a/.github/workflows/quest-bulk.yml +++ b/.github/workflows/quest-bulk.yml @@ -2,6 +2,7 @@ name: "bulk quest import" on: schedule: - cron: '0 10 * * *' # UTC time, that's 5:00 am EST, 2:00 am PST. + - cron: '0 9 6 * *' # This is the morning of the 6th. workflow_dispatch: inputs: reason: @@ -49,5 +50,5 @@ jobs: org: ${{ github.repository_owner }} repo: ${{ github.repository }} issue: '-1' - duration: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.duration || 5 }} + duration: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.duration || github.event.schedule == '0 9 6 * *' && -1 || 5 }} diff --git a/aspnetcore/blazor/call-web-api.md b/aspnetcore/blazor/call-web-api.md index 55770deffcd4..1ffa55835b13 100644 --- a/aspnetcore/blazor/call-web-api.md +++ b/aspnetcore/blazor/call-web-api.md @@ -505,6 +505,24 @@ await Http.PatchAsJsonAsync( "[{\"operationType\":2,\"path\":\"/IsComplete\",\"op\":\"replace\",\"value\":true}]"); ``` +As of C# 11 (.NET 7), you can compose a JSON string as a [raw string literal](/dotnet/csharp/language-reference/tokens/raw-string). Specify JSON syntax with the field to the [`[StringSyntax]` attribute](xref:System.Diagnostics.CodeAnalysis.StringSyntaxAttribute) for code analysis tooling: + +```razor +@using System.Diagnostics.CodeAnalysis + +... + +@code { + [StringSyntax(StringSyntaxAttribute.Json)] + private const string patchOperation = + """[{"operationType":2,"path":"/IsComplete","op":"replace","value":true}]"""; + + ... + + await Http.PatchAsJsonAsync($"todoitems/{id}", patchOperation); +} +``` + returns an . To deserialize the JSON content from the response message, use the extension method. The following example reads JSON todo item data as an array. An empty array is created if no item data is returned by the method, so `content` isn't null after the statement executes: ```csharp diff --git a/aspnetcore/blazor/components/index.md b/aspnetcore/blazor/components/index.md index 7538501ce282..260211714999 100644 --- a/aspnetcore/blazor/components/index.md +++ b/aspnetcore/blazor/components/index.md @@ -28,7 +28,7 @@ Although "Razor components" shares some naming with other ASP.NET Core content-r :::moniker range=">= aspnetcore-8.0" > [!IMPORTANT] -> When using a Blazor Web App, most of the Blazor documentation example components ***require*** interactivity to function and demonstrate the concepts covered by the articles. When you test an example component provided by an article, make sure that either the app adopts global interactivity or the component adopts an interactive render mode. More information on this subject is provided by , which is the next article in the table of contents after this article. +> When using a Blazor Web App, most of the Blazor documentation example components ***require*** interactivity to function and demonstrate the concepts covered by the articles. *Interactivity* makes it possible for users to interact with rendered components. This includes app responses to [Document Object Model (DOM)](https://developer.mozilla.org/docs/Web/API/Document_Object_Model/Introduction) events and state changes tied to C# members via Blazor's event handlers and binding. When you test an example component provided by an article in a Blazor Web App, make sure that either the app adopts global interactivity or the component adopts an interactive render mode. More information on this subject is provided by , which is the next article in the table of contents after this article. :::moniker-end @@ -67,6 +67,9 @@ Components use [Razor syntax](xref:mvc/views/razor). Two Razor features are exte * App namespaces (alphabetical order) * Other directives (alphabetical order) + > [!NOTE] + > A *render mode* is only applied in Blazor Web Apps and includes modes that establish user interactivity with the rendered component. For more information, see . + No blank lines appear among the directives. One blank line appears between the directives and the first line of Razor markup. Example: diff --git a/aspnetcore/blazor/components/render-modes.md b/aspnetcore/blazor/components/render-modes.md index 6a8c40dad5df..6a2c16bdf374 100644 --- a/aspnetcore/blazor/components/render-modes.md +++ b/aspnetcore/blazor/components/render-modes.md @@ -18,7 +18,7 @@ This guidance doesn't apply to standalone Blazor WebAssembly apps. Blazor WebAss ## Render modes -Every component in a Blazor Web App adopts a *render mode* to determine the hosting model that it uses, where it's rendered, and whether or not it's interactive. +Every component in a Blazor Web App adopts a *render mode* to determine the hosting model that it uses, where it's rendered, and whether or not it's interactive. *Interactivity* makes it possible for users to interact with rendered components. This includes app responses to [Document Object Model (DOM)](https://developer.mozilla.org/docs/Web/API/Document_Object_Model/Introduction) events and state changes tied to C# members via Blazor's event handlers and binding. The following table shows the available render modes for rendering Razor components in a Blazor Web App. To apply a render mode to a component use the `@rendermode` directive on the component instance or on the component definition. Later in this article, examples are shown for each render mode scenario. diff --git a/aspnetcore/blazor/fundamentals/index.md b/aspnetcore/blazor/fundamentals/index.md index 2a02c168a363..80d18642237e 100644 --- a/aspnetcore/blazor/fundamentals/index.md +++ b/aspnetcore/blazor/fundamentals/index.md @@ -22,10 +22,10 @@ Razor components are either *statically* rendered or *interactively* rendered. *Static* or *static rendering* is a server-side scenario that means the component is rendered without the capacity for interplay between the user and .NET/C# code. JavaScript and HTML DOM events remain unaffected, but no user events on the client can be processed with .NET running on the server. -*Interactive* or *interactive rendering* means that the component has the capacity to process .NET events via C# code. The .NET events are either processed on the server by the ASP.NET Core runtime or in the browser on the client by the WebAssembly-based Blazor runtime. +*Interactive*/*interactivity* or *interactive rendering* means that the component has the capacity to process .NET events and binding via C# code. The .NET events and binding are either processed on the server by the ASP.NET Core runtime or in the browser on the client by the WebAssembly-based Blazor runtime. > [!IMPORTANT] -> When using a Blazor Web App, most of the Blazor documentation example components ***require*** interactivity to function and demonstrate the concepts covered by the articles. When you test an example component provided by an article, make sure that either the app adopts global interactivity or the component adopts an interactive render mode. +> When using a Blazor Web App, most of the Blazor documentation example components ***require*** interactivity to function and demonstrate the concepts covered by the articles. When you test an example component provided by an article in a Blazor Web App, make sure that either the app adopts global interactivity or the component adopts an interactive render mode. More information on this subject is provided by in the *Components* section, which appears later in the Blazor documentation set. More information on these concepts and how to control static and interactive rendering is found in the article later in the Blazor documentation. diff --git a/aspnetcore/blazor/host-and-deploy/webassembly.md b/aspnetcore/blazor/host-and-deploy/webassembly.md index 06a117482bb1..6e908687c8cf 100644 --- a/aspnetcore/blazor/host-and-deploy/webassembly.md +++ b/aspnetcore/blazor/host-and-deploy/webassembly.md @@ -734,7 +734,7 @@ A standalone Blazor WebAssembly app is published as a set of static files for ho To host the app in Docker: -* Choose a Docker container with web server support, such as Ngnix or Apache. +* Choose a Docker container with web server support, such as Nginx or Apache. * Copy the `publish` folder assets to a location folder defined in the web server for serving static files. * Apply additional configuration as needed to serve the Blazor WebAssembly app. diff --git a/aspnetcore/blazor/test.md b/aspnetcore/blazor/test.md index 338a11e2cad6..bd40a33b751d 100644 --- a/aspnetcore/blazor/test.md +++ b/aspnetcore/blazor/test.md @@ -164,4 +164,4 @@ The following actions take place at each step of the test: ## Additional resources * [Getting Started with bUnit](https://bunit.dev/docs/getting-started/): bUnit instructions include guidance on creating a test project, referencing testing framework packages, and building and running tests. -* [Blazor Testing from A to Z - Egil Hansen - Swetugg Stockholm 2024](https://youtu.be/GU_XbWjrP_g?si=1SrjeaP1T9LdFegN) ([Swetugg](https://www.swetugg.se/sthlm-2025)) +* [Blazor Testing from A to Z - Egil Hansen - NDC London 2025](https://www.youtube.com/watch?v=p-H5fEMCB8s) ([NDC London](https://ndclondon.com/)) diff --git a/aspnetcore/fundamentals/minimal-apis/resultsStream/7.0-samples/ResultsStreamSample/ResultsStreamSample.csproj b/aspnetcore/fundamentals/minimal-apis/resultsStream/7.0-samples/ResultsStreamSample/ResultsStreamSample.csproj index d3545c347391..1fca67c3d0a8 100644 --- a/aspnetcore/fundamentals/minimal-apis/resultsStream/7.0-samples/ResultsStreamSample/ResultsStreamSample.csproj +++ b/aspnetcore/fundamentals/minimal-apis/resultsStream/7.0-samples/ResultsStreamSample/ResultsStreamSample.csproj @@ -16,7 +16,7 @@ - + diff --git a/aspnetcore/fundamentals/servers/yarp/yarp-overview.md b/aspnetcore/fundamentals/servers/yarp/yarp-overview.md index f1cc5da463a4..c9b41a4c158e 100644 --- a/aspnetcore/fundamentals/servers/yarp/yarp-overview.md +++ b/aspnetcore/fundamentals/servers/yarp/yarp-overview.md @@ -24,7 +24,7 @@ A reverse proxy is a server that sits between client devices and backend servers - Load Balancing: Distributes incoming traffic across multiple backend servers to prevent overloading a specific server. Distribution increases performance and reliability. - Scalability: By distributing traffic across multiple servers, a reverse proxy helps scale apps to handle more users and higher loads. Backend servers scaled (added or removed) without impacting the client. -- [SSL/TSL Termination](/azure/application-gateway/ssl-overview): Offloads the TSL encryption and decryption processes from backend servers, reducing their workload. +- [SSL/TLS Termination](/azure/application-gateway/ssl-overview): Offloads the TLS encryption and decryption processes from backend servers, reducing their workload. - Connection abstraction, decoupling and control over URL-space: Inbound requests from external clients and outbound responses from the backend are independent. This independence allows for differnt: - Versions of HTTP, ie, HTTP/1.1, HTTP/2, HTTP/3. The proxy can upgrade or downgrade HTTP versions. - Connection lifetimes, which enables having long-lived connections on the backend while maintaining short client connections. @@ -32,7 +32,7 @@ A reverse proxy is a server that sits between client devices and backend servers - Security: Internal service endpoints can be hidden from external exposure, protecting against some types of cyber attacks such as [DDoS attacks](https://www.microsoft.com/security/business/security-101/what-is-a-ddos-attack?msockid=3e35ed3aa4666d8003aaf830a5006c74). - Caching: Frequently requested resources can be cached to reduce the load on backend servers and improve response times. - Versioning: Different versions of an API can be supported using different URL mappings. -- Simplified maintenance: Reverse proxies can handle [SSL/TSL Termination](/azure/application-gateway/ssl-overview) and other tasks, simplifying the configuration and maintenance of backend servers. For example, SSL certificates and security policies can be managed at the reverse proxy level instead of on each individual server. +- Simplified maintenance: Reverse proxies can handle [SSL/TLS Termination](/azure/application-gateway/ssl-overview) and other tasks, simplifying the configuration and maintenance of backend servers. For example, SSL certificates and security policies can be managed at the reverse proxy level instead of on each individual server. ## How a reverse proxy handles HTTP diff --git a/aspnetcore/grpc/client.md b/aspnetcore/grpc/client.md index 5109cedfcb4e..0f6d84f77457 100644 --- a/aspnetcore/grpc/client.md +++ b/aspnetcore/grpc/client.md @@ -4,7 +4,7 @@ author: jamesnk description: Learn how to call gRPC services with the .NET gRPC client. monikerRange: '>= aspnetcore-3.0' ms.author: wpickett -ms.date: 01/08/2025 +ms.date: 03/06/2025 uid: grpc/client --- # Call gRPC services with the .NET client @@ -62,6 +62,8 @@ Channel and client performance and usage: `GrpcChannel.ForAddress` isn't the only option for creating a gRPC client. If calling gRPC services from an ASP.NET Core app, consider [gRPC client factory integration](xref:grpc/clientfactory). gRPC integration with `HttpClientFactory` offers a centralized alternative to creating gRPC clients. +When calling gRPC methods, prefer using [asynchronous programming with async and await](/dotnet/csharp/asynchronous-programming/). Making gRPC calls with blocking, such as using `Task.Result` or `Task.Wait()`, prevents other tasks from using a thread. This can lead to thread pool starvation and poor performance. It could cause the app to hang with a deadlock. For more information, see [Asynchronous calls in client apps](xref:grpc/performance#asynchronous-calls-in-client-apps). + ## Make gRPC calls A gRPC call is initiated by calling a method on the client. The gRPC client will handle message serialization and addressing the gRPC call to the correct service. @@ -87,8 +89,10 @@ Console.WriteLine("Greeting: " + response.Message); Each unary service method in the `.proto` file will result in two .NET methods on the concrete gRPC client type for calling the method: an asynchronous method and a blocking method. For example, on `GreeterClient` there are two ways of calling `SayHello`: -* `GreeterClient.SayHelloAsync` - calls `Greeter.SayHello` service asynchronously. Can be awaited. -* `GreeterClient.SayHello` - calls `Greeter.SayHello` service and blocks until complete. Don't use in asynchronous code. +* `GreeterClient.SayHelloAsync` - calls the `Greeter.SayHello` service asynchronously. Can be awaited. +* `GreeterClient.SayHello` - calls the `Greeter.SayHello` service and blocks until complete. Don't use in asynchronous code. Can cause performance and reliability issues. + +For more information, see [Asynchronous calls in client apps](xref:grpc/performance#asynchronous-calls-in-client-apps). ### Server streaming call diff --git a/aspnetcore/grpc/performance.md b/aspnetcore/grpc/performance.md index 2188e82c65b5..f2123feda940 100644 --- a/aspnetcore/grpc/performance.md +++ b/aspnetcore/grpc/performance.md @@ -94,6 +94,27 @@ For more information about garbage collection, see [Workstation and server garba > [!NOTE] > ASP.NET Core apps use server GC by default. Enabling `` is only useful in non-server gRPC client apps, for example in a gRPC client console app. +## Asynchronous calls in client apps + +Prefer using [asynchronous programming with async and await](/dotnet/csharp/asynchronous-programming/) when calling gRPC methods. Making gRPC calls with blocking, such as using `Task.Result` or `Task.Wait()`, prevents other tasks from using a thread. This can lead to thread pool starvation, poor performance, and the app to hang with a deadlock. + +All gRPC method types generate asynchronous APIs on gRPC clients. The exception is unary methods, which generate both async _and_ blocking methods. + +Consider the following gRPC service defined in a *.proto* file: + +```protobuf +service Greeter { + rpc SayHello (HelloRequest) returns (HelloReply); +} +``` + +Its generated `GreeterClient` type has two .NET methods for calling `SayHello`: + +* `GreeterClient.SayHelloAsync` - calls the `Greeter.SayHello` service asynchronously. Can be awaited. +* `GreeterClient.SayHello` - calls the `Greeter.SayHello` service and blocks until complete. + +The blocking `GreeterClient.SayHello` method shouldn't be used in asynchronous code. It can cause performance and reliability issues. + ## Load balancing Some load balancers don't work effectively with gRPC. L4 (transport) load balancers operate at a connection level, by distributing TCP connections across endpoints. This approach works well for loading balancing API calls made with HTTP/1.1. Concurrent calls made with HTTP/1.1 are sent on different connections, allowing calls to be load balanced across endpoints. diff --git a/aspnetcore/security/authentication/social/google-logins.md b/aspnetcore/security/authentication/social/google-logins.md index c52f3326cb1b..eb5385d4a677 100644 --- a/aspnetcore/security/authentication/social/google-logins.md +++ b/aspnetcore/security/authentication/social/google-logins.md @@ -19,7 +19,7 @@ This tutorial shows you how to enable users to sign in with their Google account * Go to [Google API & Services](https://console.cloud.google.com/apis). * A **Project** must exist first, you may have to create one. Once a project is selected, enter the **Dashboard**. -* In the **Oauth consent screen** of the **Dashboard**: +* In the **OAuth consent screen** of the **Dashboard**: * Select **User Type - External** and **CREATE**. * In the **App information** dialog, Provide an **app name** for the app, **user support email**, and **developer contact information**. * Step through the **Scopes** step. @@ -55,14 +55,14 @@ You can manage your API credentials and usage in the [API Console](https://conso * Add the [`Google.Apis.Auth.AspNetCore3`](https://www.nuget.org/packages/Google.Apis.Auth.AspNetCore3) NuGet package to the app. * Add the Authentication service to the `program.cs`: -* Follow [`Add Authtication for asp.net app`](https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#configure-your-application-to-use-google.apis.auth.aspnetcore3) +* Follow [`Add Authentication for asp.net app`](https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#configure-your-application-to-use-google.apis.auth.aspnetcore3) [!INCLUDE [default settings configuration](includes/default-settings2-2.md)] ## Sign in with Google -* Get a link to the libary at [google developer library link ](https://developers.google.com/identity/gsi/web/guides/client-library) to get link of library. -* Then go to [google developer button genration ](https://developers.google.com/identity/gsi/web/tools/configurator) -* Setup your Controller to match with ` data-login_uri="{HostName}/{ControllerName}/{actionName}" ` attrbute because after success login it will forward you to that link. +* Get a link to the library at [Google Developer Library](https://developers.google.com/identity/gsi/web/guides/client-library). +* Then go to [Google Developer Button Generation](https://developers.google.com/identity/gsi/web/tools/configurator). +* Setup your Controller to match the `data-login_uri="{HostName}/{ControllerName}/{actionName}"` attribute, as it will forward you to that link after a successful login. * Create a controller and action that takes one argument `string credential`, which is returned by Google upon completing the login process. * Verify the `credential` using the following line of code: `GoogleJsonWebSignature.Payload payload = await GoogleJsonWebSignature.ValidateAsync(credential);` diff --git a/aspnetcore/security/identity-management-solutions.md b/aspnetcore/security/identity-management-solutions.md index c1bfef6cc5f6..ddf146b35c2d 100644 --- a/aspnetcore/security/identity-management-solutions.md +++ b/aspnetcore/security/identity-management-solutions.md @@ -26,7 +26,7 @@ Many of the commercial licenses provide "community" or free options that may be |**Duende IdentityServer**|Self host|[Commercial](https://duendesoftware.com/products/identityserver#pricing)|[https://duendesoftware.com/](https://duendesoftware.com/products/identityserver)|[ASP.NET Identity integration](https://docs.duendesoftware.com)| |**Keycloak**|Container|[OSS (Apache 2.0)](https://github.com/keycloak/keycloak/blob/master/LICENSE.txt)|[https://www.keycloak.org/](https://www.keycloak.org/)|[Keycloak documentation](https://www.keycloak.org/documentation)| |**Microsoft Entra ID**|Managed|[Commercial](https://azure.microsoft.com/pricing/details/active-directory/)|[https://azure.microsoft.com/services/active-directory/](https://azure.microsoft.com/services/active-directory/)|[Entra documentation](/azure/active-directory/fundamentals/active-directory-whatis)| -|**Okta**|Managed|[Commercial](https://www.okta.com/pricing/)|[https://www.okta.com/](https://www.okta.com/)|[Okta for ASP.NET Core](https://developer.okta.com/code/dotnet/aspnetcore/)| +|**Okta**|Managed|[Commercial](https://www.okta.com/pricing/)|[https://www.okta.com/](https://www.okta.com/)|[Okta for ASP.NET Core](https://developer.okta.com/code/)| |**OpenIddict**|Self host|[OSS (Apache 2.0)](https://github.com/openiddict/openiddict-core/blob/dev/LICENSE.md)|[https://github.com/openiddict/openiddict-core](https://github.com/openiddict/openiddict-core)|[OpenIddict documentation](https://documentation.openiddict.com/)| --> @@ -37,7 +37,7 @@ Many of the commercial licenses provide "community" or free options that may be |[Duende IdentityServer](https://duendesoftware.com/products/identityserver)|Self host|[Commercial](https://duendesoftware.com/products/identityserver#pricing)|[ASP.NET Identity integration](https://docs.duendesoftware.com)| |[Keycloak](https://www.keycloak.org)|Container|[OSS (Apache 2.0)](https://github.com/keycloak/keycloak/blob/master/LICENSE.txt)|[Keycloak securing apps documentation](https://www.keycloak.org/guides#securing-apps)| |[Microsoft Entra ID](https://azure.microsoft.com/services/active-directory)|Managed|[Commercial](https://azure.microsoft.com/pricing/details/active-directory/)|[Entra documentation](/azure/active-directory/fundamentals/active-directory-whatis)| -|[Okta](https://www.okta.com)|Managed|[Commercial](https://www.okta.com/pricing/)|[Okta for ASP.NET Core](https://developer.okta.com/code/dotnet/aspnetcore/)| +|[Okta](https://www.okta.com)|Managed|[Commercial](https://www.okta.com/pricing/)|[Okta for ASP.NET Core](https://developer.okta.com/code/)| |[OpenIddict](https://github.com/openiddict/openiddict-core)|Self host|[OSS (Apache 2.0)](https://github.com/openiddict/openiddict-core/blob/dev/LICENSE.md)|[OpenIddict documentation](https://documentation.openiddict.com/)| Is there a solution that should be added to this list? Do you have a correction, suggestion, or feedback? We welcome your contributions. Learn [how to contribute](https://github.com/dotnet/aspnetcore/blob/main/CONTRIBUTING.md).