diff --git a/aspnetcore/blazor/security/blazor-web-app-with-oidc.md b/aspnetcore/blazor/security/blazor-web-app-with-oidc.md index be8987e5b81e..4776c3f06941 100644 --- a/aspnetcore/blazor/security/blazor-web-app-with-oidc.md +++ b/aspnetcore/blazor/security/blazor-web-app-with-oidc.md @@ -17,7 +17,7 @@ This article describes how to secure a Blazor Web App with [OpenID Connect (OIDC :::zone pivot="without-bff-pattern" -This version of the article covers implementing OIDC without adopting the [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends). The BFF pattern is useful for making authenticated requests to external services. Change the article version selector to **OIDC with BFF pattern** if the app's specification calls for adopting the BFF pattern. +This version of the article covers implementing OIDC without adopting the [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends) with an app that adopts global Interactive Auto rendering (server and `.Client` projects). The BFF pattern is useful for making authenticated requests to external services. Change the article version selector to **OIDC with BFF pattern** if the app's specification calls for adopting the BFF pattern. The following specification is covered: @@ -92,10 +92,10 @@ The following : Defines whether access and refresh tokens should be stored in the after a successful authorization. This property is set to `false` to reduce the size of the final authentication cookie. +* : Defines whether access and refresh tokens should be stored in the after a successful authorization. This property is set to `true` so the refresh token gets stored for non-interactive token refresh. ```csharp - oidcOptions.SaveTokens = false; + oidcOptions.SaveTokens = true; ``` * Scope for offline access (): The `offline_access` scope is required for the refresh token. @@ -251,6 +251,189 @@ The sample app only provides a user name and email for display purposes. It does :::zone-end +:::zone pivot="without-bff-pattern-server" + +This version of the article covers implementing OIDC without adopting the [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends) with an app that adopts global Interactive Server rendering (single project). The BFF pattern is useful for making authenticated requests to external services. Change the article version selector to **OIDC with BFF pattern** if the app's specification calls for adopting the BFF pattern with global Interactive Auto rendering. + +The following specification is covered: + +* The Blazor Web App uses [the Server render mode with global interactivity](xref:blazor/components/render-modes). +* This app is a starting point for any OIDC authentication flow. OIDC is configured manually in the app and doesn't rely upon [Microsoft Entra ID](https://www.microsoft.com/security/business/microsoft-entra) or [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) packages, nor does the sample app require [Microsoft Azure](https://azure.microsoft.com/) hosting. However, the sample app can be used with Entra, Microsoft Identity Web, and hosted in Azure. +* Automatic non-interactive token refresh. + +For an alternative experience using [Microsoft Authentication Library for .NET](/entra/msal/dotnet/), [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/), and [Microsoft Entra ID](https://www.microsoft.com/security/business/identity-access/microsoft-entra-id), see . + +## Sample app + +The sample app consists of a single server-side Blazor Web App project (`BlazorWebAppOidcServer`). + +Access the sample app through the latest version folder from the repository's root with the following link. The project is in the `BlazorWebAppOidcServer` folder for .NET 8 or later. + +[View or download sample code](https://github.com/dotnet/blazor-samples) ([how to download](xref:blazor/fundamentals/index#sample-apps)) + +## Configuration + +This section explains how to configure the sample app. + +> [!NOTE] +> For Microsoft Entra ID or Azure AD B2C, you can use from [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) ([`Microsoft.Identity.Web` NuGet package](https://www.nuget.org/packages/Microsoft.Identity.Web), [API documentation]()), which adds both the OIDC and Cookie authentication handlers with the appropriate defaults. The sample app and the guidance in this section doesn't use Microsoft Identity Web. The guidance demonstrates how to configure the OIDC handler *manually* for any OIDC provider. For more information on implementing Microsoft Identity Web, see the linked resources. + +### Establish the client secret + +[!INCLUDE[](~/blazor/security/includes/secure-authentication-flows.md)] + +For local development testing, use the [Secret Manager tool](xref:security/app-secrets) to store the app's client secret under the configuration key `Authentication:Schemes:MicrosoftOidc:ClientSecret`. + +> [!NOTE] +> If the app uses Microsoft Entra ID or Azure AD B2C, create a client secret in the app's registration in the Entra or Azure portal (**Manage** > **Certificates & secrets** > **New client secret**). Use the **Value** of the new secret in the following guidance. + +The [sample app](#sample-app) hasn't been initialized for the Secret Manager tool. Use a command shell, such as the Developer PowerShell command shell in Visual Studio, to execute the following command. Before executing the command, change the directory with the `cd` command to the project's directory. The command establishes a user secrets identifier (`` in the app's project file): + +```dotnetcli +dotnet user-secrets init +``` + +Execute the following command to set the client secret. The `{SECRET}` placeholder is the client secret obtained from the app's registration: + +```dotnetcli +dotnet user-secrets set "Authentication:Schemes:MicrosoftOidc:ClientSecret" "{SECRET}" +``` + +If using Visual Studio, you can confirm the secret is set by right-clicking the project in **Solution Explorer** and selecting **Manage User Secrets**. + +### Configure the app + +The following configuration is found in the project's `Program` file on the call to : + +* : Sets the authentication scheme corresponding to the middleware responsible of persisting user's identity after a successful authentication. The OIDC handler needs to use a sign-in scheme that's capable of persisting user credentials across requests. The following line is present merely for demonstration purposes. If omitted, is used as a fallback value. + + ```csharp + oidcOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + ``` + +* Scopes for `openid` and `profile` () (Optional): The `openid` and `profile` scopes are also configured by default because they're required for the OIDC handler to work, but these may need to be re-added if scopes are included in the `Authentication:Schemes:MicrosoftOidc:Scope` configuration. For general configuration guidance, see and . + + ```csharp + oidcOptions.Scope.Add(OpenIdConnectScope.OpenIdProfile); + ``` + +* : Defines whether access and refresh tokens should be stored in the after a successful authorization. This property is set to `true` so the refresh token gets stored for non-interactive token refresh. + + ```csharp + oidcOptions.SaveTokens = true; + +* Scope for offline access (): The `offline_access` scope is required for the refresh token. + + ```csharp + oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess); + ``` + +* and : Sets the Authority and Client ID for OIDC calls. + + ```csharp + oidcOptions.Authority = "{AUTHORITY}"; + oidcOptions.ClientId = "{CLIENT ID}"; + ``` + + Example: + + * Authority (`{AUTHORITY}`): `https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/` (uses Tenant ID `aaaabbbb-0000-cccc-1111-dddd2222eeee`) + * Client Id (`{CLIENT ID}`): `00001111-aaaa-2222-bbbb-3333cccc4444` + + ```csharp + oidcOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0/"; + oidcOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444"; + ``` + + Example for Microsoft Azure "common" authority: + + The "common" authority should be used for multi-tenant apps. You can also use the "common" authority for single-tenant apps, but a custom is required, as shown later in this section. + + ```csharp + oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/"; + ``` + +* : Configures the OIDC handler to only perform authorization code flow. Implicit grants and hybrid flows are unnecessary in this mode. The OIDC handler automatically requests the appropriate tokens using the code returned from the authorization endpoint. + + ```csharp + oidcOptions.ResponseType = OpenIdConnectResponseType.Code; + ``` + + > [!NOTE] + > In the Entra or Azure portal's **Implicit grant and hybrid flows** app registration configuration, do **not** select either checkbox for the authorization endpoint to return **Access tokens** or **ID tokens**. + +* and configuration of and : Many OIDC servers use "`name`" and "`role`" rather than the SOAP/WS-Fed defaults in . When is set to `false`, the handler doesn't perform claims mappings, and the claim names from the JWT are used directly by the app. The following example sets the role claim type to "`roles`," which is appropriate for [Microsoft Entra ID (ME-ID)](https://www.microsoft.com/security/business/microsoft-entra). Consult your identity provider's documentation for more information. + + > [!NOTE] + > must be set to `false` for most OIDC providers, which prevents renaming claims. + + ```csharp + oidcOptions.MapInboundClaims = false; + oidcOptions.TokenValidationParameters.NameClaimType = "name"; + oidcOptions.TokenValidationParameters.RoleClaimType = "roles"; + ``` + +* Path configuration: Paths must match the redirect URI (login callback path) and post logout redirect (signed-out callback path) paths configured when registering the application with the OIDC provider. In the Azure portal, paths are configured in the **Authentication** blade of the app's registration. Both the sign-in and sign-out paths must be registered as redirect URIs. The default values are `/signin-oidc` and `/signout-callback-oidc`. + + * : The request path within the app's base path where the user-agent is returned. + + Configure the signed-out callback path in the app's OIDC provider registration. In the following example, the `{PORT}` placeholder is the app's port: + + > :::no-loc text="https://localhost:{PORT}/signin-oidc"::: + + > [!NOTE] + > A port isn't required for `localhost` addresses when using Microsoft Entra ID. Most other OIDC providers require the correct port. + + * (configuration key: "`SignedOutCallbackPath`"): The request path within the app's base path intercepted by the OIDC handler where the user agent is first returned after signing out from the identity provider. The sample app doesn't set a value for the path because the default value of "`/signout-callback-oidc`" is used. After intercepting the request, the OIDC handler redirects to the or , if specified. + + Configure the signed-out callback path in the app's OIDC provider registration. In the following example, the `{PORT}` placeholder is the app's port: + + > :::no-loc text="https://localhost:{PORT}/signout-callback-oidc"::: + + > [!NOTE] + > When using Microsoft Entra ID, set the path in the **Web** platform configuration's **Redirect URI** entries in the Entra or Azure portal. A port isn't required for `localhost` addresses when using Entra. Most other OIDC providers require the correct port. If you don't add the signed-out callback path URI to the app's registration in Entra, Entra refuses to redirect the user back to the app and merely asks them to close their browser window. + + * : Requests received on this path cause the handler to invoke sign-out using the sign-out scheme. + + In the following example, the `{PORT}` placeholder is the app's port: + + > :::no-loc text="https://localhost/signout-oidc"::: + + > [!NOTE] + > When using Microsoft Entra ID, set the **Front-channel logout URL** in the Entra or Azure portal. A port isn't required for `localhost` addresses when using Entra. Most other OIDC providers require the correct port. + + ```csharp + oidcOptions.CallbackPath = new PathString("{PATH}"); + oidcOptions.SignedOutCallbackPath = new PathString("{PATH}"); + oidcOptions.RemoteSignOutPath = new PathString("{PATH}"); + ``` + + Examples (default values): + + ```csharp + oidcOptions.CallbackPath = new PathString("/signin-oidc"); + oidcOptions.SignedOutCallbackPath = new PathString("/signout-callback-oidc"); + oidcOptions.RemoteSignOutPath = new PathString("/signout-oidc"); + ``` + +* (*Microsoft Azure only with the "common" endpoint*) : Many OIDC providers work with the default issuer validator, but we need to account for the issuer parameterized with the Tenant ID (`{TENANT ID}`) returned by `https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration`. For more information, see [SecurityTokenInvalidIssuerException with OpenID Connect and the Azure AD "common" endpoint (`AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet` #1731)](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/1731). + + Only for apps using Microsoft Entra ID or Azure AD B2C with the "common" endpoint: + + ```csharp + var microsoftIssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcOptions.Authority); + oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator.Validate; + ``` + +## Sample app code + +Inspect the sample app for the following features: + +* Automatic non-interactive token refresh with the help of a custom cookie refresher (`CookieOidcRefresher.cs`). +* The `Weather` component uses the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) to prevent unauthorized access. 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). + +:::zone-end + :::zone pivot="with-bff-pattern" This version of the article covers implementing OIDC with the [Backend for Frontend (BFF) pattern](/azure/architecture/patterns/backends-for-frontends). Change the article version selector to **OIDC without BFF pattern** if the app's specification doesn't call for adopting the BFF pattern. diff --git a/aspnetcore/includes/run-the-app9.0.md b/aspnetcore/includes/run-the-app9.0.md new file mode 100644 index 000000000000..f2284876a802 --- /dev/null +++ b/aspnetcore/includes/run-the-app9.0.md @@ -0,0 +1,29 @@ +# [Visual Studio](#tab/visual-studio) + +* Press Ctrl+F5 to run without the debugger. + + [!INCLUDE[](~/includes/trustCertVS.md)] + + Visual Studio: + + * Starts [Kestrel](xref:fundamentals/servers/index#kestrel) server. + * Launches a browser. + * Navigates to `http://localhost:port`, such as `http://localhost:7042`. + * *port*: A randomly assigned port number for the app. + * `localhost`: The standard hostname for the local computer. Localhost only serves web requests from the local computer. + +# [Visual Studio Code](#tab/visual-studio-code) + + [!INCLUDE[](~/includes/trustCertVSC.md)] + +* Press **Ctrl-F5** to run without the debugger. + + Visual Studio Code: + + * Starts [Kestrel](xref:fundamentals/servers/index#kestrel) server. + * Launches a browser. + * Navigates to `http://localhost:port`, such as `http://localhost:7042`. + * *port*: A randomly assigned port number for the app. + * `localhost`: The standard hostname for the local computer. Localhost only serves web requests from the local computer. + +--- diff --git a/aspnetcore/security/authentication/configure-jwt-bearer-authentication.md b/aspnetcore/security/authentication/configure-jwt-bearer-authentication.md index 492b72637a0a..f633d43291af 100644 --- a/aspnetcore/security/authentication/configure-jwt-bearer-authentication.md +++ b/aspnetcore/security/authentication/configure-jwt-bearer-authentication.md @@ -125,7 +125,7 @@ JWT bearer tokens should be fully validated in an API. The following should be v * Audience claim with the expected value. * Token expiration. -The following claims are required for OAuth 2.0 access tokens: `iss`, `exp`, `aud`, `sub`, `client_id`, `iat, and `jti`. +The following claims are required for OAuth 2.0 access tokens: `iss`, `exp`, `aud`, `sub`, `client_id`, `iat`, and `jti`. If any of these claims or values are incorrect, the API should return a 401 response. @@ -188,7 +188,7 @@ var requireAuthPolicy = new AuthorizationPolicyBuilder() .Build(); builder.Services.AddAuthorizationBuilder() - .SetFallbackPolicy(requireAuthPolicy); + .SetDefaultPolicy(requireAuthPolicy); ``` The [Authorize](/dotnet/api/microsoft.aspnetcore.authorization.authorizeattribute) attribute can also be used to force the authentication. If multiple schemes are used, the bearer scheme generally needs to be set as the default authentication scheme or specified via `[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme])`. @@ -223,7 +223,7 @@ Asymmetric keys should **always** be used when creating access tokens. The publi ### Never create an access token from a username/password request -You should **NOT** create an access token from a username/password request. Username/password requests aren't authenticated and are vunerable to impersonation and phishing attacks. Access tokens should only be created using an OpenID Connect flow or an OAuth standard flow. Deviating from these standards can result in an insecure app. +You should **NOT** create an access token from a username/password request. Username/password requests aren't authenticated and are vulnerable to impersonation and phishing attacks. Access tokens should only be created using an OpenID Connect flow or an OAuth standard flow. Deviating from these standards can result in an insecure app. ### Use cookies diff --git a/aspnetcore/test/http-files.md b/aspnetcore/test/http-files.md index 1e57df13688e..b158391084ff 100644 --- a/aspnetcore/test/http-files.md +++ b/aspnetcore/test/http-files.md @@ -386,7 +386,7 @@ To generate a random integer, use `$randomInt`. The syntax is `{{$randomInt [min * `$datetime` generates a `datetime` string in UTC. The syntax is `{{$datetime [format] [offset option]}}` where the format and offset options are optional. * `$localDatetime` generates a `datetime` string in the local time zone. The syntax is `{{$localDatetime [format] [offset option]}}` where the format and offset options are optional. -* `$timeStamp` generates a `timestamp` in UTC. The `timestamp` is the [number of seconds since the Unix Epoch in UTC time](xref:System.DateTimeOffset.ToUnixTimeSeconds?displayProperty=nameWithType). The syntax is `{{$timestamp [offset option]}}` where the offset option is optional. +* `$timestamp` generates a `timestamp` in UTC. The `timestamp` is the [number of seconds since the Unix Epoch in UTC time](xref:System.DateTimeOffset.ToUnixTimeSeconds?displayProperty=nameWithType). The syntax is `{{$timestamp [offset option]}}` where the offset option is optional. The `[format]` option is one of `rfc1123`, `iso8601`, or a custom format in quotation marks. For example: diff --git a/aspnetcore/tutorials/grpc/grpc-start.md b/aspnetcore/tutorials/grpc/grpc-start.md index 9b1786091a3f..610cd9b3392e 100644 --- a/aspnetcore/tutorials/grpc/grpc-start.md +++ b/aspnetcore/tutorials/grpc/grpc-start.md @@ -4,12 +4,12 @@ author: jamesnk description: This tutorial shows how to create a gRPC Service and gRPC client on ASP.NET Core. Learn how to create a gRPC Service project, edit a proto file, and add a duplex streaming call. monikerRange: '>= aspnetcore-3.0' ms.author: wpickett -ms.date: 08/30/2023 +ms.date: 01/30/2025 uid: tutorials/grpc/grpc-start --- # Tutorial: Create a gRPC client and server in ASP.NET Core -:::moniker range=">= aspnetcore-8.0" +:::moniker range=">= aspnetcore-9.0" This tutorial shows how to create a .NET Core [gRPC](xref:grpc/index) client and an ASP.NET Core gRPC Server. At the end, you'll have a gRPC client that communicates with the gRPC Greeter service. In this tutorial, you: @@ -23,15 +23,11 @@ In this tutorial, you: # [Visual Studio](#tab/visual-studio) -[!INCLUDE[](~/includes/net-prereqs-vs-8.0.md)] +[!INCLUDE[](~/includes/net-prereqs-vs-9.0.md)] # [Visual Studio Code](#tab/visual-studio-code) -[!INCLUDE[](~/includes/net-prereqs-vsc-8.0.md)] - -# [Visual Studio for Mac](#tab/visual-studio-mac) - -[!INCLUDE[](~/includes/net-prereqs-mac-8.0.md)] +[!INCLUDE[](~/includes/net-prereqs-vsc-9.0.md)] --- @@ -43,13 +39,13 @@ In this tutorial, you: * In the **Create a new project** dialog, search for `gRPC`. Select **ASP.NET Core gRPC Service** and select **Next**. * In the **Configure your new project** dialog, enter `GrpcGreeter` for **Project name**. It's important to name the project *GrpcGreeter* so the namespaces match when you copy and paste code. * Select **Next**. -* In the **Additional information** dialog, select **.NET 8.0 (Long Term Support)** and then select **Create**. +* In the **Additional information** dialog, select **.NET 9.0 (Standard Term Support)** and then select **Create**. # [Visual Studio Code](#tab/visual-studio-code) The tutorial assumes familiarity with VS Code. For more information, see [Getting started with VS Code](https://code.visualstudio.com/docs). -* Select **New Terminal** from the **Terminal** menu to open the [integrated terminal](https://code.visualstudio.com/docs/editor/integrated-terminal). +* Select **New Terminal** from the **Terminal** menu to open the [integrated terminal](https://code.visualstudio.com/docs/terminal/basics). * Change to the directory (`cd`) that will contain the project. * Run the following commands: @@ -64,19 +60,11 @@ The tutorial assumes familiarity with VS Code. For more information, see [Gettin [!INCLUDE[](~/includes/vscode-trust-authors-add-assets.md)] -# [Visual Studio for Mac](#tab/visual-studio-mac) - -* Start Visual Studio 2022 for Mac and select **File** > **New Project**. -* In the **Choose a template for your new project** dialog, select **Web and Console** > **App** > **gRPC Service** and select **Continue**. -* Select **.NET 8.0** for the target framework and select **Continue**. -* Name the project **GrpcGreeter**. It's important to name the project *GrpcGreeter* so the namespaces match when you copy and paste code. -* Select **Continue**. - --- ### Run the service -[!INCLUDE[](~/includes/run-the-app6.0.md)] +[!INCLUDE[](~/includes/run-the-app9.0.md)] The logs show the service listening on `https://localhost:`, where `` is the localhost port number randomly assigned when the project is created and set in `Properties/launchSettings.json`. @@ -110,11 +98,11 @@ info: Microsoft.Hosting.Lifetime[0] * Open a second instance of Visual Studio and select **New Project**. * In the **Create a new project** dialog, select **Console App**, and select **Next**. * In the **Project name** text box, enter **GrpcGreeterClient** and select **Next**. -* In the **Additional information** dialog, select **.NET 8.0 (Long Term Support)** and then select **Create**. +* In the **Additional information** dialog, select **.NET 9.0 (Standard Term Support)** and then select **Create**. # [Visual Studio Code](#tab/visual-studio-code) -* Open the [integrated terminal](https://code.visualstudio.com/docs/editor/integrated-terminal). +* Open the [integrated terminal](https://code.visualstudio.com/docs/terminal/basics). * Change directories (`cd`) to a folder for the project. * Run the following commands: @@ -125,14 +113,6 @@ info: Microsoft.Hosting.Lifetime[0] [!INCLUDE[](~/includes/vscode-trust-authors-add-assets.md)] -# [Visual Studio for Mac](#tab/visual-studio-mac) - -* In Visual Studio 2022 for Mac select **File** > **Add** > **Project...**. -* In the **Choose a template for your new project** dialog, select **Web and Console** > **App** > **Console Application**, and select **Continue**. -* Select **.NET 8.0** for the target framework, and select **Continue**. -* Name the project **GrpcGreeterClient**. It's important to name the project *GrpcGreeterClient* so the namespaces match when you copy and paste code. -* Select **Continue**. - --- ### Add required NuGet packages @@ -177,15 +157,6 @@ dotnet add GrpcGreeterClient.csproj package Google.Protobuf dotnet add GrpcGreeterClient.csproj package Grpc.Tools ``` -# [Visual Studio for Mac](#tab/visual-studio-mac) - -* Right-click **GrpcGreeterClient** project in the **Solution Pad** and select **Manage NuGet Packages**. -* Enter **Grpc.Net.Client** in the search box. -* Select the **Grpc.Net.Client** package from the results pane and select **Add Package**. -* In **Select Projects** select **OK**. -* If the **License Acceptance** dialog appears, select **Accept** if you agree to the license terms. -* Repeat for `Google.Protobuf` and `Grpc.Tools`. - --- ### Add greet.proto @@ -208,10 +179,6 @@ dotnet add GrpcGreeterClient.csproj package Grpc.Tools Select the `GrpcGreeterClient.csproj` file. -# [Visual Studio for Mac](#tab/visual-studio-mac) - - Right-click the project and select **Edit Project File**. - --- * Add an item group with a `` element that refers to the *greet.proto* file: @@ -236,7 +203,7 @@ dotnet add GrpcGreeterClient.csproj package Grpc.Tools * Update the gRPC client `Program.cs` file with the following code. - [!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample8/GrpcGreeterClient/Program.cs?name=snippet2&highlight=6)] + [!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeterClient/Program.cs?name=snippet2&highlight=5)] * In the preceding highlighted code, replace the localhost port number `7042` with the `HTTPS` port number specified in `Properties/launchSettings.json` within the `GrpcGreeter` service project. @@ -247,33 +214,28 @@ The Greeter client is created by: * Instantiating a `GrpcChannel` containing the information for creating the connection to the gRPC service. * Using the `GrpcChannel` to construct the Greeter client: -[!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample8/GrpcGreeterClient/Program.cs?name=snippet&highlight=1-3)] +[!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeterClient/Program.cs?name=snippet&highlight=1-3)] The Greeter client calls the asynchronous `SayHello` method. The result of the `SayHello` call is displayed: -[!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample8/GrpcGreeterClient/Program.cs?name=snippet&highlight=4-7)] +[!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeterClient/Program.cs?name=snippet&highlight=4-6)] ## Test the gRPC client with the gRPC Greeter service Update the `appsettings.Development.json` file by adding the following highlighted lines: -[!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample8/GrpcGreeter/appsettings.Development.json?highlight=6-7)] +[!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/appsettings.Development.json?highlight=6-7)] # [Visual Studio](#tab/visual-studio) -* In the Greeter service, press `Ctrl+F5` to start the server without the debugger. -* In the `GrpcGreeterClient` project, press `Ctrl+F5` to start the client without the debugger. +* In the `GrpcGreeter` service project, press `Ctrl+F5` to start the server without the debugger. +* In the `GrpcGreeterClient` console project, press `Ctrl+F5` to start the client without the debugger. # [Visual Studio Code](#tab/visual-studio-code) * Start the Greeter service. * Start the client. -# [Visual Studio for Mac](#tab/visual-studio-mac) - -* Start the Greeter service. -* Start the client. - --- The client sends a greeting to the service with a message containing its name, *GreeterClient*. The service sends the message "Hello GreeterClient" as a response. The "Hello GreeterClient" response is displayed in the command prompt: @@ -295,13 +257,13 @@ info: Microsoft.Hosting.Lifetime[0] info: Microsoft.Hosting.Lifetime[0] Content root path: C:\GH\aspnet\docs\4\Docs\aspnetcore\tutorials\grpc\grpc-start\sample\GrpcGreeter info: Microsoft.AspNetCore.Hosting.Diagnostics[1] - Request starting HTTP/2 POST https://localhost:/Greet.Greeter/SayHello application/grpc + Request starting HTTP/2 POST https://localhost:/greet.Greeter/SayHello application/grpc info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] - Executing endpoint 'gRPC - /Greet.Greeter/SayHello' + Executing endpoint 'gRPC - /greet.Greeter/SayHello' info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] - Executed endpoint 'gRPC - /Greet.Greeter/SayHello' + Executed endpoint 'gRPC - /greet.Greeter/SayHello' info: Microsoft.AspNetCore.Hosting.Diagnostics[2] - Request finished in 78.32260000000001ms 200 application/grpc + Request finished HTTP/2 POST https://localhost:7042/greet.Greeter/SayHello - 200 - application/grpc 40.4615ms ``` > [!NOTE] @@ -316,6 +278,8 @@ info: Microsoft.AspNetCore.Hosting.Diagnostics[2] :::moniker-end +[!INCLUDE[](~/tutorials/grpc/grpc-start/includes/grpc-start8.md)] + [!INCLUDE[](~/tutorials/grpc/grpc-start/includes/grpc-start7.md)] [!INCLUDE[](~/tutorials/grpc/grpc-start/includes/grpc-start6.md)] diff --git a/aspnetcore/tutorials/grpc/grpc-start/includes/grpc-start8.md b/aspnetcore/tutorials/grpc/grpc-start/includes/grpc-start8.md new file mode 100644 index 000000000000..3b641696593b --- /dev/null +++ b/aspnetcore/tutorials/grpc/grpc-start/includes/grpc-start8.md @@ -0,0 +1,306 @@ +:::moniker range="= aspnetcore-8.0" +This tutorial shows how to create a .NET Core [gRPC](xref:grpc/index) client and an ASP.NET Core gRPC Server. At the end, you'll have a gRPC client that communicates with the gRPC Greeter service. + +In this tutorial, you: + +> [!div class="checklist"] +> * Create a gRPC Server. +> * Create a gRPC client. +> * Test the gRPC client with the gRPC Greeter service. + +## Prerequisites + +# [Visual Studio](#tab/visual-studio) + +[!INCLUDE[](~/includes/net-prereqs-vs-8.0.md)] + +# [Visual Studio Code](#tab/visual-studio-code) + +[!INCLUDE[](~/includes/net-prereqs-vsc-8.0.md)] + +# [Visual Studio for Mac](#tab/visual-studio-mac) + +[!INCLUDE[](~/includes/net-prereqs-mac-8.0.md)] + +--- + +## Create a gRPC service + +# [Visual Studio](#tab/visual-studio) + +* Start Visual Studio 2022 and select **New Project**. +* In the **Create a new project** dialog, search for `gRPC`. Select **ASP.NET Core gRPC Service** and select **Next**. +* In the **Configure your new project** dialog, enter `GrpcGreeter` for **Project name**. It's important to name the project *GrpcGreeter* so the namespaces match when you copy and paste code. +* Select **Next**. +* In the **Additional information** dialog, select **.NET 8.0 (Long Term Support)** and then select **Create**. + +# [Visual Studio Code](#tab/visual-studio-code) + +The tutorial assumes familiarity with VS Code. For more information, see [Getting started with VS Code](https://code.visualstudio.com/docs). + +* Select **New Terminal** from the **Terminal** menu to open the [integrated terminal](https://code.visualstudio.com/docs/editor/integrated-terminal). +* Change to the directory (`cd`) that will contain the project. +* Run the following commands: + + ```dotnetcli + dotnet new grpc -o GrpcGreeter + code -r GrpcGreeter + ``` + + The `dotnet new` command creates a new gRPC service in the *GrpcGreeter* folder. + + The `code` command opens the *GrpcGreeter* project folder in the current instance of Visual Studio Code. + +[!INCLUDE[](~/includes/vscode-trust-authors-add-assets.md)] + +# [Visual Studio for Mac](#tab/visual-studio-mac) + +* Start Visual Studio 2022 for Mac and select **File** > **New Project**. +* In the **Choose a template for your new project** dialog, select **Web and Console** > **App** > **gRPC Service** and select **Continue**. +* Select **.NET 8.0** for the target framework and select **Continue**. +* Name the project **GrpcGreeter**. It's important to name the project *GrpcGreeter* so the namespaces match when you copy and paste code. +* Select **Continue**. + +--- + +### Run the service + +[!INCLUDE[](~/includes/run-the-app6.0.md)] + +The logs show the service listening on `https://localhost:`, where `` is the localhost port number randomly assigned when the project is created and set in `Properties/launchSettings.json`. + +```console +info: Microsoft.Hosting.Lifetime[0] + Now listening on: https://localhost: +info: Microsoft.Hosting.Lifetime[0] + Application started. Press Ctrl+C to shut down. +info: Microsoft.Hosting.Lifetime[0] + Hosting environment: Development +``` + +> [!NOTE] +> The gRPC template is configured to use [Transport Layer Security (TLS)](https://tools.ietf.org/html/rfc5246). gRPC clients need to use HTTPS to call the server. The gRPC service localhost port number is randomly assigned when the project is created and set in the *Properties\launchSettings.json* file of the gRPC service project. + +### Examine the project files + +*GrpcGreeter* project files: + +* `Protos/greet.proto`: defines the `Greeter` gRPC and is used to generate the gRPC server assets. For more information, see [Introduction to gRPC](xref:grpc/index). +* `Services` folder: Contains the implementation of the `Greeter` service. +* `appSettings.json`: Contains configuration data such as the protocol used by Kestrel. For more information, see . +* `Program.cs`, which contains: + * The entry point for the gRPC service. For more information, see . + * Code that configures app behavior. For more information, see [App startup](xref:fundamentals/startup). + +## Create the gRPC client in a .NET console app + +# [Visual Studio](#tab/visual-studio) + +* Open a second instance of Visual Studio and select **New Project**. +* In the **Create a new project** dialog, select **Console App**, and select **Next**. +* In the **Project name** text box, enter **GrpcGreeterClient** and select **Next**. +* In the **Additional information** dialog, select **.NET 8.0 (Long Term Support)** and then select **Create**. + +# [Visual Studio Code](#tab/visual-studio-code) + +* Open the [integrated terminal](https://code.visualstudio.com/docs/editor/integrated-terminal). +* Change directories (`cd`) to a folder for the project. +* Run the following commands: + + ```dotnetcli + dotnet new console -o GrpcGreeterClient + code -r GrpcGreeterClient + ``` + +[!INCLUDE[](~/includes/vscode-trust-authors-add-assets.md)] + +# [Visual Studio for Mac](#tab/visual-studio-mac) + +* In Visual Studio 2022 for Mac select **File** > **Add** > **Project...**. +* In the **Choose a template for your new project** dialog, select **Web and Console** > **App** > **Console Application**, and select **Continue**. +* Select **.NET 8.0** for the target framework, and select **Continue**. +* Name the project **GrpcGreeterClient**. It's important to name the project *GrpcGreeterClient* so the namespaces match when you copy and paste code. +* Select **Continue**. + +--- + +### Add required NuGet packages + +The gRPC client project requires the following NuGet packages: + +* [Grpc.Net.Client](https://www.nuget.org/packages/Grpc.Net.Client), which contains the .NET Core client. +* [Google.Protobuf](https://www.nuget.org/packages/Google.Protobuf/), which contains protobuf message APIs for C#. +* [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools/), which contain C# tooling support for protobuf files. The tooling package isn't required at runtime, so the dependency is marked with `PrivateAssets="All"`. + +# [Visual Studio](#tab/visual-studio) + +Install the packages using either the Package Manager Console (PMC) or Manage NuGet Packages. + +#### PMC option to install packages + +* From Visual Studio, select **Tools** > **NuGet Package Manager** > **Package Manager Console** +* From the **Package Manager Console** window, run `cd GrpcGreeterClient` to change directories to the folder containing the `GrpcGreeterClient.csproj` files. +* Run the following commands: + + ```powershell + Install-Package Grpc.Net.Client + Install-Package Google.Protobuf + Install-Package Grpc.Tools + ``` + +#### Manage NuGet Packages option to install packages + +* Right-click the project in **Solution Explorer** > **Manage NuGet Packages**. +* Select the **Browse** tab. +* Enter **Grpc.Net.Client** in the search box. +* Select the **Grpc.Net.Client** package from the **Browse** tab and select **Install**. +* Repeat for `Google.Protobuf` and `Grpc.Tools`. + +# [Visual Studio Code](#tab/visual-studio-code) + +Run the following commands from the **Integrated Terminal**: + +```dotnetcli +dotnet add GrpcGreeterClient.csproj package Grpc.Net.Client +dotnet add GrpcGreeterClient.csproj package Google.Protobuf +dotnet add GrpcGreeterClient.csproj package Grpc.Tools +``` + +# [Visual Studio for Mac](#tab/visual-studio-mac) + +* Right-click **GrpcGreeterClient** project in the **Solution Pad** and select **Manage NuGet Packages**. +* Enter **Grpc.Net.Client** in the search box. +* Select the **Grpc.Net.Client** package from the results pane and select **Add Package**. +* In **Select Projects** select **OK**. +* If the **License Acceptance** dialog appears, select **Accept** if you agree to the license terms. +* Repeat for `Google.Protobuf` and `Grpc.Tools`. + +--- + +### Add greet.proto + +* Create a *Protos* folder in the gRPC client project. +* Copy the *Protos\greet.proto* file from the gRPC Greeter service to the *Protos* folder in the gRPC client project. +* Update the namespace inside the `greet.proto` file to the project's namespace: + + ```json + option csharp_namespace = "GrpcGreeterClient"; + ``` + +* Edit the `GrpcGreeterClient.csproj` project file: + +# [Visual Studio](#tab/visual-studio) + + Right-click the project and select **Edit Project File**. + +# [Visual Studio Code](#tab/visual-studio-code) + + Select the `GrpcGreeterClient.csproj` file. + +# [Visual Studio for Mac](#tab/visual-studio-mac) + + Right-click the project and select **Edit Project File**. + + --- + +* Add an item group with a `` element that refers to the *greet.proto* file: + + ```xml + + + + ``` + +### Create the Greeter client + +* Build the client project to create the types in the `GrpcGreeterClient` namespace. + +> [!NOTE] +> The `GrpcGreeterClient` types are generated automatically by the build process. The tooling package [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools/) generates the following files based on the *greet.proto* file: +> +> * `GrpcGreeterClient\obj\Debug\[TARGET_FRAMEWORK]\Protos\Greet.cs`: The protocol buffer code which populates, serializes and retrieves the request and response message types. +> * `GrpcGreeterClient\obj\Debug\[TARGET_FRAMEWORK]\Protos\GreetGrpc.cs`: Contains the generated client classes. +> +> For more information on the C# assets automatically generated by [Grpc.Tools](https://www.nuget.org/packages/Grpc.Tools/), see [gRPC services with C#: Generated C# assets](xref:grpc/basics#generated-c-assets). + +* Update the gRPC client `Program.cs` file with the following code. + + [!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample8/GrpcGreeterClient/Program.cs?name=snippet2&highlight=6)] + +* In the preceding highlighted code, replace the localhost port number `7042` with the `HTTPS` port number specified in `Properties/launchSettings.json` within the `GrpcGreeter` service project. + +`Program.cs` contains the entry point and logic for the gRPC client. + +The Greeter client is created by: + +* Instantiating a `GrpcChannel` containing the information for creating the connection to the gRPC service. +* Using the `GrpcChannel` to construct the Greeter client: + +[!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample8/GrpcGreeterClient/Program.cs?name=snippet&highlight=1-3)] + +The Greeter client calls the asynchronous `SayHello` method. The result of the `SayHello` call is displayed: + +[!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample8/GrpcGreeterClient/Program.cs?name=snippet&highlight=4-7)] + +## Test the gRPC client with the gRPC Greeter service + +Update the `appsettings.Development.json` file by adding the following highlighted lines: + +[!code-csharp[](~/tutorials/grpc/grpc-start/sample/sample8/GrpcGreeter/appsettings.Development.json?highlight=6-7)] + +# [Visual Studio](#tab/visual-studio) + +* In the Greeter service, press `Ctrl+F5` to start the server without the debugger. +* In the `GrpcGreeterClient` project, press `Ctrl+F5` to start the client without the debugger. + +# [Visual Studio Code](#tab/visual-studio-code) + +* Start the Greeter service. +* Start the client. + +# [Visual Studio for Mac](#tab/visual-studio-mac) + +* Start the Greeter service. +* Start the client. + +--- + +The client sends a greeting to the service with a message containing its name, *GreeterClient*. The service sends the message "Hello GreeterClient" as a response. The "Hello GreeterClient" response is displayed in the command prompt: + +```console +Greeting: Hello GreeterClient +Press any key to exit... +``` + +The gRPC service records the details of the successful call in the logs written to the command prompt: + +```console +info: Microsoft.Hosting.Lifetime[0] + Now listening on: https://localhost: +info: Microsoft.Hosting.Lifetime[0] + Application started. Press Ctrl+C to shut down. +info: Microsoft.Hosting.Lifetime[0] + Hosting environment: Development +info: Microsoft.Hosting.Lifetime[0] + Content root path: C:\GH\aspnet\docs\4\Docs\aspnetcore\tutorials\grpc\grpc-start\sample\GrpcGreeter +info: Microsoft.AspNetCore.Hosting.Diagnostics[1] + Request starting HTTP/2 POST https://localhost:/Greet.Greeter/SayHello application/grpc +info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] + Executing endpoint 'gRPC - /Greet.Greeter/SayHello' +info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] + Executed endpoint 'gRPC - /Greet.Greeter/SayHello' +info: Microsoft.AspNetCore.Hosting.Diagnostics[2] + Request finished in 78.32260000000001ms 200 application/grpc +``` + +> [!NOTE] +> The code in this article requires the ASP.NET Core HTTPS development certificate to secure the gRPC service. If the .NET gRPC client fails with the message `The remote certificate is invalid according to the validation procedure.` or `The SSL connection could not be established.`, the development certificate isn't trusted. To fix this issue, see [Call a gRPC service with an untrusted/invalid certificate](xref:grpc/troubleshoot#call-a-grpc-service-with-an-untrustedinvalid-certificate). + +### Next steps + +* View or download [the completed sample code for this tutorial](https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/tutorials/grpc/grpc-start/sample) ([how to download](xref:index#how-to-download-a-sample)). +* +* +* + +:::moniker-end diff --git a/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/GrpcGreeter.csproj b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/GrpcGreeter.csproj new file mode 100644 index 000000000000..6ae05574958b --- /dev/null +++ b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/GrpcGreeter.csproj @@ -0,0 +1,17 @@ + + + + net9.0 + enable + enable + + + + + + + + + + + diff --git a/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/Program.cs b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/Program.cs new file mode 100644 index 000000000000..d28e71194b21 --- /dev/null +++ b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/Program.cs @@ -0,0 +1,14 @@ +using GrpcGreeter.Services; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +builder.Services.AddGrpc(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +app.MapGrpcService(); +app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909"); + +app.Run(); diff --git a/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/Protos/greet.proto b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/Protos/greet.proto new file mode 100644 index 000000000000..02343fa083fc --- /dev/null +++ b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/Protos/greet.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +option csharp_namespace = "GrpcGreeter"; + +package greet; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply); +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings. +message HelloReply { + string message = 1; +} diff --git a/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/Services/GreeterService.cs b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/Services/GreeterService.cs new file mode 100644 index 000000000000..cd001d4e8b29 --- /dev/null +++ b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/Services/GreeterService.cs @@ -0,0 +1,23 @@ +using Grpc.Core; +using GrpcGreeter; + +namespace GrpcGreeter.Services; + +#region snippet +public class GreeterService : Greeter.GreeterBase +{ + private readonly ILogger _logger; + public GreeterService(ILogger logger) + { + _logger = logger; + } + + public override Task SayHello(HelloRequest request, ServerCallContext context) + { + return Task.FromResult(new HelloReply + { + Message = "Hello " + request.Name + }); + } +} +#endregion diff --git a/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/appsettings.Development.json b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/appsettings.Development.json new file mode 100644 index 000000000000..c1401263e40e --- /dev/null +++ b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/appsettings.Development.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Microsoft.AspNetCore.Hosting": "Information", + "Microsoft.AspNetCore.Routing.EndpointMiddleware": "Information" + } + } +} diff --git a/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/appsettings.json b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/appsettings.json new file mode 100644 index 000000000000..1aef5074f6fa --- /dev/null +++ b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeter/appsettings.json @@ -0,0 +1,14 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "Kestrel": { + "EndpointDefaults": { + "Protocols": "Http2" + } + } +} diff --git a/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeterClient/GrpcGreeterClient.csproj b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeterClient/GrpcGreeterClient.csproj new file mode 100644 index 000000000000..37a5d86af888 --- /dev/null +++ b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeterClient/GrpcGreeterClient.csproj @@ -0,0 +1,22 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + diff --git a/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeterClient/Program.cs b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeterClient/Program.cs new file mode 100644 index 000000000000..fa564594aaf2 --- /dev/null +++ b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeterClient/Program.cs @@ -0,0 +1,15 @@ +#region snippet2 +using Grpc.Net.Client; +using GrpcGreeterClient; + +#region snippet +// The port number must match the port of the gRPC server. +using var channel = GrpcChannel.ForAddress("https://localhost:7042"); +var client = new Greeter.GreeterClient(channel); +var reply = await client.SayHelloAsync( + new HelloRequest { Name = "GreeterClient" }); +Console.WriteLine("Greeting: " + reply.Message); +Console.WriteLine("Press any key to exit..."); +Console.ReadKey(); +#endregion +#endregion \ No newline at end of file diff --git a/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeterClient/Protos/greet.proto b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeterClient/Protos/greet.proto new file mode 100644 index 000000000000..1a015952296c --- /dev/null +++ b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/GrpcGreeterClient/Protos/greet.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +option csharp_namespace = "GrpcGreeterClient"; + +package greet; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply); +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings. +message HelloReply { + string message = 1; +} diff --git a/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/readme.md b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/readme.md new file mode 100644 index 000000000000..88379a8e4efc --- /dev/null +++ b/aspnetcore/tutorials/grpc/grpc-start/sample/sample9/readme.md @@ -0,0 +1,23 @@ +--- +page_type: sample +description: "Sample projects for a gRPC Service and gRPC client on ASP.NET Core." +languages: +- csharp +products: +- dotnet-core +- aspnet-core +- vs +urlFragment: create-grpc-client +--- + +# Create a gRPC client and server in ASP.NET Core 9 + +This sample demonstrates a .NET Core [gRPC](https://grpc.io/docs/guides/) client and an ASP.NET Core gRPC Server. + +For a tutorial on this sample see [Tutorial: Create a gRPC client and server in ASP.NET Core](https://learn.microsoft.com/aspnet/core/tutorials/grpc/grpc-start?view=aspnetcore-9.0) + +### Docs help & next steps for gRPC + +* [Introduction to gRPC on ASP.NET Core](https://learn.microsoft.com/aspnet/core/grpc/) +* [gRPC services with C#](https://learn.microsoft.com/aspnet/core/grpc/basics/) +* [Migrating gRPC services from C-core to ASP.NET Core](https://learn.microsoft.com/aspnet/core/grpc/migration/) diff --git a/aspnetcore/zone-pivot-groups.yml b/aspnetcore/zone-pivot-groups.yml index 622721bdd92c..4ae76f47e7ef 100644 --- a/aspnetcore/zone-pivot-groups.yml +++ b/aspnetcore/zone-pivot-groups.yml @@ -85,9 +85,11 @@ groups: prompt: Choose the app specification pivots: - id: without-bff-pattern - title: OIDC without BFF pattern + title: OIDC without BFF pattern (Auto) + - id: without-bff-pattern-server + title: OIDC without BFF pattern (Server) - id: with-bff-pattern - title: OIDC with BFF pattern + title: OIDC with BFF pattern (Auto) - id: tooling title: Tooling prompt: Select your tooling