DANIEL ROTH: Hi everyone.
I'm Daniel Roth,
Product Manager at Microsoft for Blazor.
Blazor is a web UI framework built on
the mature foundation of.NET
to enable greater performance,
productivity, and security
when building modern web apps.
Today's web apps use a variety of approaches to
deliver the best UI experiences.
Some pages are rendered from the server in response to
requests so that the UI loads
almost immediately and is easily indexed.
In other cases, it's easier to
handle the UI from the client so
that you get rich interactivity
and access to client capabilities.
With Blazor in.NET 8,
you can handle all of your web UI needs using
Blazor's convenient component model
from both the client and the server.
Let me show you how. This recipe app
is built entirely using Blazor.
On the homepage, we can see a bunch of
recipes and we can click
on a recipe to see all of its details.
If we look at the browser DevTools
to see what this app looks like,
let's look at everything and refresh the page,
we can see there's no WebAssembly
being downloaded for this app.
There are no WebSockets being set up.
There's not even any JavaScript being downloaded.
This entire app is being fully rendered from the server,
so it loads almost instantly and is ready to scale.
No JavaScript required. In.NET 8,
you can use Blazor components to
do full server-side rendering.
Now let's look at the code to
see how this is implemented.
Here's the project.
Let's look at the component for
the homepage and also the
components for that recipe details page.
Now, each of these components is
set up as a routable endpoint.
For example, right here we can see the route
for the recipe details page.
As requests come to the server
they're routed to the component and
the component renders full HTML right to the response.
Now we can also handle forum posts from our application.
Let's go back to the app and close the DevTools.
For example here on the homepage we can search
for all the recipes that have chocolate.
That was a forum posts to do the search.
If we click on one of these recipes
and go down to the bottom,
we can see there's this little widget for
posting a review on the recipe.
This one is delicious and let's submit that.
Then we can see that the review
was added to the bottom of the page.
If we submit the form without adding any data,
you can see that validation works too.
How has this form implemented?
Let's go back to the code.
Here's the recipe details page.
If we scroll down,
here's the star rating reviews component
that's setting up that widget.
Let's go to its definition.
Then here we can see that we're using
the built-in Blazor edit form and
input components to implement this form.
These components will modify the data and
validate it before calling your submit event handler,
all from the server.
That's great. Now we can actually enhance
the user experience of this app to make it even better.
Let's go back to the application.
Now currently, if we go back to the homepage,
every time we navigate,
we're actually doing a full page loads.
You might even see a little UI blip as
the page gets completely
reloaded. That's a little jarring.
Also, if we go back to
the review form and let's post another review,
you may have noticed that if I submit this,
that we are also losing the scroll position.
Again, that's because we're doing
a full page load when we submit the form.
We can improve the navigation
and form handling experience
by adding some client-side loading.
Let's go back to our application.
Let's go to main layout.lazor.
This is the main layout for this application.
At the bottom, I'm just going to add the Blazor script,
then let's go ahead and restart the app.
Well, with that script Blazor will now
enhance page navigations and form handling.
We just wait for that to start.
Cool. Now that it's loaded.
If we navigate, let's for example,
navigate to one of the recipes and go back.
It navigates fast and silky smooth.
There's no longer that UI blip.
That's because Blazor is intercepting
every navigation and then handling
the response content and using it to updating
the DOM of the page
without having to fully load the page.
Much smoother navigation experience.
Then if we go to one of these recipes
and submit the form,
let's add another review.
Maybe this one is just okay. We'll submit that one.
Notice that the review gets added to
the bottom and we don't lose the scroll position anymore.
Now sometimes, and let's go back to the homepage,
pages need to perform
long-running async tasks in order to fully render.
Like maybe you need to get some data from
a database or call an API.
This can delay the rendering of a page.
To simulate this, let's go back to
our app and let's go to where we're
loading the recipe data in this recipe store,
and I'm going to add some code to
simulate our database query.
Here in this get recipes page,
let's add a little code right here,
and then we'll restart this.
This is just a Task.Delay as if we're
making a long-running database query.
We'll go ahead and restart that.
Cool. Now if we refresh the homepage,
I'm going to click one-one thousand,
then the page finishes loading.
It's a little easier to see if we go to
a recipe and I'm going to click back,
ready, click one-one thousand then the page loads.
We have to wait for all those long-running async tasks
to complete in order to fully render the page.
Now with Blazor in.NET 8,
we can improve the perceived load time of the page,
pages that have long-running async tasks
by using streaming rendering.
Streaming rendering allows the page surrender with
placeholder content while the async tasks are running.
When the tasks are completed,
the new content can be streamed to the client on
the same response connection and
then patched by Blazor into the DOM.
Now to enabling streaming rendering, it's really easy.
Let's go to the homepage of the app.
Let's do this on index.razor,
and we're just going to add
an attribute at the top of the page.
The stream rendering,
we got true attribute,
and that will turn on
streaming rendering for our homepage.
Now notice, like right here, you'll see there's this,
if recipes is null,
then we're going to render
this loading recipes placeholder.
That will be important to watch for that in
just a second. Let's go back to the app.
Now if we refresh the page,
yeah, you see there's that little loading
recipes dot dot dot that shows up.
We can get rid of these guys.
Let's refresh one more time, refresh,
loading recipes dot-dot-dot and then once
the database query has completed,
the updated content is
seamlessly patched into the existing page.
You get pixels on the screen really
fast and your app feels much more responsive.
Now so far our Blazor app is still only using
server-side rendering with some framework
provided enhancements on the client.
Now it's time to add some client interactivity.
This application also has
a page where we can submit new recipes.
There's this recipe editor page,
and we want this page to have a more sophisticated UI,
like for example,
we want to be able to choose
a picture that we upload and being
able to see a little preview
of it right here on the page,
right now we're just getting the filename.
We also have this ingredients list Builder
where we want to be able to add
ingredients and be able to
edit and reorder them using dag and drop.
Right now if I click this
Add button to add an ingredient,
it doesn't even do anything yet.
That's because this page is
using just server-side rendering.
It's not setup for interactivity yet.
Let's fix that. Let's add some interactivity.
Let's start with just this ingredients list editor.
Let's go back to be out. Let's go
to that submit recipe page.
Down here is the ingredients
list editor component that we saw.
I'm just going to add an attribute render mode,
and we're going to set the render mode
for this component to be,
well something let's say we have a couple of options.
We can do server,
which means that the interactivity
for this component will be handled
over a WebSocket connection using Blazor server.
Or we could use WebAssembly,
in which case the interactivity will be handled from
the client in the browser running on
WebAssembly. Let's start off with server.
We'll do server first,
and then we'll go ahead and restart. All right, cool.
Let's go back to that submit recipe page.
Now if we go to our ingredient lists builder,
we should be able to add some ingredients.
Add some flour, yes,
it's working, some eggs, I don't know.
Maybe a few docs.
It doesn't really matter, but we can stretch
between the units for a metric to imperial.
We can even drag and drop
our ingredients to reorder them.
This is now an island of interactivity using
Blazor server within
our broader server-side rendered application.
We really want this whole page to
be interactive. We can do that too.
Let's go back to
the application and I'm actually going to
remove that render mode attribute that we just started.
Let's add some data binding for the ingredients.
But up at the top,
I'm going to add another attribute to
this summit recipe page to say that I want
the render mode for this whole page to be server.
Let's go ahead and restart that.
Great. Let's go back to that summit recipe page.
Now we should be able to select a picture.
Instead of just seeing the filename,
we get a picture preview.
We can still add our ingredients.
That works fine.
We can even submit the whole form and get
client-side validation working great,
so now the whole page is interactive using laser server.
What's really cool is that the rest of
the app is still using server-side rendering.
If we go back to the homepage and let's bring
back up those browser dev tools.
Let's refresh the page to see
everything that's being downloaded.
Initially, we don't have
any web socket connections being set up.
No Blazor server yet.
But if we browse to that summit recipe page, there it is.
Now we have the Blazor server WebSocket connection
being set up.
When we leave that page,
the connection can be closed down and
any server-side states can be freed up so that
we reduce the load on our server.
You use Blazor server just where it's needed.
Now we can use Blazor WebAssembly as well.
If we go back to that page and instead of using server,
we set this up as WebAssembly,
we can do that too.
Now one thing I want you to notice is
that there's only one project here.
We don't need a separate project
for our Blazor WebAssembly code.
That's thanks to multitargeting,
we're able to build for both the client
and the server from this one project.
Now if we go back to that summit recipe page,
we should still see that the interactivity is working.
Let's make sure that's functional.
Yes, it's working.
Well, let's go back to the homepage and bring up
the browser dev tools to see what's happening this time.
First, I'm going to clear out
all the site data just to make sure we don't
have any Blazor WebAssembly stuff pre-cached.
Now if we refresh this homepage,
okay, do we have any WebAssembly?
No WebAssembly yet.
But if we browse to the summit Recipes page
there now we're seeing
the dotnetWebAssembly runtime being
downloaded and set up and being used.
If we have any other pages in
our app that are using Blazor WebAssembly,
they can reuse this downloaded runtime because it's
cached for the entire application. All right, cool.
We can set up interactivity for our app
using Blazor server or Blazor WebAssembly,
and we can do that on
a per component basis or for entire pages.
That's really nice. But maybe you'd prefer to have
that decision to be made automatically at runtime.
You might do something clever,
like start users off with Blazor server,
which loads fast while you
download the dotnetWebAssembly runtime in the background.
That way the app can switch to use Blazor WebAssembly on
future visits if it has been
previously cached, what might that look like?
All right, let's go back to
the app one more time and we're going to
switch the render mode to auto,
use an auto rendering mode.
Let's restart the application.
See what that does.
I think we can close all these other tabs.
All right, let's bring up the browser dev tools
one last time.
Again, let's Cloud any site data to make sure we don't
have any Blazor WebAssembly stuff precast.
Let's refresh the page.
Do we have any WebAssembly yet? No WebAssembly.
Do we have any WebSockets?
No WebSockets. What if we
browse to the summit recipe page?
They are now we see the
Blazor server web socket being set up.
But also in the background,
we're downloading that dotnetWebAssembly runtime.
Now which ones being used?
Well, if we look in the dev console,
we can see that this app is
currently running over a WebSocket.
It's using Blazor server,
but it's got the dominant WebAssembly runtime
downloaded and cached.
When we browse to this app again,
like we can just refresh the page,
now we can see in the browser dev console
that we're running on WebAssembly,
we're using Blazor WebAssembly.
The app detected that the runtime was
already there and it just used it so we're
able to save on
those precious server resources. Super cool.
Our app is now using the vast of server and client,
thanks to the new full-stack web UI support
and Blazor in DotNet eight.
In this demo, we've seen
server-side rendering using Blazor components,
enhance navigation and form handling,
streaming rendering, adding
client-side interactivity per component or per page,
and the ability to select
the appropriate render mode at runtime.
I hope you enjoyed learning about Blazor in DotNet 8.
There's plenty more that's new in Blazor to make
your next web projects easier and more productive.
Be sure to give it a try today by downloading DotNet 8.