From ec6a69273170fccb5b629d3e41561bfde9c82821 Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Fri, 30 Jun 2023 07:45:44 -0400 Subject: [PATCH 1/2] Remove instruction numbering (#29677) --- aspnetcore/blazor/project-structure.md | 10 +- .../blazor/tutorials/build-a-blazor-app.md | 224 +++++++++--------- 2 files changed, 121 insertions(+), 113 deletions(-) diff --git a/aspnetcore/blazor/project-structure.md b/aspnetcore/blazor/project-structure.md index 135e085f0bd1..64c002927b21 100644 --- a/aspnetcore/blazor/project-structure.md +++ b/aspnetcore/blazor/project-structure.md @@ -45,7 +45,15 @@ Project structure: * `appsettings.json` and environmental app settings files: Provide [configuration settings](xref:blazor/fundamentals/configuration) for the app. -* `Program.cs`/`Program.Server.cs`/`Program.Browser.cs`: The app's entry point that sets up the ASP.NET Core [host](xref:fundamentals/host/generic-host) and contains the app's startup logic, including service registrations and request processing pipeline configuration. If a Blazor Web App app is created only for Blazor Server hosting, a single file named `Program.cs` is created by the Blazor project template. If a Blazor Web App is created for both Blazor Server and Blazor WebAssembly hosting, two files are created. `Program.Server.cs` is for server-side execution by the server-side .NET runtime, and `Program.Browser.cs` is created for client-side execution by the client-side .NET runtime based on WebAssembly. +* `Program.cs`/`Program.Server.cs`/`Program.Browser.cs`: The app's entry point that sets up the ASP.NET Core web application or WebAssembly [host](xref:fundamentals/host/generic-host#host-definition) and contains the app's startup logic, including service registrations, configuration, logging, and request processing pipeline. + + If a Blazor Web App app is only created for Blazor Server hosting, a single file named `Program.cs` is created by the Blazor project template. If a Blazor Web App is created for both Blazor Server and Blazor WebAssembly hosting, two files are created: + + * `Program.Server.cs` is created for server-side execution by the server-side .NET runtime. + * `Program.Browser.cs` is created for client-side execution by the client-side .NET runtime based on WebAssembly. + + A `Program` file: + * Specifies the app's [dependency injection (DI)](xref:fundamentals/dependency-injection) services. Services for Razor components are added by calling `AddRazorComponents`. For Blazor Server hosting, `AddServerComponents` adds services to support rendering interactive server components, and `AddWebAssemblyComponents` adds services to support rendering interactive WebAssembly components. * Configures the app's request handling pipeline. For Blazor Server hosting, `MapRazorComponents` discovers available components and specifies the root component for the app, which by default is the `App` component (`App.razor`). diff --git a/aspnetcore/blazor/tutorials/build-a-blazor-app.md b/aspnetcore/blazor/tutorials/build-a-blazor-app.md index 1e5dc7d969b6..af416f1a9d8d 100644 --- a/aspnetcore/blazor/tutorials/build-a-blazor-app.md +++ b/aspnetcore/blazor/tutorials/build-a-blazor-app.md @@ -73,380 +73,380 @@ cd TodoList ## Build a todo list Blazor app -1. Add a new `Todo` Razor component to the app using the following command: +Add a new `Todo` Razor component to the app using the following command: - ```dotnetcli - dotnet new razorcomponent -n Todo -o Pages - ``` +```dotnetcli +dotnet new razorcomponent -n Todo -o Pages +``` - The `-n|--name` option in the preceding command specifies the name of the new Razor component. The new component is created in the project's `Pages` folder with the `-o|--output` option. +The `-n|--name` option in the preceding command specifies the name of the new Razor component. The new component is created in the project's `Pages` folder with the `-o|--output` option. - > [!IMPORTANT] - > Razor component file names require a capitalized first letter. Open the `Pages` folder and confirm that the `Todo` component file name starts with a capital letter `T`. The file name should be `Todo.razor`. +> [!IMPORTANT] +> Razor component file names require a capitalized first letter. Open the `Pages` folder and confirm that the `Todo` component file name starts with a capital letter `T`. The file name should be `Todo.razor`. :::moniker range=">= aspnetcore-8.0" -1. Open the `Todo` component in any file editor and make the following changes at the top of the file: +Open the `Todo` component in any file editor and make the following changes at the top of the file: - * Add an `@page` Razor directive with a relative URL of `/todo`. - * Add the `@rendermode` Razor directive set to `Auto`. The directive indicates that for this component the render mode should be determined automatically based on a policy. The default render mode for a Blazor Web App is server-side rendering (SSR), which means that the `Todo` component is rendered interactively on the server via Blazor Server hosting with server-side prerendering. - * Add a page title with the `PageTitle` component, which enables adding an HTML `` element to the page. +* Add an `@page` Razor directive with a relative URL of `/todo`. +* Add the `@rendermode` Razor directive set to `Auto`. The directive indicates that for this component the render mode should be determined automatically based on a policy. The default render mode for a Blazor Web App is server-side rendering (SSR), which means that the `Todo` component is rendered interactively on the server via Blazor Server hosting with server-side prerendering. +* Add a page title with the `PageTitle` component, which enables adding an HTML `<title>` element to the page. :::moniker-end :::moniker range=">= aspnetcore-6.0 < aspnetcore-8.0" -1. Open the `Todo` component in any file editor and make the following changes at the top of the file: +Open the `Todo` component in any file editor and make the following changes at the top of the file: - * Add an `@page` Razor directive with a relative URL of `/todo`. - * Add a page title with the `PageTitle` component, which enables adding an HTML `<title>` element to the page. +* Add an `@page` Razor directive with a relative URL of `/todo`. +* Add a page title with the `PageTitle` component, which enables adding an HTML `<title>` element to the page. :::moniker-end :::moniker range="< aspnetcore-6.0" -1. Open the `Todo` component in any file editor and add an `@page` Razor directive with a relative URL of `/todo`. +Open the `Todo` component in any file editor and add an `@page` Razor directive with a relative URL of `/todo`. :::moniker-end - `Pages/Todo.razor`: +`Pages/Todo.razor`: :::moniker range=">= aspnetcore-8.0" - :::code language="razor" source="build-a-blazor-app/8.0/Todo0.razor" highlight="1"::: +:::code language="razor" source="build-a-blazor-app/8.0/Todo0.razor" highlight="1"::: :::moniker-end :::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" - :::code language="razor" source="build-a-blazor-app/7.0/Todo0.razor" highlight="1"::: +:::code language="razor" source="build-a-blazor-app/7.0/Todo0.razor" highlight="1"::: :::moniker-end :::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - :::code language="razor" source="build-a-blazor-app/6.0/Todo0.razor" highlight="1"::: +:::code language="razor" source="build-a-blazor-app/6.0/Todo0.razor" highlight="1"::: :::moniker-end :::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - :::code language="razor" source="build-a-blazor-app/5.0/Todo0.razor" highlight="1"::: +:::code language="razor" source="build-a-blazor-app/5.0/Todo0.razor" highlight="1"::: :::moniker-end :::moniker range="< aspnetcore-5.0" - :::code language="razor" source="build-a-blazor-app/3.1/Todo0.razor" highlight="1"::: +:::code language="razor" source="build-a-blazor-app/3.1/Todo0.razor" highlight="1"::: :::moniker-end - Save the `Pages/Todo.razor` file. +Save the `Pages/Todo.razor` file. -1. Add the `Todo` component to the navigation bar. +Add the `Todo` component to the navigation bar. - The `NavMenu` component is used in the app's layout. Layouts are components that allow you to avoid duplication of content in an app. The `NavLink` component provides a cue in the app's UI when the component URL is loaded by the app. +The `NavMenu` component is used in the app's layout. Layouts are components that allow you to avoid duplication of content in an app. The `NavLink` component provides a cue in the app's UI when the component URL is loaded by the app. - In the navigation element (`<nav>`) content of the `NavMenu` component, add the following `<div>` element for the `Todo` component. +In the navigation element (`<nav>`) content of the `NavMenu` component, add the following `<div>` element for the `Todo` component. - In `Shared/NavMenu.razor`: +In `Shared/NavMenu.razor`: :::moniker range=">= aspnetcore-8.0" - :::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Shared/build-a-blazor-app/NavMenu.razor"::: +:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Shared/build-a-blazor-app/NavMenu.razor"::: :::moniker-end :::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" - :::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Shared/build-a-blazor-app/NavMenu.razor"::: +:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Shared/build-a-blazor-app/NavMenu.razor"::: :::moniker-end :::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - :::code language="razor" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/Shared/build-a-blazor-app/NavMenu.razor"::: +:::code language="razor" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/Shared/build-a-blazor-app/NavMenu.razor"::: :::moniker-end :::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - :::code language="razor" source="~/../blazor-samples/5.0/BlazorSample_WebAssembly/Shared/build-a-blazor-app/NavMenu.razor"::: +:::code language="razor" source="~/../blazor-samples/5.0/BlazorSample_WebAssembly/Shared/build-a-blazor-app/NavMenu.razor"::: :::moniker-end :::moniker range="< aspnetcore-5.0" - :::code language="razor" source="~/../blazor-samples/3.1/BlazorSample_WebAssembly/Shared/build-a-blazor-app/NavMenu.razor"::: +:::code language="razor" source="~/../blazor-samples/3.1/BlazorSample_WebAssembly/Shared/build-a-blazor-app/NavMenu.razor"::: :::moniker-end - Save the `Shared/NavMenu.razor` file. +Save the `Shared/NavMenu.razor` file. -1. Build and run the app by executing the [`dotnet watch run`](xref:tutorials/dotnet-watch) command in the command shell from the `TodoList` folder. After the app is running, visit the new Todo page by selecting the **`Todo`** link in the app's navigation bar, which loads the page at `/todo`. +Build and run the app by executing the [`dotnet watch run`](xref:tutorials/dotnet-watch) command in the command shell from the `TodoList` folder. After the app is running, visit the new Todo page by selecting the **`Todo`** link in the app's navigation bar, which loads the page at `/todo`. - Leave the app running the command shell. Each time a file is saved, the app is automatically rebuilt, and the page in the browser is automatically reloaded. +Leave the app running the command shell. Each time a file is saved, the app is automatically rebuilt, and the page in the browser is automatically reloaded. -1. Add a `TodoItem.cs` file to the root of the project (the `TodoList` folder) to hold a class that represents a todo item. Use the following C# code for the `TodoItem` class. +Add a `TodoItem.cs` file to the root of the project (the `TodoList` folder) to hold a class that represents a todo item. Use the following C# code for the `TodoItem` class. - `TodoItem.cs`: +`TodoItem.cs`: :::moniker range=">= aspnetcore-8.0" - :::code language="csharp" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/build-a-blazor-app/TodoItem.cs"::: +:::code language="csharp" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/build-a-blazor-app/TodoItem.cs"::: :::moniker-end :::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" - :::code language="csharp" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/build-a-blazor-app/TodoItem.cs"::: +:::code language="csharp" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/build-a-blazor-app/TodoItem.cs"::: :::moniker-end :::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - :::code language="csharp" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/build-a-blazor-app/TodoItem.cs"::: +:::code language="csharp" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/build-a-blazor-app/TodoItem.cs"::: :::moniker-end :::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - :::code language="csharp" source="~/../blazor-samples/5.0/BlazorSample_WebAssembly/build-a-blazor-app/TodoItem.cs"::: +:::code language="csharp" source="~/../blazor-samples/5.0/BlazorSample_WebAssembly/build-a-blazor-app/TodoItem.cs"::: :::moniker-end :::moniker range="< aspnetcore-5.0" - :::code language="csharp" source="~/../blazor-samples/3.1/BlazorSample_WebAssembly/build-a-blazor-app/TodoItem.cs"::: +:::code language="csharp" source="~/../blazor-samples/3.1/BlazorSample_WebAssembly/build-a-blazor-app/TodoItem.cs"::: :::moniker-end - > [!NOTE] - > If using Visual Studio to create the `TodoItem.cs` file and `TodoItem` class, use ***either*** of the following approaches: - > - > * Remove the namespace that Visual Studio generates for the class. - > * Use the **Copy** button in the preceding code block and replace the entire contents of the file that Visual Studio generates. +> [!NOTE] +> If using Visual Studio to create the `TodoItem.cs` file and `TodoItem` class, use ***either*** of the following approaches: +> +> * Remove the namespace that Visual Studio generates for the class. +> * Use the **Copy** button in the preceding code block and replace the entire contents of the file that Visual Studio generates. -1. Return to the `Todo` component and perform the following tasks: +Return to the `Todo` component and perform the following tasks: - * Add a field for the todo items in the `@code` block. The `Todo` component uses this field to maintain the state of the todo list. - * Add unordered list markup and a `foreach` loop to render each todo item as a list item (`<li>`). +* Add a field for the todo items in the `@code` block. The `Todo` component uses this field to maintain the state of the todo list. +* Add unordered list markup and a `foreach` loop to render each todo item as a list item (`<li>`). - `Pages/Todo.razor`: +`Pages/Todo.razor`: :::moniker range=">= aspnetcore-8.0" - :::code language="razor" source="build-a-blazor-app/8.0/Todo2.razor" highlight="7-12,15"::: +:::code language="razor" source="build-a-blazor-app/8.0/Todo2.razor" highlight="7-12,15"::: :::moniker-end :::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" - :::code language="razor" source="build-a-blazor-app/7.0/Todo2.razor" highlight="7-12,15"::: +:::code language="razor" source="build-a-blazor-app/7.0/Todo2.razor" highlight="7-12,15"::: :::moniker-end :::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - :::code language="razor" source="build-a-blazor-app/6.0/Todo2.razor" highlight="7-12,15"::: +:::code language="razor" source="build-a-blazor-app/6.0/Todo2.razor" highlight="7-12,15"::: :::moniker-end :::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - :::code language="razor" source="build-a-blazor-app/5.0/Todo2.razor" highlight="7-12,15"::: +:::code language="razor" source="build-a-blazor-app/5.0/Todo2.razor" highlight="7-12,15"::: :::moniker-end :::moniker range="< aspnetcore-5.0" - :::code language="razor" source="build-a-blazor-app/3.1/Todo2.razor" highlight="7-12,15"::: +:::code language="razor" source="build-a-blazor-app/3.1/Todo2.razor" highlight="7-12,15"::: :::moniker-end -1. The app requires UI elements for adding todo items to the list. Add a text input (`<input>`) and a button (`<button>`) below the unordered list (`<ul>...</ul>`): +The app requires UI elements for adding todo items to the list. Add a text input (`<input>`) and a button (`<button>`) below the unordered list (`<ul>...</ul>`): :::moniker range=">= aspnetcore-8.0" - :::code language="razor" source="build-a-blazor-app/8.0/Todo3.razor" highlight="14-15"::: +:::code language="razor" source="build-a-blazor-app/8.0/Todo3.razor" highlight="14-15"::: :::moniker-end :::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" - :::code language="razor" source="build-a-blazor-app/7.0/Todo3.razor" highlight="14-15"::: +:::code language="razor" source="build-a-blazor-app/7.0/Todo3.razor" highlight="14-15"::: :::moniker-end :::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - :::code language="razor" source="build-a-blazor-app/6.0/Todo3.razor" highlight="14-15"::: +:::code language="razor" source="build-a-blazor-app/6.0/Todo3.razor" highlight="14-15"::: :::moniker-end :::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - :::code language="razor" source="build-a-blazor-app/5.0/Todo3.razor" highlight="14-15"::: +:::code language="razor" source="build-a-blazor-app/5.0/Todo3.razor" highlight="14-15"::: :::moniker-end :::moniker range="< aspnetcore-5.0" - :::code language="razor" source="build-a-blazor-app/3.1/Todo3.razor" highlight="14-15"::: +:::code language="razor" source="build-a-blazor-app/3.1/Todo3.razor" highlight="14-15"::: :::moniker-end -1. Save the `TodoItem.cs` file and the updated `Pages/Todo.razor` file. In the command shell, the app is automatically rebuilt when the files are saved. The browser reloads the page. +Save the `TodoItem.cs` file and the updated `Pages/Todo.razor` file. In the command shell, the app is automatically rebuilt when the files are saved. The browser reloads the page. -1. When the **`Add todo`** button is selected, nothing happens because an event handler isn't attached to the button. +When the **`Add todo`** button is selected, nothing happens because an event handler isn't attached to the button. -1. Add an `AddTodo` method to the `Todo` component and register the method for the button using the `@onclick` attribute. The `AddTodo` C# method is called when the button is selected: +Add an `AddTodo` method to the `Todo` component and register the method for the button using the `@onclick` attribute. The `AddTodo` C# method is called when the button is selected: :::moniker range=">= aspnetcore-8.0" - :::code language="razor" source="build-a-blazor-app/8.0/Todo4.razor" highlight="2,7-10"::: +:::code language="razor" source="build-a-blazor-app/8.0/Todo4.razor" highlight="2,7-10"::: :::moniker-end :::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" - :::code language="razor" source="build-a-blazor-app/7.0/Todo4.razor" highlight="2,7-10"::: +:::code language="razor" source="build-a-blazor-app/7.0/Todo4.razor" highlight="2,7-10"::: :::moniker-end :::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - :::code language="razor" source="build-a-blazor-app/6.0/Todo4.razor" highlight="2,7-10"::: +:::code language="razor" source="build-a-blazor-app/6.0/Todo4.razor" highlight="2,7-10"::: :::moniker-end :::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - :::code language="razor" source="build-a-blazor-app/5.0/Todo4.razor" highlight="2,7-10"::: +:::code language="razor" source="build-a-blazor-app/5.0/Todo4.razor" highlight="2,7-10"::: :::moniker-end :::moniker range="< aspnetcore-5.0" - :::code language="razor" source="build-a-blazor-app/3.1/Todo4.razor" highlight="2,7-10"::: +:::code language="razor" source="build-a-blazor-app/3.1/Todo4.razor" highlight="2,7-10"::: :::moniker-end -1. To get the title of the new todo item, add a `newTodo` string field at the top of the `@code` block: +To get the title of the new todo item, add a `newTodo` string field at the top of the `@code` block: :::moniker range=">= aspnetcore-6.0" - ```csharp - private string? newTodo; - ``` +```csharp +private string? newTodo; +``` :::moniker-end :::moniker range="< aspnetcore-6.0" - ```csharp - private string newTodo; - ``` +```csharp +private string newTodo; +``` :::moniker-end - Modify the text `<input>` element to bind `newTodo` with the `@bind` attribute: +Modify the text `<input>` element to bind `newTodo` with the `@bind` attribute: - ```razor - <input placeholder="Something todo" @bind="newTodo" /> - ``` +```razor +<input placeholder="Something todo" @bind="newTodo" /> +``` -1. Update the `AddTodo` method to add the `TodoItem` with the specified title to the list. Clear the value of the text input by setting `newTodo` to an empty string: +Update the `AddTodo` method to add the `TodoItem` with the specified title to the list. Clear the value of the text input by setting `newTodo` to an empty string: :::moniker range=">= aspnetcore-8.0" - :::code language="razor" source="build-a-blazor-app/8.0/Todo6.razor" highlight="21-28"::: +:::code language="razor" source="build-a-blazor-app/8.0/Todo6.razor" highlight="21-28"::: :::moniker-end :::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" - :::code language="razor" source="build-a-blazor-app/7.0/Todo6.razor" highlight="21-28"::: +:::code language="razor" source="build-a-blazor-app/7.0/Todo6.razor" highlight="21-28"::: :::moniker-end :::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - :::code language="razor" source="build-a-blazor-app/6.0/Todo6.razor" highlight="21-28"::: +:::code language="razor" source="build-a-blazor-app/6.0/Todo6.razor" highlight="21-28"::: :::moniker-end :::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - :::code language="razor" source="build-a-blazor-app/5.0/Todo6.razor" highlight="21-28"::: +:::code language="razor" source="build-a-blazor-app/5.0/Todo6.razor" highlight="21-28"::: :::moniker-end :::moniker range="< aspnetcore-5.0" - :::code language="razor" source="build-a-blazor-app/3.1/Todo6.razor" highlight="21-28"::: +:::code language="razor" source="build-a-blazor-app/3.1/Todo6.razor" highlight="21-28"::: :::moniker-end -1. Save the `Pages/Todo.razor` file. The app is automatically rebuilt in the command shell, and the page reloads in the browser. +Save the `Pages/Todo.razor` file. The app is automatically rebuilt in the command shell, and the page reloads in the browser. -1. The title text for each todo item can be made editable, and a checkbox can help the user keep track of completed items. Add a checkbox input for each todo item and bind its value to the `IsDone` property. Change `@todo.Title` to an `<input>` element bound to `todo.Title` with `@bind`: +The title text for each todo item can be made editable, and a checkbox can help the user keep track of completed items. Add a checkbox input for each todo item and bind its value to the `IsDone` property. Change `@todo.Title` to an `<input>` element bound to `todo.Title` with `@bind`: - ```razor - <ul> - @foreach (var todo in todos) - { - <li> - <input type="checkbox" @bind="todo.IsDone" /> - <input @bind="todo.Title" /> - </li> - } - </ul> - ``` +```razor +<ul> + @foreach (var todo in todos) + { + <li> + <input type="checkbox" @bind="todo.IsDone" /> + <input @bind="todo.Title" /> + </li> + } +</ul> +``` -1. Update the `<h1>` header to show a count of the number of todo items that aren't complete (`IsDone` is `false`). The Razor expression in the following header evaluates each time Blazor rerenders the component. +Update the `<h1>` header to show a count of the number of todo items that aren't complete (`IsDone` is `false`). The Razor expression in the following header evaluates each time Blazor rerenders the component. - ```razor - <h1>Todo (@todos.Count(todo => !todo.IsDone))</h1> - ``` +```razor +<h1>Todo (@todos.Count(todo => !todo.IsDone))</h1> +``` -1. The completed `Todo` component (`Pages/Todo.razor`): +The completed `Todo` component (`Pages/Todo.razor`): :::moniker range=">= aspnetcore-8.0" - :::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/build-a-blazor-app/Todo.razor"::: +:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/build-a-blazor-app/Todo.razor"::: :::moniker-end :::moniker range=">= aspnetcore-7.0 < aspnetcore-8.0" - :::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/build-a-blazor-app/Todo.razor"::: +:::code language="razor" source="~/../blazor-samples/7.0/BlazorSample_WebAssembly/Pages/build-a-blazor-app/Todo.razor"::: :::moniker-end :::moniker range=">= aspnetcore-6.0 < aspnetcore-7.0" - :::code language="razor" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/Pages/build-a-blazor-app/Todo.razor"::: +:::code language="razor" source="~/../blazor-samples/6.0/BlazorSample_WebAssembly/Pages/build-a-blazor-app/Todo.razor"::: :::moniker-end :::moniker range=">= aspnetcore-5.0 < aspnetcore-6.0" - :::code language="razor" source="~/../blazor-samples/5.0/BlazorSample_WebAssembly/Pages/build-a-blazor-app/Todo.razor"::: +:::code language="razor" source="~/../blazor-samples/5.0/BlazorSample_WebAssembly/Pages/build-a-blazor-app/Todo.razor"::: :::moniker-end :::moniker range="< aspnetcore-5.0" - :::code language="razor" source="~/../blazor-samples/3.1/BlazorSample_WebAssembly/Pages/build-a-blazor-app/Todo.razor"::: +:::code language="razor" source="~/../blazor-samples/3.1/BlazorSample_WebAssembly/Pages/build-a-blazor-app/Todo.razor"::: :::moniker-end -1. Save the `Pages/Todo.razor` file. The app is automatically rebuilt in the command shell, and the page reloads in the browser. +Save the `Pages/Todo.razor` file. The app is automatically rebuilt in the command shell, and the page reloads in the browser. -1. Add items, edit items, and mark todo items done to test the component. +Add items, edit items, and mark todo items done to test the component. -1. When finished, shut down the app in the command shell. Many command shells accept the keyboard command <kbd>Ctrl</kbd>+<kbd>C</kbd> (Windows) or <kbd>⌘</kbd>+<kbd>C</kbd> (macOS) to stop an app. +When finished, shut down the app in the command shell. Many command shells accept the keyboard command <kbd>Ctrl</kbd>+<kbd>C</kbd> (Windows) or <kbd>⌘</kbd>+<kbd>C</kbd> (macOS) to stop an app. ## Publish to Azure From a2626c632bb3b53cc6d901cebc3379f25b3f0c28 Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Fri, 30 Jun 2023 10:11:11 -0400 Subject: [PATCH 2/2] Blazor SignalR tutorial for .NET 8 (#29681) --- aspnetcore/blazor/tooling.md | 4 +- .../blazor/tutorials/build-a-blazor-app.md | 10 + .../tutorials/signalr-blazor-preview.md | 454 ++++++++++++++++++ aspnetcore/blazor/tutorials/signalr-blazor.md | 9 +- aspnetcore/toc.yml | 2 + 5 files changed, 470 insertions(+), 9 deletions(-) create mode 100644 aspnetcore/blazor/tutorials/signalr-blazor-preview.md diff --git a/aspnetcore/blazor/tooling.md b/aspnetcore/blazor/tooling.md index 3f215925d4e0..4f95245f1d3b 100644 --- a/aspnetcore/blazor/tooling.md +++ b/aspnetcore/blazor/tooling.md @@ -475,7 +475,7 @@ To create a Blazor app on macOS, use the following guidance: > [!NOTE] > Visual Studio for Mac will be able to create Blazor Web Apps in an upcoming release. -<!-- HOLD FOR 8.0 UPDATE TO USE VS UI +<!-- UPDATE FOR 8.0 In the sidebar, select **Web and Console** > **App**. @@ -599,7 +599,7 @@ For more information on template options, see the following resources: :::moniker range=">= aspnetcore-8.0" -<!-- HOLD FOR 8.0 +<!-- UPDATE FOR 8.0 * [`blazor`](/dotnet/core/tools/dotnet-new-sdk-templates#blazor) diff --git a/aspnetcore/blazor/tutorials/build-a-blazor-app.md b/aspnetcore/blazor/tutorials/build-a-blazor-app.md index af416f1a9d8d..9f7f75b05e2a 100644 --- a/aspnetcore/blazor/tutorials/build-a-blazor-app.md +++ b/aspnetcore/blazor/tutorials/build-a-blazor-app.md @@ -33,8 +33,18 @@ At the end of this tutorial, you'll have a working todo list app. ## Prerequisites +:::moniker range=">= aspnetcore-8.0" + +[Download and install the .NET 8.0 Preview](https://dotnet.microsoft.com/download/dotnet/8.0) + +:::moniker-end + +:::moniker range="< aspnetcore-8.0" + [Download and install .NET](https://dotnet.microsoft.com/download/dotnet) if it isn't already installed on the system or if the system doesn't have the latest version installed. +:::moniker-end + ## Create a Blazor app :::moniker range=">= aspnetcore-8.0" diff --git a/aspnetcore/blazor/tutorials/signalr-blazor-preview.md b/aspnetcore/blazor/tutorials/signalr-blazor-preview.md new file mode 100644 index 000000000000..f9c38da0eb3d --- /dev/null +++ b/aspnetcore/blazor/tutorials/signalr-blazor-preview.md @@ -0,0 +1,454 @@ +--- +title: Use ASP.NET Core SignalR with Blazor (.NET 8 Preview) +author: guardrex +description: Create a chat app that uses ASP.NET Core SignalR with Blazor. +monikerRange: '>= aspnetcore-8.0' +ms.author: riande +ms.custom: mvc +ms.date: 06/30/2023 +uid: blazor/tutorials/signalr-blazor-preview +--- +# Use ASP.NET Core SignalR with Blazor (.NET 8 Preview) + +<!-- UPDATE FOR 8.0 + +[!INCLUDE[](~/includes/not-latest-version.md)] + +--> + +This tutorial provides a basic working experience for building a real-time app using SignalR with Blazor. For detailed Blazor guidance, see the [Blazor reference documentation](xref:blazor/index). + +> [!IMPORTANT] +> This is the .NET 8 preview version of this article, which is currently undergoing updates for .NET 8. Some of the features described might not be available or fully working at this time. The work on this article will be completed when .NET 8 reaches the *Release Candidate* stage, which is currently scheduled for September. For the current release, see the [.NET 7 version of this article](xref:blazor/tutorials/signalr-blazor?view=aspnetcore-7.0&preserve-view=true). + +Learn how to: + +> [!div class="checklist"] +> * Create a Blazor project +> * Add the SignalR client library +> * Add a SignalR hub +> * Add SignalR services and an endpoint for the SignalR hub +> * Add Razor component code for chat + +At the end of this tutorial, you'll have a working chat app. + +<!-- UPDATE FOR 8.0 + +## Prerequisites + +# [Visual Studio](#tab/visual-studio) + +[Visual Studio 2022 or later](https://visualstudio.microsoft.com/downloads/?utm_medium=microsoft&utm_source=learn.microsoft.com&utm_campaign=inline+link&utm_content=download+vs2022) with the **ASP.NET and web development** workload + +# [Visual Studio Code](#tab/visual-studio-code) + +* [Visual Studio Code](https://code.visualstudio.com/download) +* [C# for Visual Studio Code (latest version)](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) +* [Download and install .NET](https://dotnet.microsoft.com/download/dotnet) if it isn't already installed on the system or if the system doesn't have the latest version installed. + +The Visual Studio Code instructions use the .NET CLI for ASP.NET Core development functions such as project creation. You can follow these instructions on macOS, Linux, or Windows and with any code editor. Minor changes may be required if you use something other than Visual Studio Code. + +# [Visual Studio for Mac](#tab/visual-studio-mac) + +[Visual Studio for Mac 2022 or later](https://visualstudio.microsoft.com/vs/mac/) with the **.NET** workload + +# [.NET Core CLI](#tab/netcore-cli/) + +[Download and install .NET](https://dotnet.microsoft.com/download/dotnet) if it isn't already installed on the system or if the system doesn't have the latest version installed. + +--- + +--> + +## Prerequisites + +# [Visual Studio](#tab/visual-studio) + +[Visual Studio 2022 Preview](https://visualstudio.microsoft.com/vs/preview/) with the **ASP.NET and web development** workload + +# [Visual Studio Code](#tab/visual-studio-code) + +* [Visual Studio Code](https://code.visualstudio.com/download) +* [C# for Visual Studio Code (latest version)](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) +* [.NET 8.0 Preview](https://dotnet.microsoft.com/download/dotnet/8.0) if it isn't already installed on the system or if the system doesn't have the latest version installed. + +The Visual Studio Code instructions use the .NET CLI for ASP.NET Core development functions such as project creation. You can follow these instructions on macOS, Linux, or Windows and with any code editor. Minor changes may be required if you use something other than Visual Studio Code. + +# [Visual Studio for Mac](#tab/visual-studio-mac) + +[Visual Studio for Mac 2022 Preview](https://visualstudio.microsoft.com/vs/mac/preview/) with the **.NET** workload + +# [.NET Core CLI](#tab/netcore-cli/) + +[.NET 8.0 Preview](https://dotnet.microsoft.com/download/dotnet/8.0) + +--- + +<!-- UPDATE FOR 8.0 + +## Sample app + +Downloading the tutorial's sample chat app isn't required for this tutorial. The sample app is the final, working app produced by following the steps of this tutorial. + +[View or download sample code](https://github.com/dotnet/blazor-samples) + +--> + +## Create a Blazor Web App + +Follow the guidance for your choice of tooling: + +# [Visual Studio](#tab/visual-studio) + +> [!NOTE] +> Visual Studio 2022 or later and .NET Core SDK 8.0.0 or later are required. + +Create a new project. + +Select the **Blazor Web App** template. Select **Next**. + +Type `BlazorSignalRApp` in the **Project name** field. Confirm the **Location** entry is correct or provide a location for the project. Select **Next**. + +Confirm the **Framework** is .NET 8.0 or later. Select **Create**. + +# [Visual Studio Code](#tab/visual-studio-code) + +In a command shell, execute the following command: + +```dotnetcli +dotnet new blazor -o BlazorSignalRApp +``` + +The `-o|--output` option creates a folder for the project. If you've created a folder for the project and the command shell is open in that folder, omit the `-o|--output` option and value to create the project. + +In Visual Studio Code, open the app's project folder. + +When the dialog appears to add assets to build and debug the app, select **Yes**. Visual Studio Code automatically adds the `.vscode` folder with generated `launch.json` and `tasks.json` files. For information on configuring VS Code assets in the `.vscode` folder, including how to manually add the files to the [solution](xref:blazor/tooling#visual-studio-solution-file-sln), see the **Linux** operating system guidance in <xref:blazor/tooling?pivot=linux>. + +# [Visual Studio for Mac](#tab/visual-studio-mac) + +Visual Studio for Mac can't create a Blazor Web App in its UI at this time. Open a command shell with Apple's **Terminal** utility application in macOS's `Applications/Utilities` folder. Change the directory to the location where you want to create the app with the [`ls` command](https://man7.org/linux/man-pages/man1/ls.1.html). For example, use the `ls Desktop` command to change the directory to the desktop. Execute the following command in the command shell: + +```dotnetcli +dotnet new blazor -o BlazorApp +``` + +After the app is created, open the project file (`BlazorApp.csproj`) with Visual Studio for Mac. + +> [!NOTE] +> Visual Studio for Mac will be able to create Blazor Web Apps in an upcoming release. + +<!-- UPDATE FOR 8.0 + +Select the **New Project** command from the **File** menu or create a **New** project from the **Start Window**. + +In the sidebar, select **Web and Console** > **App**. + +Choose the **Blazor Web App** template. Select **Continue**. + +Confirm that **Authentication** is set to **No Authentication**. Select **Continue**. + +In the **Project name** field, name the app `BlazorSignalRApp`. Select **Create**. + +If a prompt appears to trust the development certificate, trust the certificate and continue. The user and keychain passwords are required to trust the certificate. + +Open the project by navigating to the project folder and opening the project's solution file (`.sln`). + +--> + +# [.NET Core CLI](#tab/netcore-cli/) + +In a command shell, execute the following command: + +```dotnetcli +dotnet new blazor -o BlazorSignalRApp +``` + +The `-o|--output` option creates a folder for the project. If you've created a folder for the project and the command shell is open in that folder, omit the `-o|--output` option and value to create the project. + +--- + +## Add the SignalR client library + +# [Visual Studio](#tab/visual-studio/) + +In **Solution Explorer**, right-click the `BlazorSignalRApp` project and select **Manage NuGet Packages**. + +In the **Manage NuGet Packages** dialog, confirm that the **Package source** is set to `nuget.org`. + +With **Browse** and **Include prerelease** selected, type `Microsoft.AspNetCore.SignalR.Client` in the search box. + +In the search results, select the latest **preview** [`Microsoft.AspNetCore.SignalR.Client`](https://www.nuget.org/packages/Microsoft.AspNetCore.SignalR.Client) package. <!-- Set the version to match the shared framework of the app. --> Select **Install**. + +If the **Preview Changes** dialog appears, select **OK**. + +If the **License Acceptance** dialog appears, select **I Accept** if you agree with the license terms. + +# [Visual Studio Code](#tab/visual-studio-code/) + +In the **Integrated Terminal** (**View** > **Terminal** from the toolbar), execute the following command: + +```dotnetcli +dotnet add package Microsoft.AspNetCore.SignalR.Client --prerelease +``` + +<!-- UPDATE FOR 8.0 + +To add an earlier version of the package, supply the `--version {VERSION}` option, where the `{VERSION}` placeholder is the version of the package to add. + +--> + +# [Visual Studio for Mac](#tab/visual-studio-mac) + +In the **Solution** sidebar, right-click the `BlazorSignalRApp` project and select **Manage NuGet Packages**. + +In the **Manage NuGet Packages** dialog, confirm that the **Package source** dropdown list is set to `nuget.org`. + +With **Browse** and **Include prerelease** selected, type `Microsoft.AspNetCore.SignalR.Client` in the search box. + +In the search results, select the checkbox next to the latest **preview** [`Microsoft.AspNetCore.SignalR.Client`](https://www.nuget.org/packages/Microsoft.AspNetCore.SignalR.Client) package. <!-- Set the version to match the shared framework of the app. --> Select **Add Package**. + +If the **License Acceptance** dialog appears, select **Accept** if you agree with the license terms. + +# [.NET Core CLI](#tab/netcore-cli/) + +In a command shell from the project's folder, execute the following command: + +```dotnetcli +dotnet add package Microsoft.AspNetCore.SignalR.Client --prerelease +``` + +<!-- UPDATE FOR 8.0 + +To add an earlier version of the package, supply the `--version {VERSION}` option, where the `{VERSION}` placeholder is the version of the package to add. + +--> + +--- + +## Add a SignalR hub + +Create a `Hubs` (plural) folder and add the following `ChatHub` class (`Hubs/ChatHub.cs`): + +```csharp +using Microsoft.AspNetCore.SignalR; + +namespace BlazorSignalRApp.Hubs; + +public class ChatHub : Hub +{ + public async Task SendMessage(string user, string message) + { + await Clients.All.SendAsync("ReceiveMessage", user, message); + } +} +``` + +<!-- UPDATE FOR 8.0 + +## Add services and an endpoint for the SignalR hub + +--> + +## Add Razor component support, services, and an endpoint for the SignalR hub + +Open the `Program.cs` file. + +Add the namespaces for <xref:Microsoft.AspNetCore.ResponseCompression?displayProperty=fullName> and the `ChatHub` class to the top of the file: + +```csharp +using Microsoft.AspNetCore.ResponseCompression; +using BlazorSignalRApp.Hubs; +``` + +<!-- UPDATE FOR 8.0 (REMOVE THE FOLLOWING) --> + +Locate the line that adds services and configuration for Razor components: + +```csharp +builder.Services.AddRazorComponents(); +``` + +Chain a call to `AddServerComponents` to `AddRazorComponents`. Change the line to the following: + +```csharp +builder.Services.AddRazorComponents().AddServerComponents(); +``` + +<!-- UPDATE FOR 8.0 (END OF REMOVAL) --> + +Add Response Compression Middleware services: + +```csharp +builder.Services.AddResponseCompression(opts => +{ + opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat( + new[] { "application/octet-stream" }); +}); +``` + +Use Response Compression Middleware at the top of the processing pipeline's configuration: + +```csharp +app.UseResponseCompression(); +``` + +Add an endpoint for the hub immediately after the line `app.MapRazorComponents<App>();`: + +```csharp +app.MapHub<ChatHub>("/chathub"); +``` + +## Add Razor component code for chat + +Open the `Pages/Index.razor` file. + +Replace the markup with the following code: + +<!-- UPDATE FOR 8.0 + +@rendermode Auto + +--> + +```razor +@page "/" +@attribute [RenderModeServer] +@using Microsoft.AspNetCore.SignalR.Client +@inject NavigationManager Navigation +@implements IAsyncDisposable + +<PageTitle>Index</PageTitle> + +<div class="form-group"> + <label> + User: + <input @bind="userInput" /> + </label> +</div> +<div class="form-group"> + <label> + Message: + <input @bind="messageInput" size="50" /> + </label> +</div> +<button @onclick="Send" disabled="@(!IsConnected)">Send</button> + +<hr> + +<ul id="messagesList"> + @foreach (var message in messages) + { + <li>@message</li> + } +</ul> + +@code { + private HubConnection? hubConnection; + private List<string> messages = new List<string>(); + private string? userInput; + private string? messageInput; + + protected override async Task OnInitializedAsync() + { + hubConnection = new HubConnectionBuilder() + .WithUrl(Navigation.ToAbsoluteUri("/chathub")) + .Build(); + + hubConnection.On<string, string>("ReceiveMessage", (user, message) => + { + var encodedMsg = $"{user}: {message}"; + messages.Add(encodedMsg); + InvokeAsync(StateHasChanged); + }); + + await hubConnection.StartAsync(); + } + + private async Task Send() + { + if (hubConnection is not null) + { + await hubConnection.SendAsync("SendMessage", userInput, messageInput); + } + } + + public bool IsConnected => + hubConnection?.State == HubConnectionState.Connected; + + public async ValueTask DisposeAsync() + { + if (hubConnection is not null) + { + await hubConnection.DisposeAsync(); + } + } +} +``` + +> [!NOTE] +> Disable Response Compression Middleware in the `Development` environment when using [Hot Reload](xref:test/hot-reload). For more information, see <xref:blazor/fundamentals/signalr#disable-response-compression-for-hot-reload>. + +## Run the app + +Follow the guidance for your tooling: + +# [Visual Studio](#tab/visual-studio) + +Press <kbd>F5</kbd> to run the app with debugging or <kbd>Ctrl</kbd>+<kbd>F5</kbd> (Windows)/<kbd>⌘</kbd>+<kbd>F5</kbd> (macOS) to run the app without debugging. + +# [Visual Studio Code](#tab/visual-studio-code) + +Press <kbd>F5</kbd> to run the app with debugging or <kbd>Ctrl</kbd>+<kbd>F5</kbd> (Windows)/<kbd>⌘</kbd>+<kbd>F5</kbd> (macOS) to run the app without debugging. + +# [Visual Studio for Mac](#tab/visual-studio-mac) + +Press <kbd>⌘</kbd>+<kbd>↩</kbd> to run the app with debugging or <kbd>⌥</kbd>+<kbd>⌘</kbd>+<kbd>↩</kbd> to run the app without debugging. + +> [!IMPORTANT] +> Google Chrome or Microsoft Edge must be the selected browser for a debugging session. + +# [.NET Core CLI](#tab/netcore-cli/) + +In a command shell from the project's folder, execute the following commands: + +```dotnetcli +dotnet run +``` + +--- + +Copy the URL from the address bar, open another browser instance or tab, and paste the URL in the address bar. + +Choose either browser, enter a name and message, and select the button to send the message. The name and message are displayed on both pages instantly: + +![SignalR Blazor sample app open in two browser windows showing exchanged messages.](signalr-blazor/_static/signalr-blazor-finished.png) + +Quotes: *Star Trek VI: The Undiscovered Country* ©1991 [Paramount](https://www.paramountmovies.com/movies/star-trek-vi-the-undiscovered-country) + +## Next steps + +In this tutorial, you learned how to: + +> [!div class="checklist"] +> * Create a Blazor project +> * Add the SignalR client library +> * Add a SignalR hub +> * Add SignalR services and an endpoint for the SignalR hub +> * Add Razor component code for chat + +To learn more about building Blazor apps, see the Blazor documentation: + +> [!div class="nextstepaction"] +> <xref:blazor/index> +> [Bearer token authentication with Identity Server, WebSockets, and Server-Sent Events](xref:signalr/authn-and-authz#bearer-token-authentication) + +## Additional resources + +* [Secure a SignalR hub in hosted Blazor WebAssembly apps](xref:blazor/security/webassembly/index#secure-a-signalr-hub) +* <xref:signalr/introduction> +* [SignalR cross-origin negotiation for authentication](xref:blazor/fundamentals/signalr#signalr-cross-origin-negotiation-for-authentication-blazor-webassembly) +* [SignalR configuration](xref:blazor/host-and-deploy/server#signalr-configuration) +* <xref:blazor/debug> +* <xref:blazor/security/server/threat-mitigation> +* [Blazor samples GitHub repository (`dotnet/blazor-samples`)](https://github.com/dotnet/blazor-samples) diff --git a/aspnetcore/blazor/tutorials/signalr-blazor.md b/aspnetcore/blazor/tutorials/signalr-blazor.md index 727402e7d39d..cda7475e5707 100644 --- a/aspnetcore/blazor/tutorials/signalr-blazor.md +++ b/aspnetcore/blazor/tutorials/signalr-blazor.md @@ -30,10 +30,7 @@ At the end of this tutorial, you'll have a working chat app. # [Visual Studio](#tab/visual-studio) -Install either of the following: - -* [Visual Studio 2022 or later](https://visualstudio.microsoft.com/downloads/?utm_medium=microsoft&utm_source=learn.microsoft.com&utm_campaign=inline+link&utm_content=download+vs2022) with the **ASP.NET and web development** workload -* [.NET](https://dotnet.microsoft.com/download/dotnet) if it isn't already installed on the system or if the system doesn't have the latest version installed. +[Visual Studio 2022 or later](https://visualstudio.microsoft.com/downloads/?utm_medium=microsoft&utm_source=learn.microsoft.com&utm_campaign=inline+link&utm_content=download+vs2022) with the **ASP.NET and web development** workload # [Visual Studio Code](#tab/visual-studio-code) @@ -45,7 +42,7 @@ The Visual Studio Code instructions use the .NET CLI for ASP.NET Core developmen # [Visual Studio for Mac](#tab/visual-studio-mac) -[Visual Studio for Mac 2022 or later](https://visualstudio.microsoft.com/vs/mac/) +[Visual Studio for Mac 2022 or later](https://visualstudio.microsoft.com/vs/mac/) with the **.NET** workload # [.NET Core CLI](#tab/netcore-cli/) @@ -105,8 +102,6 @@ To configure Visual Studio Code assets in the `.vscode` folder for debugging, se # [Visual Studio for Mac](#tab/visual-studio-mac) -Install the latest version of [Visual Studio for Mac](https://visualstudio.microsoft.com/vs/mac/). When the installer requests the workloads to install, select **.NET**. - Select the **New Project** command from the **File** menu or create a **New** project from the **Start Window**. In the sidebar, select **Web and Console** > **App**. diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 195a2c7288c4..ff1cc9e6c7db 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -373,6 +373,8 @@ items: uid: blazor/tutorials/build-a-blazor-app - name: SignalR with Blazor uid: blazor/tutorials/signalr-blazor + - name: SignalR with Blazor (.NET 8 Preview) + uid: blazor/tutorials/signalr-blazor-preview - name: Learn modules href: /training/paths/build-web-apps-with-blazor/ - name: Blazor Hybrid