Learn how to use forms in Blazor, add event handlers, and validate the data a user submits. By using Blazor form components, you can validate client-side forms without writing client-side JavaScript to handle the validations.
Learning objectives
By the end of this module, you’re able to:
Improve your app’s interactivity using Blazor event handlers.
Use forms in Blazor to facilitate data entry.
Extend forms in Blazor with server and client-side validation.
Prerequisites
Basic knowledge of web app concepts
C# .NET experience at a beginner level
Local installations of the .NET SDK and Visual Studio Code
Now that the code is configured to generate an OpenAPI document file that describes the web API, VanArsdel’s development team turns their attention to publishing the application.
Seamless development experiences in Visual Studio, from code to deploy
In a fusion development team, time is one of the most valuable assets. You write code and build an app, then use different tools to deploy your app. You come back to the code, update it, and switch to the other tools for deployment. The cost for switching between tools is huge, and eventually it decreases your productivity.
What if your development tool, Visual Studio, can do everything for you in one place? It saves time and increases productivity. Visual Studio offers features to publish your app to Azure App Service.
Visual Studio also offers the feature to integrate your web API with Azure API Management while publishing the app.
In the next couple of exercises, you’ll explore how to publish your web API application to Azure App Service and integrate it using Azure API Management.
Before a web API can be published to with Visual Studio, it should have an OpenAPI description document.
The OpenAPI document is used by API Management to discover the endpoints for the web API. It’s easier than ever for the VanArsdel developers to create an OpenAPI description of their web APIs using the Swashbuckle tooling.
What is OpenAPI and what does it do?
The OpenAPI document defines a standard and programming language-agnostic interface description for web APIs. It allows both humans and computers to discover and understand the capabilities of a service without having access to source code, extra documentation, or inspection of network traffic.
The OpenAPI document is a contract for web APIs. It’s all a consuming application needs to understand and communicate with the web APIs, without having to know where the APIs are located or whether they’re running.
Generate an OpenAPI document from an ASP.NET Core web API application
There are several ways to generate the OpenAPI document from your ASP.NET Core Web API app. Swashbuckle is the most popular way to do so.
It’s easy to use and, once it’s installed to your app, it automatically displays the Swagger UI screen.
Swashbuckle also generates the OpenAPI document on-the-fly, which includes all the API endpoint details, payload structures, security requirements, etc. Here’s the sample document for VanArsdel’s inventory management web API.
In the next unit, an exercise will show you how to enable this OpenAPI capability for your ASP.NET Core Web API app.
helps organizations publish web APIs to external, partner, and internal developers to unlock the potential of their data and services. But before publishing the web APIs for other developers to consume, the author of the web APIs must first deploy them to Azure API Management.
Developers using Visual Studio to create ASP.NET Core web APIs can use functionality built right in to export their web API directly to Azure API Management.
In a previous module on fusion development teams, you met the folks at VanArsdel, Ltd. A fusion development team pairs professional, high-code, developers with citizen, low-code, developers to create better apps faster. The citizen developers create applications to suit their needs using Power Apps and those applications consume services created by professional developers, such as web APIs. Before citizen developers can use any web APIs in their Power Apps applications, the web APIs must be hosted somewhere. Azure API Management is an ideal spot.
The professional development team at VanArsdel, led by Kiana, have built several ASP.NET Core web APIs for inventory management. They want to publish the web APIs to using Visual Studio. This step allows the development teams to have minimal context switching between Azure API Management and Visual Studio during development.
Throughout this module, you explore how Visual Studio can offer frictionless development experiences for web API application development from code to deploy.
Template components that you can reuse across multiple apps provide a foundation of tried and tested layout and logic for UI element customization. Template components apply a standardized design across a web app by defining common elements and applying them to all pages. Templates can streamline updates, such as rebranding, because you make modifications only at the central template location.
In this unit, you learn about template components and how you can incorporate them into a Blazor application.
The RenderFragment type
A template component supplies the layout and logic for one or more fragments of HTML markup. The HTML renders by using the context the template component provides. The template component uses a RenderFragment object as a placeholder into which the markup is inserted at runtime.
A template is just an ordinary Razor component. To use a template, a consuming component references it like any other component. The ChildContent name is the default for a RenderFragment parameter. You can give the parameter a different name, but you must specify this name when the test page applies the template.
Generic RenderFragment<T> parameters
By default, the RenderFragment class acts as a placeholder for a block of HTML markup. However, you can use the generic type RenderFragment<TValue> to render other types of content by using a type parameter and providing the logic to handle the specified type in the template component.
For example, suppose you want to create a template that displays the items in a collection. You might use a C# foreach loop to iterate through the collection and display the items found. However, the collection might contain data of any type, so you need a generic way to render each item.
To write a generic type template component, you need to specify the type parameter in the template component itself, and in the consuming component of the template. The following list represents common characteristics of generic type template components.
The type parameter in a template component is introduced using the @typeparam directive. A template component can have multiple type parameters if necessary.
The template probably defines a parameter containing an enumerable collection of objects of the type specified by the type parameter.
The template also defines a ChildContent parameter based on the generic RenderFragment type that takes the same type parameter.
Blazor components have a well-defined lifecycle that starts when they’re first created and ends when they’re destroyed. A set of events that occur in response to specific triggers governs the component lifecycle. Such triggers include the component being initialized, users interacting with the component, or the page where the component resides being closed.
In this unit, you learn about the events that occur during the Blazor component lifecycle. You see how to handle these events to optimize the work done and increase the responsiveness of a Blazor page.
The Blazor component lifecycle
Blazor components represent the views in Blazor apps, which define the layout and UI logic. The components generate HTML markup when the app runs. User interaction events can trigger custom code, and components can be updated to rerender the display. Upon page closure, Blazor removes the component and cleans up any resources. New instances are created when the user returns to the page.
The following diagram illustrates the events that occur during the lifetime of a component, and the methods you can use to handle these events. Blazor provides both synchronous and asynchronous versions of each method except for SetParametersAsync.
All Blazor components descend from the ComponentBase class or the IComponent interface that defines the methods shown and provides default behavior. You handle an event by overriding the corresponding method.
Although the diagram implies that there’s a single-threaded flow between lifecycle methods, the asynchronous versions of these methods enable a Blazor app to expedite the rendering process. For example, when the first await occurs in SetParametersAsync, the Blazor component runs the OnInitialized and OnInitializedAsync methods. When the awaited statement completes, the execution thread in SetParametersAsync resumes.
The same logic applies throughout the series of lifecycle methods. Also, each await operation that occurs during OnInitializedAsync and OnParametersSetAsync indicates that the state of the component changed, and can trigger an immediate rendering of the page. The page might be rendered several times before initialization is fully complete.
Understand lifecycle methods
Each component lifecycle method has a specific purpose, and you can override the methods to add custom logic to your component. The following table lists the lifecycle methods in the order they occur, and describes their purpose.
If the component implements either IDisposable or IAsyncDisposable, the appropriate disposable occurs as part of destroying the component.
The SetParametersAsync method
When a user visits a page containing a Blazor component, the Blazor runtime creates a new instance of the component and runs the default constructor. Once the component is constructed, the Blazor runtime calls the SetParametersAsync method.
If the component defines any parameters, the Blazor runtime injects the values for these parameters from the calling environment into the component. These parameters are contained in a ParameterView object and are made accessible to the SetParametersAsync method. You call the base.SetParametersAsync method to populate the Parameter properties of your component with these values.
Alternatively, if you need to handle the parameters differently, this method is the place to do it. For example, you might need to validate any parameters passed to the component before using them.
Note
The SetParametersAsync method always runs when a component is being created, even if the component doesn’t have any parameters.
The OnInitialized and OnInitializedAsync methods
You can override the OnInitialized and OnInitializedAsync methods to include custom functionality. These methods run after the SetParametersAsync method populates the component’s parameter-based properties, which are attributed with either . You run initialization logic in these methods.
If the render-mode property of the application is set to Server, the OnInitialized and OnInitializedAsync methods run only once for a component instance. If a parent of the component modifies the component parameters, the SetParametersAsync method runs again, but these methods don’t. If you need to reinitialize a component when the parameters change, use the SetParametersAsync method. If you want to do initialization once, use these methods.
If the render-mode property is set to the OnInitialized and OnInitializedAsync methods run twice: once during the prerender phase that generates the static page output, and again when the server establishes a SignalR connection with the browser. You might do expensive initialization tasks in these methods, such as retrieving data from a web service that you use to set the Blazor component state. In this case, cache the state information during the first execution and reuse the saved state during the second execution.
Any dependencies the Blazor component uses are injected after the instance is created but before the OnInitialized or OnInitializedAsync methods run. You can use the objects injected by these dependencies in the OnInitialized or OnInitializedAsync methods, but not before.
Important
Blazor components don’t support constructor dependency injection. Instead, use either the @inject directive in the component markup or the on the property declaration.
During the prerender phase, code in a Blazor Server component can’t perform actions that require a connection to the browser, such as calling JavaScript code. You should place logic that depends on a connection with the browser in the OnAfterRender or OnAfterRenderAsync methods.
The OnParametersSet and OnParametersSetAsync methods
The OnParametersSet and OnParametersSetAsync methods run after the OnInitialized or OnInitializedAsync methods the first time the component renders, or after the SetParametersAsync method in subsequent rendering. Like SetParametersAsync, these methods are always called, even if the component has no parameters.
Use either method to complete initialization tasks that depend on the component parameter values, such as calculating values for computed properties. Don’t do long-running operations such as these in a constructor. Constructors are synchronous, and waiting for long-running operations to complete affects the responsiveness of the page that contains the component.
The OnAfterRender and OnAfterRenderAsync methods
The OnAfterRenderand OnAfterRenderAsync methods run every time the Blazor runtime needs to update the view represented by the component in the user interface. This state occurs automatically when:
The state of the component changes, for example when the OnInitialized or OnInitializedAsync methods or the OnParametersSet and OnParametersSetAsync methods run.
A UI event is triggered.
The application code calls the StateHasChanged method of the component.
When StateHasChanged is called, either from an external event or a UI trigger, the component conditionally rerenders. The following list details the order of method invocations including and following StateHasChanged:
StateHasChanged: Marks the component as needing to rerender.
ShouldRender: Returns a flag indicating whether the component should render.
The StateHasChanged method calls the ShouldRender method of the component. The purpose of this method is to determine whether the state change requires the component to rerender the view. By default, all state changes trigger a render operation, but you can override the ShouldRender method and define your decision-making logic. The ShouldRender method returns true if the view should be rendered again, or false otherwise.
If the component needs to render, you can use the BuildRenderTree method to generate a model that can update the version of the DOM the browser uses to display the UI. You can use the default method implementation that the ComponentBase class provides, or you can override it with custom logic if you have specific requirements.
Next, the component view is rendered and the UI is updated. Finally, the component runs the OnAfterRender and OnAfterRenderAsync methods. At this point, the UI is fully functional, and you can interact with JavaScript and any elements in the DOM. Use these methods to do any other steps that require access to the fully rendered content, such as calling JavaScript code from JS interop.
The OnAfterRender and OnAfterRenderAsync methods take a boolean parameter called firstRender. This parameter is true the first time the methods are run, but false thereafter. You can evaluate this parameter to do one-time operations that might be wasteful and resource intensive if you repeat them every time the component renders.
Note
Don’t confuse prerendering with the first render for a Blazor component. Prerendering occurs before a SignalR connection is established with the browser, and generates a static version of a page. The first render occurs when the connection with the browser is fully active and all functionality is available.
The Dispose and DisposeAsync methods
Like any .NET class, a Blazor component can use managed and unmanaged resources. The runtime automatically reclaims managed resources. However, you should implement the IDisposable or IAsyncDisposable interfaces and provide a Dispose or DisposeAsync method to release any unmanaged resources. This practice reduces the chances of memory leaks in the server.
Handle exceptions in lifecycle methods
If a lifecycle method for a Blazor component fails, it closes the SignalR connection to the browser, which in turn causes the Blazor app to stop functioning. To prevent this outcome, make sure you’re prepared to handle exceptions as part of the logic for the lifecycle methods.
Blazor uses C# components rather than JavaScript to create web pages or HTML sections with dynamic content. But you can use Blazor JavaScript interoperability (JS interop) to call JavaScript libraries in Blazor apps and call JavaScript functions from .NET C# code.
In this unit, you learn how to call JavaScript from C# code in a Blazor page, and how to invoke C# methods from JavaScript functions. In the next unit, you use an alert component from a JavaScript library to update your Blazor pizza delivery website.
Use Blazor JavaScript interoperability
A typical Blazor component uses layout and user interface logic to render HTML at runtime. You use C# code to handle events and other dynamic page features that interact with the user and external services. In many cases, you don’t need to use JavaScript code. Instead, you can use Blazor with .NET libraries, which provide many equivalent capabilities.
However, sometimes you need to use an existing JavaScript library. For example, some open-source JavaScript libraries render components and handle user interface elements in a specialized manner. Or, you might have existing tried and tested JavaScript code that you want to reuse instead of converting it into C#.
You can integrate JavaScript libraries into your applications by using Blazor JavaScript interoperability, or JS interop. You use JS interop to call JavaScript functions from .NET methods and to invoke .NET methods from JavaScript functions. JS interop handles the marshaling of data and object references between Blazor and JavaScript to ease the transition between them.
Load JavaScript code in a Blazor app
You add JavaScript to a Blazor app the same way you add it to a standard HTML web app, by using the HTML <script> element. You add the <script> tag after the existing <script src="_framework/blazor.*.js"></script> tag in either the Pages/_Host.cshtml file or the wwwroot/index.html file, depending on your Blazor hosting model. For more information, see ASP.NET Core Blazor hosting models.
It’s best not to place scripts in the <head> element of the page. Blazor controls only the content in the <body> element of an HTML page, so JS interop could fail if the scripts depend on Blazor. Also, the page might display more slowly because of the time it takes to parse the JavaScript code.
Place JavaScript files under the wwwroot folder of your Blazor project.
Another option is to inject the <script> element that references a JavaScript file into the Pages/_Host.cshtml page dynamically. This approach is useful if you need to load different scripts depending on conditions that can be determined only at runtime. This approach can also speed up the initial loading of the app if you trigger the logic with an event that fires after a page is rendered. For more information, see ASP.NET Core Blazor startup.
Call JavaScript from .NET code
You use the to call a JavaScript function from .NET code. To make the JS interop runtime available, inject an instance of the IJSRuntime abstraction into a Blazor page after the @page directive near the beginning of the file.
The IJSRuntime interface exposes methods to invoke JavaScript code. Use InvokeAsync<TValue> to call a JavaScript function that returns a value. Otherwise, call InvokeVoidAsync. As the names suggest, both methods are asynchronous, so you use the C# await operator to capture results.
The parameter to the InvokeAsync or InvokeVoidAsync method is the name of the JavaScript function to invoke, followed by any arguments the function requires. The JavaScript function must be part of the window scope or a subscope of window. Arguments must be JSON-serializable.
Note
JS interop is available only when a SignalR connection is established between the Blazor Server app and the browser. You can’t make interop calls until rendering is complete. To detect whether rendering is finished, event in your Blazor code.
Use an ElementReference object to update the DOM
Blazor maintains a representation of the Document Object Model (DOM) as a virtual render tree. As the page structure changes, Blazor generates a new render tree that contains the differences. When the changes are complete, Blazor iterates through the differences to update the browser display of the user interface and the browser version of the DOM that JavaScript uses.
Many third-party JavaScript libraries are available to render elements on a page, and these libraries can update the DOM. If your JavaScript code modifies elements of the DOM, the Blazor copy of the DOM might no longer match the current state. This situation can cause unexpected behavior and possibly introduce security risks. It’s important not to make changes that can cause the Blazor view of the DOM to become corrupted.
The simplest way to handle this situation is to create a placeholder element in the Blazor component, usually an empty <div @ref="placeHolder"></div> element. Blazor code interprets this code as a blank space, and the Blazor render tree doesn’t attempt to track its contents. You can freely add JavaScript code elements to this <div>, and Blazor doesn’t attempt to change it.
Blazor app code defines a field of type to hold the reference to the <div> element. The @ref attribute on the <div> element sets the value of the field. The ElementReference object then passes to a JavaScript function, which can use the reference to add content to the <div> element.
Call .NET code from JavaScript
JavaScript code can run a .NET method your Blazor code defines by using the DotNet utility class, part of the JS interop library. The DotNet class exposes the invokeMethod and invokeMethodAsync helper functions. Use invokeMethod to run a method and wait for the result, or use invokeMethodAsync to call the method asynchronously. The invokeMethodAsync method returns a JavaScript Promise.
Tip
To maintain responsiveness in your applications, define the .NET method as async, and call it by using invokeMethodAsync from JavaScript.
You must tag the .NET method being called with . The method must be public, and any parameters must be JSON-serializable. Also, for an asynchronous method, the return type must be void, a Task, or a generic Task<T> object where T is a JSON-serializable type.
To call a static method, you provide the name of the .NET assembly that contains the class, an identifier for the method, and any parameters the method accepts as arguments to the invokeMethod or invokeMethodAsync functions. By default, the method identifier is the same as the name of the method, but you can specify a different value by using the JSInvokable attribute.
Call a .NET instance method from JavaScript
To run an instance method, JavaScript requires an object reference that points to the instance. JS interop provides the generic type you can use to create an object reference in .NET code. The code must make this object reference available to JavaScript.
The JavaScript code can then call invokeMethodAsync with the name of the .NET method and any parameters the method requires. To avoid memory leaks, the .NET code should dispose of the object reference when it’s no longer needed.
A pizza delivery company hires you to modernize their customer-facing Blazor website, which includes pizza listings, ordering pages, and other functionality. Blazor interactive web applications use .NET to share logic between the server and the client code.
In your updates, you want to:
Use JavaScript to animate a rendered HTML component.
Use a JavaScript library to apply branding to an alert page.
Change how the app responds to events after page rendering is complete.
Create and apply a template component to update multiple pages.
This module shows you how to interoperate with JavaScript code, use templated components, and respond to component lifecycle events in Blazor.
Learning objectives
Call JavaScript functions from .NET code and call .NET code from JavaScript in Blazor apps.
Handle events in the lifecycle of Blazor components.
Create reusable template components that you can incorporate into Blazor apps.
Prerequisites
Familiarity with HTML, CSS, and JavaScript web development.
An integrated development environment (IDE). This module uses Visual Studio Code.
Tip
This module uses the .NET Command Line Interface (CLI) and Visual Studio Code for local development. After you complete the module, you can apply the concepts and continue development by using Visual Studio for Windows, Visual Studio for Mac, or Visual Studio Code with Windows, Linux, or Mac.
.NET 9.0 SDK
This module uses the .NET 9.0 SDK. Ensure that you have .NET 9.0 installed by running the following command in your preferred command terminal: