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.