Telerik blogs

Big changes are coming for Blazor in .NET 8, and we’re already beginning to see some of those changes emerging in the early preview releases. Here’s how Blazor is shaping up ahead of its November release.

Server-Side Rendering with Blazor

A big focus for .NET 8 is making it possible to build web app using Blazor’s battle-tested, productive component model, but have those components rendered on the server.

This opens the door to using Blazor where you would otherwise use MVC or Razor Pages, to run on your server and return HTML to the browser. With this flow, there are no open socket connections, and no need to ship DLLs to the browser.

For many applications this is a compelling option and, as of .NET 8 Preview 3, an early version of this server-side rendering is in place.

Here’s how it currently works (note, the implementation details shown here will likely change in the coming months).

I’ve started with a standard ASP.NET web app project, and a layout component (MainLayout.razor).

@inherits LayoutComponentBase
@implements IRazorComponentApplication<MainLayout>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <base href="/"/>
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet"/>
    <link href="css/app.css" rel="stylesheet"/>
    <link href="Net8Demos.styles.css" rel="stylesheet"/>
    <HeadOutlet></HeadOutlet>
</head>
<body>
<PageTitle>.NET 8 Demos</PageTitle>

<div class="page">
    <main>
        <article class="content px-4">
            @Body
        </article>
    </main>
</div>

</body>
</html>

Note the call to implement IRazorComponentApplication<MainLayout>. That line is currently needed so ASP.NET can route requests to your components, but this requirement is likely to disappear in a future release.

I’ve then created a simple test component:

Index.razor

@layout MainLayout
@page "/"

<h2>
    Hello Blazor (Server Side Rendering)
</h2>

What we’re aiming for is all requests to the home page / to be routed to this component.

For that to work we need to make sure we add a couple of lines to Program.cs.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorComponents();

var app = builder.Build();

...

app.MapRazorComponents<MainLayout>();

app.Run();

They key calls here are to AddRazorComponents and MapRazorComponents.

With that, let’s run the app, and view it in the browser.

dotnet run

A simple page in the browser, showing a Hello World message

Well, we’re not going to win any design awards for this one, but it works!

Notice how there’s a single request (to localhost) and the response is standard HTML. Blazor rendered the Index.razor component (which uses the MainLayout layout page) on the server, and returned standard HTML back to the browser.

Here’s another component, this time to render a “Github style” news feed.

NewsFeed.razor

@page "/News"

<section class="container">
    <p>For you (beta)</p>

    <h4>Trending Repositories</h4>

    <section>
        <Card User="jonhilton"
              Repository="practicalBlazorComponents"
              Description="A new online, interactive workshop!"
              Languages="@(new List<string> { "C#", "JavaScript" })"/>

        <Card User="AdrienTorris"
              Repository="awesome-blazor"
              Description="Resources for Blazor, a .NET web framework using
                           C#/Razor and HTML that runs in the browser with WebAssembly."
              Languages="@(new List<string> { "C#" })"/>
    </section>
</section>

This renders instances of another component, Card (which shows details for each “repository”).

Run this in the browser, and we see the same results, pure HTML returned in the response.

A list of trending repositories, with titles and details for each one

Form Posts

If server-side rendering tackles displaying data in the browser, what about capturing user input?

Long before single-page applications (SPAs) and the emergence of JavaScript as the “go to” technology for building web apps, website interactions were generally handled by forms. In Preview 4, we find some early support for using forms with Blazor server-side rendering.

To make it work, you need to use something called CascadingModelBinder for your components. In our example above, we can add this to MainLayout.razor.

...

<div class="page">
    <main>
        <article class="content px-4">
            <CascadingModelBinder>
                @Body
            </CascadingModelBinder>
        </article>
    </main>
</div>

...

Then we can use Blazor’s standard EditForm component to define a form.

Here’s a form for collecting user suggestions for our Github news feed.

SuggestRepository.razor

@page "/SuggestRepository"

<EditForm OnValidSubmit="HandleSubmit" Model="model" method="POST">
    <section class="form-group">
        <label for="name">Your name:</label>
        <InputText @bind-Value="model.YourName" class="form-control" id="name"/>
    </section>

    <section class="form-group">
        <label for="repoUrl">Repository URL:</label>
        <InputText @bind-Value="model.RepositoryUrl" class="form-control" id="repoUrl"/>
    </section>

    <section class="form-group">
        <label for="notes">Your notes:</label>
        <InputTextArea @bind-Value="model.YourNotes" class="form-control" id="notes"/>
    </section>

    <section class="py-2">
        <button type="submit" class="btn btn-primary">Submit your suggestion</button>
    </section>
</EditForm>
@code {

    SuggestionModel model = new();

    private void HandleSubmit()
    {
        Console.WriteLine("OK, we're handling the submit!");
    }

    record SuggestionModel
    {
        public string YourName { get; set; }
        public string RepositoryUrl { get; set; }
        public string YourNotes { get; set; }
    }

}

This is a standard EditForm with a little bit of Bootstrap CSS thrown in, to make it look reasonable in the browser.

Notice the form method is set to POST (GET requests aren’t supported with Blazor SSR).

View this in the browser, and we’ll see a standard HTML form. Submit the form, and we see a POST request to /SuggestRepository, including the entered form values.

A form with inputs for name, repository URL and notes, with a submit button at the bottom

In the SuggestRepository Blazor component, we can handle this incoming data in the HandleSubmit method and do whatever we like with it (post to a database, API, etc.)

Proof that this is working lies in the server logs for the running ASP.NET application:

A snapshot of a terminal window showing the message 'OK, we're handling the submit!' several times

(I may have hit that submit button a few times!)

At the time of writing, model binding and validation isn’t in place yet (it’s coming). The workaround for now is to drop down to the FormDataProvider service and handle the incoming form data manually.

@page "/SuggestRepository"
@inject FormDataProvider FormData

<EditForm ...>
	...
</EditForm>
@code {
    
    SuggestionModel model = new();

    protected override void OnInitialized()
    {
        // Manually model bind the form data using the FormDataProvider service
        if (FormData.Entries.TryGetValue("YourName", out var yourNameValues))
        {
            model.YourName = yourNameValues.First();
        }
    }
    
    private void HandleSubmit()
    {
        Console.WriteLine("OK, we're handling the submit from " + model.YourName);
    }  
    
    ...
    
}

Now when we submit the form, our instance of SuggestionModel is updated with the posted vales, and we can access them in our HandleSubmit handler.

A form with the Name input prefilled with the name Jon

Streaming Rendering with Blazor Components

The other big update to hit the preview releases is streaming rendering.

This handles the scenario where you have a Blazor component which is fetching data, and you want to show a message while that data fetching takes place.

With server-side rendering, you would usually only get one chance to send a response to the browser (when everything has loaded, the data has been fetched and the HTML rendered).

Streaming rendering makes it possible to perform an initial return with the HTML for the essential structure of the page, then fill in the rest of the details as they become available (when data fetching is complete).

To make it work, we need to add an additional script to our app.

Let’s add it to the MainLayout.razor layout we’re using.

<body> 
	...
    
	<script src="_framework/blazor.web.js" suppress-error="BL9992"></script>
</body>

Now we can add an attribute to our component, to enable Streaming Rendering.

NewsFeed.razor

@attribute [StreamRendering(true)]
@page "/News"

...

Now, for the sake of our demo, let’s simulate a network call and add some UI to handle the situation where we’re waiting for that call to complete.

@attribute [StreamRendering(true)]
@page "/News"

@if (loading)
{
    <p>Fetching news feed!</p>
}
else
{
	...
}
@code {

    bool loading;

    protected override async Task OnInitializedAsync()
    {
        loading = true;
        await Task.Delay(1000);
        loading = false;
    }

}

With this, when someone visits this page the component will render without waiting for the async tasks to complete, and will render the loading UI we’ve defined.

Then, when the async call completes, it will stream the updated HTML to the response, and Blazor will patch that into the DOM.

animation showing an initial loading screen, followed by a simple news feed

Route to Named Elements

On to smaller changes!

You can now route directly to a specific HTML element on a page using standard URL fragments.

Say you have a product page, and an element with the id set to BuyNow.

@page "/product"

...

<div id="BuyNow">
    <h3>Buy Now</h3>
    <p>It's really good!</p>
</div>

If someone navigates to <your-site-url/product#BuyNow, they’ll be routed to this page and Blazor will correctly scroll to the BuyNow div.

Sections Support

As we’ve seen, you can use layouts for your Blazor components but until now you’ve only been able to inject content into one part of your layout.

<main>
    <article>
    	@Body
    </article>
</main>

When a component uses this layout, @body will be replaced with that component’s contents.

But what if you want to render content in different parts of the layout?

For example, you might want to render content in a sidebar for your page, as well as the main section.

<main>
	<aside>
        <!-- Let component's put content here? -->
    </aside>
    <article>
    	@body
    </article>
</main>

With .NET 8, you can define a SectionOutlet where you want additional content to be rendered:

@using Microsoft.AspNetCore.Components.Sections

<main>
	<aside>
        <SectionOutlet SectionName="Sidebar" />
    </aside>
    <article>
    	@body
    </article>
</main>

With this, any component using this layout can provide content for that sidebar section.

For example, here’s a component to show an article, which also fetches a list of related articles. It can render those related article links in the sidebar using the new .NET 8 SectionContent component.

Article.razor

<SectionContent SectionName="Sidebar">
    @foreach(var article in related){
        <a href="@article.Link">@article.Title</a>
    }
</SectionContent>

@articleContent
...
@code {
    
    List<ContentLink> related;
    string articleContent;
    
    ...
    
}

Webcil Packaging for Blazor WASM Apps

Finally, Blazor WASM will sometimes fail to load in certain environments due to network/security policies that block the download or use of .dll files.

New in the .NET 8 preview releases is an option to enable the use of Webcil instead. Webcil is a web-friendly packaging of .NET assemblies that, by removing content specific to native Windows execution, should avoid these issues.

You can enable Webcil via your Blazor WASM app’s project file:

<PropertyGroup>
    <WasmEnableWebcil>true</WasmEnableWebcil>
</PropertyGroup>

In Summary

The early preview releases of .NET 8 are showing some promising hints of what’s to come for Blazor later this year.

While server-side rendering plus streaming rendering catch the eye and will likely prove the focus for .NET 8, it’s worth keeping an eye on the other smaller changes, which look set to plug some of the remaining gaps in Blazor’s rich component model come November.


Next up: Big Changes Coming for Blazor in .NET 8.

Jon Hilton
About the Author

Jon Hilton

Jon spends his days building applications using Microsoft technologies (plus, whisper it quietly, a little bit of JavaScript) and his spare time helping developers level up their skills and knowledge via his blog, courses and books. He's especially passionate about enabling developers to build better web applications by mastering the tools available to them. Follow him on Twitter here.

Related Posts

Comments

Comments are disabled in preview mode.