>> [MUSIC] Hello, everyone. Welcome to the September edition
of the Blazer Community Stand Up. With us today, we have Daniel Roth. >> Hello, everyone. Welcome. >> Jon Galloway. >> Very excited to be here. Let's see some Blazer. >> Today the topic is full
stack Blazer tips and updates. Part of this is going to be where
Dan is going to go over some of the new changes coming
in ARC1 for Blazer, and then I'll be giving a
presentation after that about just a Blazer static
server rendering overview and how it works and how it
impacts how you build apps. That's that and I guess
we should start by doing the community links. Here we go. First we have a blog
post by Jon Hilton, Blazer SSR gets auto render mode
in the latest.NET 8 preview. It's not just about auto mode, this is a general
Preview 7 overview. It goes in depth about a lot of different features
coming to Preview 7 like how forms work and root level cascading
values and things like that. It's a pretty cool blog post
and it goes fairly in depth. If you want to learn
how to use some of those new features,
certainly check that out. Yeah, so the next one is a
pretty interesting one we have it calls itself
a Blazer framework. It's a component library, but also it provides some abstract base classes
for Blazer components, so normally components
inherit from component base, but they provide alternate
components with different mechanics around how they react to changes
to state and things like that. It's a pretty interesting framework, but it also does include some
pretty nicely styled components. They actually have a site
here that we can look at, but they have various really
beautiful looking components that you can use in Blazer apps. If you like this look, I think this would be a
cool thing to check out. But yeah, they also
have some helpers for rendering like
render fragments I believe there was something
on here about that. Then a >> [inaudible] reactivity. >> Yeah, it takes an alternate approach
to handling changes to state. With component base, you have to state has changed method which allows you to indicate that the component
should be rendered. But that gets called implicitly
by things like event callbacks, but as far as I understand from
this library, that's not true. It doesn't get called automatically. You have to call update manually, but then they also have
special reactive value which does automatically
trigger a state change. It's just like an interesting
new approach for hindering reactivity in Blazer apps and I might have gotten
something wrong there, I haven't actually
personally tried it, but it looks interesting. I think. >> Reactive value, I don't know, it sounds like knockout to me for some reason,
is it? But maybe not. Sounds like it's a value that is about when it's changed
and can plumb into the component infrastructure to know that any things need to
rerender. That's interesting. >> Great, it's great to see
people innovating in this space. >> Yeah, it's super interesting. So I'm curious to
see where this goes. Next, we have Blazer
Barcode Scanner. This is a library that lets you scan barcodes and
I think QR codes too. I was trying out my phone
earlier with a barcode, but I think the light on my
camera messes it up a little, so I'm not going to try to demo
that, but it's pretty cool. If you need to scan QR codes
or barcodes from a Blazer app, this is a pretty convenient
way to make that work. Next, we have a new
version of Blazorise, which is a Blazer component library. It's one of the bigger ones, and it has various improvements, various new components
like Signature Pads, has a splitter component for resizable panels as well as enhancements to their
data grid component, which I believe is based off the quick grid component
that is shipped with Blazer. If you're using Blazorise,
then try the new version. >> That's interesting. That
off Canvas component there. >> Off Canvas? >> Yeah. >> Oh, yeah. >> Is that for custom drawing?
Is that what that's on? >> Responsive design for desktop
and mobile. I don't know. >> Yeah, I'm curious about that
too. Cool, it sounds neat. >> In some sense, for
me, this is one of the reasons why we
need the community. There are things that even
concepts that I was like, might not have even know about. We're certainly not all knowing and so when the community can go and explore these ******
and ideas and concepts, that just makes things
better for everyone. It's cool to learn about these things and see people
playing around with a stack. >> It's nice too because
for some of these, they have to have opinions. They say, here's how
we do components, or here's how we do
charts or whatever and if Blazer did that
at the bottom level, you lock people in, but when people build a
library, they can say, here's how we do this
certain thing and you get these different
flavors of development. >> Yeah, absolutely. >> Last on the list, we have a
YouTube video by Coder Foundry, Why 2024 is the Year of Blazor. This is a pretty cool video. It's a very positive perspective about the future of.NET and about
the new things coming in.NET 8. It also shows an example that
uses some of the new features. It's pretty cool, I will say. So definitely check
out this video if you want another perspective on things. I think that's it for
the community links. I think we're handing
it off to Dan now. >> One other link if
you want to share it. It's the blog post
should be live by now. >> I'll check that out. >> Who is that guy? I also
got my same jacket on. >> Very fresh blog post. >>.NET 8. At least
candidate 1 is live. It just shipped right now, hot off the press. Download it, install it, get it on your machines. It's got a lot of great stuff in it. Just went live right now. >> All the Blazor stuff. >> Look at all the Blazor stuff. Easy way to get it,
just go to.NET/next. That's a nice short link for the next preview release of.NET if you want to get whatever
the latest preview release is. That has been updated for
a release candidate 1, and so you can download
it, install it. This is a release candidate, so that means that we
are pretty much done. This is supposed to be
a candidate release for the upcoming stable
release of.NET 8, which is planned for November, every year new.NET version. Most of the features are in. Like most of the changes have
been done with this release. Not all although, there are still some
areas that we do expect some pending changes, Blazor being one of those. If you're looking for everything
to be done in Blazor for.NET 8, we're not quite there yet
with release candidate 1, we will have another release
candidate next month, that will be release candidate 2, and we expect to be
feature-complete, and done with all the big changes
for Blazor at that point. A few more things
coming from Blazor, but for the broad.NET platform, pretty much everything else is there and done and ready to try out. If you've been waiting,
holding off on.NET 8, saying I don't know
if I'm going to try preview four or five or whatever, I'm going to wait till
it's more taking shape, this is a good moment to
start kicking the tires. You can take your
existing.NET 7 out, and try upgrading
them to.NET 8 to RC1. Or if you've been following
along with the releases, you can easily upgrade from.NET 8
preview 7 to.NET to RC1 as well. >> I don't know if there's a link to that next page if you want to show that Mckennon because
I'm really interested. Like we've been working on
this page and trying to make it useful to people, so it has the links
to the newest stuff. Down at the bottom, we've got some top recommended
videos which we're always updating. We'll likely put this
one on there too, so this has all the preview
blog posts and all that stuff. >> Good resource if
you want to stay on the cutting edge of what's
happening with.NET. Now, if you haven't been
following along with every single preview
release and you want to know what's actually new in.NET 8. Like how do I get a broad overview? Particularly for like
ASPNET Core and Blazor, we have done some work to update the official release notes page that lives with the ASPNET
Core documentation. Mckinnon, if you go
back to the block post, there should be at the top. I think I mentioned this at
the top, where to find this. What's new in ASPNET Core and.NET 8. If you click on that, hopefully,
that link works. There it is. That's a summary of all the new features in ASPNET Core and Blazor that you
can read through and check out the preview documentation for those features so you can get a full view of all
the stuff that's new across the.NET 8 release from.NET 7. That's if you haven't been
completely following along. Lots of cool stuff
in here, obviously, the full stack web UI work
that we've done in Blazor, but there's been work that's
been done in minimal APIs, the native AOT work to support taking APIs built with ASPNET Core, and being able to fully
ahead of time compile them. Lots of work in the authentication
and authorization space. Tons of good stuff to try out. Way more than we can even cover in this one-hour Blazor
community sender. Now, from.NET 8 preview 7
to.NET 8 release candidate 1. There's also a bunch of new
things that wasn't there before. Let's take a look at that today.
Let's go back to the blog post, and there's things across the board, but we'll be focusing on
the new Blazor features. First thing in RC1, we have done a bunch
of work to further improve and clean up the new
Blazor web app template. This is the new Blazor template
that's intended to unify our web UI story for.NET
and ASPNET Core, so you have a one-stop shop for building all of your
web applications. All of your web UI needs
should be satisfied here. It's set up with all the new
Blazor capabilities in.NET 8. Like support for static
server rendering, where you can just render
a Blazor or a component to the response stream in response
to a request due to an endpoint. Very similar to the
rendering that we've always supported with MVC and razor pages, and even back further with.NET. We go back to web forms and
some of the older frameworks. You can now do that pattern
with Blazor components, the template is set up with that. There's the progressive enhancements
of static server rendering. Like the ability to do enhanced
navigations and form handling. That's where Blazor
will actually intercept the page navigation to prevent
the need for a full page reload, for a full page refresh, when you're going to a new page. It will instead intercept
that request and do a fetch request down in Javascript. Then the rendering still
happens from the server, but Blazor then takes care of
looking at what's actually changed based on what was
rendered from the server and patching that into the DOM. There's no web sockets involved
here, there's no WebAssembly. It's still doing
server-side rendering, static server rendering, but it's doing it in a more
enhanced and seamless way. This makes your app feel more like a SPA app when you're
navigating around. It's fast, it's smooth. You don't see that blip
when the page reloads, but it's still leveraging the
server for the actual rendering. Streaming rendering is
enabled in the template. This is when you have pages that
do long-running async tasks, but you still want to get pixels down to the browser
as fast as possible. Streaming rendering, will do an initial render of your
Blazor components with some initial HTML and some
placeholders for content that's going to come later while
you go and query the database, or do an API call. That update can then be
rendered from the server with a separate component render and streamed to the same response stream so that the UI can be updated. That's streaming rendering,
and then, of course, all the normal interactive modes that Blazor has
supported for a while. The Blazor Server render mode, Blazor WebAssembly render mode, where you want to have
a component that can deal with button clicks
and drag and drop, and full rich interactivity. Also, the new auto render mode, which uses server and
WebAssembly together. We start out with server so that
the app loads fast while we download the Blazor WebAssembly
run time in the background. Then once it's
downloaded and loaded, we can then switch to using
that run time locally. >> Go ahead. >> I have a quick
question on that auto render mode because I
honestly didn't understand. It's stringing the WebAssembly down. Does it switch over
automatically or is it on next navigation or something,
that it's going to load? >> I'm going to let
Mackinnon answer that. This is Mackinnon's
feature actually, he's been doing a
lot of work on this. When does it actually
switch Mackinnon? >> If a component was already initialized with a Blazor
Server render mode, it will stay that way until
the component gets disposed. But after the WebAssembly
bits are downloaded, then new components
that are added to the page will start using
Blazor WebAssembly. You don't have this complicated
state transferring system that will switch a
Blazor Server component to a Blazor WebAssembly component. Once the WebAssembly
bits are downloaded, from then on, your components
will use Blazor WebAssembly. >> Got it, okay. >> Often this happens
on another page load. You had the components, they were using Blazor Server, the user comes back to
that page and now it shifts to Blazor WebAssembly. But it doesn't actually have to be a full page reload, right Mackinnon? If the component initially rendered
as Blazor Server and then you did something in the UI that caused that component to just no
longer be on the page. Then the Blazor Server circuit
can be cleaned up at that point, and then you do something else on the page that causes that
component to come back. When it comes back it will
actually be Blazor WebAssembly instead of Blazor Server
or even within that , that's possible too. The next time you
use that component, is the way to think about
when auto will do the switch. It will check to see is the
WebAssembly run time there? If it's there, then it will use it. Otherwise it falls back
to the Blazor Server. Let's look at the
template a little bit. I'm going to show some of the
new things in the template. It's got some new options, it's got some new
layout of the files. Let's see what we've done. Can
we switch over to my screen? Perfect. I have already downloaded
and installed.NET eight RC one. I've installed also the latest Visual Studio update that
just went out today, 17.8 Preview two, so make sure you get that. You'll need that to have a good
dot and eight tooling experience. If you're a Visual Studio code user, you can also use the C# Dev Kit
extension in Visual Studio code. Let's go ahead and try and create a new project and I want to
create a Blazor web app, let's go ahead and
create a Blazor web app. Project, that looks
like a good name. Here I want to point
out that we've got some new options that
are showing up in the template that we
didn't have before. First of all, we now have the "Use Interactive WebAssembly
components" option. This option will turn
on the ability to actually render a component using
the WebAssembly render mode, and we want to really push it
all the way down to the client. You could do this before
with our previous.NET 8.0 Preview releases but you
had to set it up manually. Now the template will
help you do that. We have the existing use
interactive server components. This is the one that will set up Blazor Server for you with
your interactive components. What's new is it's now
enabled by default, if you forget to check it,
no interactivity is working. Hopefully that will
become less of an issue. We'll just always turn on Blazor Server based interactivity because you've already got a Server, you might as well leverage it. Then lastly, we have
a new option for including the sample
content of the template. The counter page, the weather page, these are great and
awesome components but not every app needs a counter
in a weather component. This is basically the equiva***t of what we used to do
with empty template, we used to have a
separate empty template. We've decided just to make
that an option where you say, "Do you want the sample
content or not?" If you don't want it, just
uncheck this check box. It'll remove the sample pages and also it will remove Bootstrap so you can use whatever CSS
framework that you love. Whether it's Tailwind
or pick whatever it is that suits your fancy. Okay? >> Look like you've basically
answered Andy's question here. You're saying it's
there, the option for the empty template and
that's basically it, right? >> That's the option, yes. We do have the option
for the empty template. Just uncheck this
checkbox when you're done looking at the sample content, and you will now have
a more blank Canvas, shall we say, for
your Blazor web app. I'm going to create this project as it is with the
Server option selected. First, I'm going to leave
WebAssembly unselected so we can see what just doing Server looks like. You can see we get a
single very clean project and a few things are
different in here. One thing that's different
is that we now have a new folder layout for the
content of the Blazor application. I'm just going to get here. We
used to have this pages folder. It used to be top level, and then we had a shared folder. We've cleaned that up and decided, let's just go ahead and create a top level components folder and
all of your Blazor components will just live under
there so they're easy to find, easy to manage. There's nothing
semantically meaningful about this components folder
from the frameworks perspective, you could name this
folder whatever you want, you don't have to use this
folder if you don't want to. It's just a pattern and
a convention that we've decided to now start
using in the templates. We still have the pages folder where all your routable components live. It'll be under here. We'll
expand that in a second. We got rid of the old shared folder because really the only thing
that was in there was the layout. Let me expand these so we can
actually see what's going on inside. There you go. The shared is now just
layout and that's where we've got your main layout
and the Nab menu components. Those are unchanged but they're
just living in a different folder. I always thought shared was a
bit weird like sharing what? What are we sharing in that folder? Some people would put their just
random components in there, is like, oh maybe this is a place
I can just take components. Now you've got the top level
components folder for that, so hopefully that's a little
cleaner and more convenient. Here's our pages, same pages as before but we've renamed the files to
match their function. The names before were
a little obscure, a little unclear I would argue. The counter component
is the counter. We've renamed the what
was index thought razor to just be home because it's
the homepage for your app, which I think is nice because
that's how we talk about it. We don't usually say
this is my index page, this is the home page. >> That's a holdover
from MVC days, right? >> Yeah, it's an old
school name, I don't know. Maybe people will like
this, maybe they won't, let us know what you
think about these names. We know we're expressing
some opinions here, moving people's cheese a little bit. If you think it could be done
better differently, let us know. Then what used to be the fetch data component is now just the weather component
because that's what it does, it displays a weather page. It still shows patterns for
getting data and rendering them, but now I think it has a
bit more of a clearer name. Other things that are different. In App.razor, we've done
a bunch of work to clean up this file and make it simpler, easier to parse
what's going on here. Things that we've changed. First of all, we have
removed the Bootstrap icons. Those are no longer there.
Let me put my notes for show. I forget anything that
we've removed from here. Before we used to use this really old icon set
called local iconic, which I think has been
defunct for a while. Sorry about that, that we kept
shipping that for a while. We initially thought, "Well, let's switch to the
Bootstrap icons." Those turned out we're big. Luckily a little heavy
for the app size. Now we just have a few custom
icons that we include in the template when you check
the sample pages content. If you don't do that, then you don't get that
content and you can use whatever icon set you'd like. >> Those are just like
SVG static files and? >> It's just SVGs in the CSS. Pretty simple. >> Oh, in the CSS. >> The default Blazor error UI is
no longer in the app component, we've moved it over here
into the main layout. This is the little bit of markup
that will show up if there's an unhandled exception that gets detected when the
Blazor up is running. We moved into the layout because
you tend to need to think about how the AUI should interact with the rest of the layout
of your application, so that you can customize it and make it reasonable
for your application. If you're wondering where that is,
it moved over into the layout. Then we have simplified how routing is set up by introducing this template
routes component. This is not a built
in Blazor component, this is just a component
that lives in the template. If we go to its definition, we can see all it's doing is
setting up the Blazor router. This is a little simpler as well. You'll notice that we only have
a render fragment for found. There's no render
fragment for not found. That's because thanks to static server rendering
where we have proper as core endpoints for each of the Blazor routable
components in our app. The not found content of the Blazor router actually
just never gets used. You don't actually need it, so we've dropped it from
the template as well. Last thing in App.razor, I'm going to come back to routes
in just a second because there's some interesting nuances
to that component. But the last thing we changed
is the Blazor script tag. You'll notice that it no longer has the suppressed error
attribute on it. It used to be that with
Blazor components, we went out of a way
to try and keep you from putting script tags into what were historically always
interactively rendered components where dumb elements can
come and dumb elements can go. Script tags and components
didn't really make sense in the past because there was
no way to really remove them. If you had rendering
logic that said, "If something is no longer true, then don't render the script tag." Well, that wouldn't
actually do anything from an HML Dom perspective. But now that we support
static server rendering, script tags in the component is actually a very legitimate scenario, we're using it in the root app
component for the application. That error is no longer
there and so we've removed that suppress error
attribute from the script tag. You should still be aware of the
issues of using script tags. If your component is interactive, like if it's a Blazor
Server component or a Blazor WebAssembly component, you probably don't want
to have script tags in those components but we're
not going to prevent you, if you decide that's
what you want to do, the framework is not
going to get in the way. Now I want to go back to
this routes component, because this routes
component is interesting. Why did we introduce
this separate component? Yes, it makes the App.razor a
little shorter and smaller, but why not just in line, the Blazor router right
here in App.razor? Well, there is actually
a really good reason. The first question
you might wonder is, well, let me back up. The main reason is that we wanted to make sure that it's easy for you to enable interactivity at the root of the app instead of
just on a single page. Right now, with the
Blazor web app template, we really only enable
interactivity for one page. We turn on interactivity
for the counter. The counter has a button, you click the counter and the count goes up. That's where really the only on
click handler that's happening and that exists in the Blazor
web app template today. >> But what if you want to have
interactivity throughout the app, like what if you want to use
the Blazer client side router? If you want to have
interactivity in your layout, then you need interactivity to be at a higher level scope or maybe even
at the root of the application, which we think it will
be fairly common. This is basically the
way Blazer server and Blazer WebAssembly worked
in previous releases. We want to make that easy, and so that's why we factor things
into this routes component. If you want to, for
example, use Blazer server, you can just say at render mode, then render server right here
on the route's component. Now the whole Blazer Router and all the components that it
renders will use Blazer server. You're probably going to also want
to put this on your head out. I think Mckinnon is going to talk
about this in just a little bit, but to really make everything
in the app fully interactive, you want the components that live in the root component
to be interactive. Now you might wonder,
well why don't we just make app.razor interactive? Why not put the render mode
attribute right up here at the top? We just say what is it like at attributed render mode
server right here? Well, the reason is
is because you can't, the app.razor component, the root component from your
app needs to be static. It needs to render statically. It can't be an
interactive component, in part because of that
issue with the script tags. The root component is
the thing that really needs to render the Blazer script, and you can't remove script tags, so the root component really
can't be interactive. That's not a thing
that will be allowed. If you try to do that,
you'll get an error. We can't put it at
the root component. Well, why can't we just
put it like on the router? Why not just take the Blazer router, and stick it right
here, right in line, and then put the render mode attribute right on
the router component? The reason why that also isn't
going to work is because, well, when you make a
transition in Blazer from static server rendering to
an interactive component, the component parameters for the interactive component
need to be serializable, like that component might be running on WebAssembly in the browser. You need to be able to flow
the component parameter values to that component while
it's running potentially all the way on the
client in the browser. The router component in Blazer has render fragments
for its parameters, and those are not going
to be serializable. Rendering an interactive
component with non serializable parameters is
also going to generate an error, so hence the need for
the routes component. It provides a nice boundary between the static server rendering of our application and the
interactive rendering. That's why that's there. Hopefully, that will help people
who might have those questions. That's how we've
simplified app.razor. It's nice and clean. Any questions about that? I know
I went through a lot there. >> There's a bunch of questions. Do you want to rip
through some real quick? >> We can. Yeah. Let's
go through a couple. >> All right. Let's see.- >> Did I break the app
there? All the changes- >> One question you showed using
Visual Studio to create the app. Is there CLI switches
for all that stuff? >> Absolutely, yes. You can do everything
CLI, first with.NET. Let me see. We get a new
Windows terminal up here. If I want to create a
little bigger, there we go. Let's go to my desktop
and I will do.NET New Blazer is the short name for
the new Blazer Web App template. We had Blazer server. Blazer WASM I think was
the Blazer WebAssembly one ,.NET New Blazer will
create a Blazer Web App. I figured that then you'll get the Blazer web app template
and it has options for server, use WASM. The same option. I think [FOREIGN] empty it looks like I have a new Get feed that I don't have
authentication support for. I need to clean up my new get feeds. It has the empty
option on it as well, so all the options that we
surface in Visual Studio, those will be available
from the CLI as well. >> Okay. >> You're a Mac user
and you don't have a full visual studio template
creating experience or Linux user, you'll be able to create
a Blazer Web App. >> Okay, let me sea few questions
on the switching betweens. How does debugging
experience work when switching between server and WASM? >> Good question. We
already support this today. The Blazer WebAssembly code that's running in the browser on
a WebAssembly run time. We support debugging that code, and the way that's done is through
some very tricky, fancy stuff, we actually go through the
Javascript debugging protocol, like we have to
connect to the browser through the Javascript debugging
protocol, and in the middle, we stick a.NET debugging
proxy that will augment the Javascript
debugging protocol with dot net specific
concepts that allow us to understand what's happening. From a.NET perspective, we have that and at the same
time you can also connect the normal.NET debugger
to your server process. Visual studio can connect to both of those things
at the same time. You should be able to hit
breakpoints and inspect code, whether it's running on WebAssembly
or running on the server. We should probably create
one of those projects. So far I've only created
a server project. >> All right. >> This is interactive.
Like you can see that I can click the button,
the count goes up. That's using Blazer server
for the counter page. Just the counter page. The homepage is static server rendering like this is
just sending requests, getting content and rendering it. There's nothing interactive
about this page, and then on the weather page, we've got the weather table. You might have seen
there's that little delay. Before the table gets
rendered, you click "Loading". Why is that happening?
That's streaming rendering, that loading dot dot is
simulating like doing an API call to some proper weather surface to
actually get the weather data. It takes a minute, but we get
pixels on the screen immediately, and then a half a second later you actually see the weather content. That delay is totally
simulated by the way. Like if you look at the
weather component down here is where that's being done and it is literally
just a task dot delay. [LAUGHTER]. The weather page is slow
and you're wondering why. It's because we put
a task dot delay in your template code just to
demonstrate streaming rendering. >> That's not making an API call, that's just directly on page. >> It's not making
an actual API call. The key aspect here
is that it is async, like you're doing something
async that is long running. Blazer will render the
component immediately, when initialized gets called, it does some of the async work, so it immediately returns the task and Blazer will immediately render the component with
whatever state it's got. Initially we have no weather
forecasts and that's why we get the loading dot dot user
interface and then later when the task completes because our task dot delay is done
and we got all the weather forecasts as if we had
made an API call or done a database query or
whatever Async work it is. Then Blazer detects
that the task is now completed and we'll render
the component again, and that's when it streams and
update to the same response stream, like it's just one request. You made a request,
you got initial batch of HTML, and then
half a second later, you get a little bit more
HTML in the response. Blazer then takes care of patching
that into the DOM using that Blazer.web.script
that we saw in the. >> It's not like a web
socket or anything, it's just one long
HTTP response stream. >> One request. I mean, long,
it's like half a second. In this case, if you had really
long running Async tasks, it could take a while just like, but it would have taken that
same amount of time anyway, whether you were streaming or not. You would just have the user
sitting there looking at their blank screen wondering,
hey, is this working? What's happening? Why am I
not seeing any content yet? What nice thing about streaming
rendering is you can put Pixels in front of the user immediately while those longer running
tasks are happening, the normal request timeouts that
exist in SM core will then apply. If it takes too long,
then the server might decide this request
is having a problem, I'm going to end it
or maybe the client is misbehaving in some way, so I should kill this request to
save on those server resources. >> Yeah. Okay. >> Yeah. >> Those are all there. That's all the server side rendering
based features, both static server rendering and interactive server rendering
with Blazor server. Let's do Blazor WebAssembly
because that's a little different. Let's create a new project. Blazor Web App 2, and now I'm going to check
the checkbox to say yes. Give me some WebAssembly with
that and we will have both. Now, we can do both server and WebAssembly
interactive components. Let's go and create this, so now we don't just have
one project anymore. Now we have two projects and
this is a little different than what we had originally envisioned and set out to
do it with dot net eight. Originally when we were prototyping
things, we thought oh man, it would be cool if we
could put the stuff that's going to go
down to WebAssembly and the stuff that's going
to be on the server. Let's just put that all
on one project and we can use like multi targeting
to decide what builds for what and then you get a single project experience for
both WebAssembly and server. We ended up deciding for
dot eight not to do that. Why is that? Well, the reason is that the code
that you build for WebAssembly, you really need to think
carefully about well, how much code should go
down to the browser, what dependencies do
I want to go down to the browser like maybe
you have dependencies that have proprietary code in them or sensitive
code that you don't want to ship publicly to the Internet
with Blazor WebAssembly, that code those assemblies
will be available to anyone who then downloads them. When we tried to do that with a single project model where
we were using multi targeting, it was very difficult to reason about and control what got built for WebAssembly and what got
built for the server. It was just too easy
to accidentally like pull in a large dependency or some service specific code into the WebAssembly part of the built, so we kept those
separate just like we did with Blazor WebAssembly
and previous releases. We have a separate client
project that represents, this is the stuff that's going to
go down to the browser and then the server project is
the stuff that's just going to stay on the server. It does make a couple of
things a little harder, but we think that clarity
is really critical for people who are trying to build
this style of web application. If we look at what we got
here so that there is also a small workaround that's currently in the template
that is actually was not needed and
we'll clean it up, I'll show you how
to clean it up, but in the client project,
let's start there. We have a counter component. This is the counter component that's actually going to
handle the button click and increment the count and
you can see that it has been attributed with an
interactive render mode, and because we have both server and WebAssembly turned on we just went ahead and said you
know what, you've got both. Let's use auto, let's use the
goodness, the fancy new thing, so this counter
component will initially start with Blazor server and
then once the run time has been downloaded it
will switch to blazer WebAssembly the next time you
initialize the component. Now the workaround I was mentioning is that you may also
see wait a minute, there's another counter
component up here in server. Why is that there? This counter component
all it's doing is calling the client counter
component and it has the route and you can see it's got this little comet in here that this is a temporary workaround until we can actually discover routable components for static
server rendering that are in another assembly than the
main assembly which is funny because we have
that support in RC1, but we just didn't
update the template, so this was just a little something that didn't
quite get done for RC1. This will get cleaned up for RC2, so we'd actually don't need
this server counter component, so what I'm going to do to clean
that up, I'm going to get rid, I'm going to copy the route
and I'm going to move it over into the client
one and I'll show you how to do this the new way. I'm just going to delete now the server Counter component,
so we don't need it. It's going to come from our
client project and now in program CS here we can
see that this is where setting up support for server
rendered components and WebAssembly rendered components
is being done and then down below we actually
enabled the render modes. Down here is where I'm going to
make on that additional call to add additional assemblies
and this is where I can manually specify that
I would like routing to discover routable components from assemblies other than
just the assembly that this app component
is coming from, so I'm going to do typeof (Counter). Assembly, so we'll have
the assembly there, so that should allow the server project to find my
counter in the coming project. >> If I've got a
bunch of components, I'm not going to need to say that for counter and weather and blah, blah, blah, there's a way to
say like go get them all? >> You'll have to do it for
each additional assembly that you have routable
components in, but you only need to do
it at the assembly level. You don't need to do it at
like a per component level. I'm just using the counter
component here because it's a convenient way to get the assembly
where that component lives. >> Cool. >> That should now be it and
let's go ahead and run this. Let's see if it's working properly. Cool, so now we've
got our new web app. Now before I go to counter, let's go ahead and
bring up the deb tools. Let's see if we can see auto
in effect with this template, so let's look at all requests
and that looks good, so I'm going to go to
the counter component now and we got a whole bunch of
stuff that's being downloaded, so first of all do we have
any WebSocket connections? There is the Blazor Server
WebSocket connection being set up, so this should work. I can click counter is working. Do I also have any WebAssembly? I got a whole bunch of WebAssembly
now. What is up with that? Well, first of all let's
just search for dotnet, so here's the actual dotnet
WebAssembly run time. It's now called dotnet.native.wasm. I got renamed in dotnet and
actually don't know why, but it used to be just dotnet.wasm. The runtime folks needed to give
it a new name, so what they did. That's the actual run time, so what is all this
other WebAssembly that's being downloaded
like all these guys. Well, in dotnet we've introduced this new web friendly packaging
format for your assemblies called WebCIL I'm going to call it which is we took the dotnet
assemblies and we strip off all of the native window
executable stuff from them, like DLLs are based off of the Windows portable
executable file format and when you're running
dotnet assemblies in the browser using WebAssembly, you're not running them
natively on Windows, you're running them
on the web platform using a dotnet run time
built for WebAssembly, so you don't need any of that native Windows executable stuff and actually it's
problematic because a bunch of like highly more restrictive
environments will see like wow, that's a Windows DLL. It's being transferred
across the network. Why is that happening?
Let's just block that. We'll then block the
DLL transfer and then your Blazor WebAssembly
app doesn't work because of security software
getting in the way, so we've repackaged
the assemblies now, so they no longer have all of those like somewhat scary looking bits. To be clear all the code in a Blazor WebAssembly app always runs within the security
sandbox of the browser. It cannot run natively on the device because the web
platform won't let you [inaudible] But this just like avoids looking like you're doing something more nefarious than
you're actually trying to do, so that's what's happening there, so we've now downloaded also the dotnet WebAssembly run time and
the app bundle in the background. It's still using the WebSocket and I think we can see that if
we like bring up the WebSocket. Let me clear all these messages
and if I click you can see the binary messages
are flowing across that WebSocket as we
use Blazor Server, but now if I refresh this page, let's go ahead and do that. >> This WebSocket people are like, why is there another
WebSocket there? You can see over here, this is actually some visual
studio tooling that's kicking in. This is how we do hot reload
and CSS Hot reload and stuff. You still see a WebSocket that's not because Blazor is
using Blazor server, that's just part of the tooling. >> Static 101, so 100 is continue. I don't even remember what 101 is. >> 101 is the upgraded protocol. When I want it to go from just HB to an actual WebSocket protocol,
that's how you do the transition. We should now be
running on WebAssembly instead of server. Can I still see? I don't even see the Blazor
server connection anymore, but is that because I cleared it, Mackinnon actually? Maybe
I've cleared it by accident. >> It's because you
refreshed the page. >> Oh, yeah and we got a new. I didn't have preserve log. One thing to note is
that in.NET 8 RC1, when you're done with Blazor server, the circuit will actually
still stick around in RC1. We haven't done the logic
yet to clean it up. Once all the Blazor server
components are gone, we ideally should then just
clean up all the circuits. In RC1, the circuit
will actually still just stick around while
the app is running. In RC2, we are doing the clean
up work so that you only have the circuit live while there are Blazor server components
that are active on the page. We've just switched from
server to WebAssembly. That's the auto mode. From here on out now
that we've cached the.NET runtime and the app bundle, it will use Blazor WebAssembly
from here on forward. >> Cool, wow. >> Now, things to note, when using WebAssembly, the code that you want to run in the browser needs to be built
from this client project. While it's really easy to
take a component and say, hey, I want you now to be
a Blazor server component. Remember what we did
with routes where I just went to app.razor and just added render mode right
here? That was really easy. It's very easy with server when you want to then switch to WebAssembly. If I want to say at
rendermode WebAssembly. >> It says, renderserver
it should say rendermode. >> Okay, thank you. Well, let's say I want to do that. Well, this component right now
lives in the server project. >> Yeah. >> It doesn't live in
the client project. So when you make a transition
to WebAssembly or auto, you will have to move code around. You'll have to move the routes
component into the client project. Now in.NET 8 RC2, we will provide another option on the template that helps you do that. If you want your app to be fully interactive at the root
and you want it to be maybe server or maybe WebAssembly. Making it WebAssembly means moving that code into
the client project. We'll provide a template option
that just does that for you. But if you have your own components, like a little island of
interactivity on a page, and you start you
initially thought, oh, that should be a Blazor
server component, but then you change your mind. That will mean doing a
little project refactoring. You'll have to move it into
the client project so that it gets part of that build.
Something to be aware of. That's the new Blazor
web app template. I think I've hit all the new
goodies that are in this project. Yes. I think we've touched them all. There's other stuff
that's new in RC1, I'll just say the top two briefly because I know we've
got some other stuff that Mackinnon is going to show. There's improvements to routing. We've updated the
Blazor router to now use the same implementation as the ASP.NET core router. That means a bunch of
features now light up for the Blazor router,
like default values. All of the built in route
constraints are now supported in Blazor pages and complex segments, like if you have a pass segment
that you want to have be partially a route value and
partially just a fixed value. That's now supported in
Blazor's routing system, whereas it wasn't before. There's been some nice
improvements to QuickGrid. This was actually a community
contribution from Elder James. Thank you, Elder James.
Wherever you are. He added a feature where the
QuickGrid component will now pass through any
additional attributes to the underlying rendered table. He also added a feature
to the form validation, where you can now easily check
if a field is valid or not. Let's see what else. There's some
new runtime features as well. There's a new trimming feature
for people who are doing ahead of time compilation where you can
now trim down the.NET DLLs, well, the Web CILs that get
shipped with your application. Before we needed both the
pre-compiled Wasm and also still needed the.NET assemblies for cases where we had to fall
back to the IL interpreter. We will now do trimming on those
assemblies to remove unused code. There's a new option that
you can try out for that. There's also a new runtime
API for configuring the.NET runtime with various low
level runtime features. Like if you want to change the
virtual file system path location, or even simulate environment
variables from the browser. There are a bunch of low
level.NET runtime APIs in Java scripts that you
can use to do that. Those APIs are now
available for Blazor apps. Lots of good stuff. Mackinnon
is looking at me like, Dan, we have other stuff to talk about so I'm going to
go ahead and stop here. >> I know. >> Go and read the blog
post and give it a try. Mackinnon, I think, now is going to must be a little bit more
detail on [inaudible]. >> I have a question,
because we've got 20 stared questions queued up. I wonder if we could go rapid fire on some of these before
turning over to Mackinnon. Because I know Mackinnon
is eager to get going, but I do want to get some
while they're still topical. >> Let's do it. >> How about I'll run through
and any that you want to pass on for now we'll get
to later or something. Cool. Let me see one. Is there a remote development
container? I'm not really sure. >> A remote development container. I mean are they talking about like? >> Depth container
maybe or codespace. >> Code space thing, maybe. I don't know. I would check the.NET 8 blog post. The top level one, not the ASP.NET core
one but the one for the broad.NET 8 RC1 release and
see what they list there. I can't remember off
the top of my head. >> Okay. >> We do ship container images
for.NET 8 with each release so there definitely are
docker container images that are available for.NET 8 RC1, but for remote
development container, I'm not sure of that one. >> Okay. This one I
think you answered here, interactive Wasm component still on a separate project.
You did show that. >> It does too. For.NET 9 we'll look again to see if we can get to that single project model. But for.NET 8, yes, you will
need a separate project. >> Cool. Is there an
option for Core hosted? >> That's that new option, I was talking about that in RC2, we will add an option
that you can make the route of your Blazor
web app interactive. That will then give
you the equiva***t of the old Blazor server template and the Blazor WebAssembly template with the ASP.NET Core
hosted option checked. That's what we'll be adding
in the next release. Not in this release, this release, you have
to set that up manually. If you want to do the semantically equiva***t thing for ASP.NET Core hosted
Blazor WebAssembly app, that's a long phrase, you can do it, you'll just have
to move the routes component, set its render mode
to be WebAssembly or auto and all that stuff in order
to get things in the right place. I do have a sample
project that I've been migrating forward
with each of the.NET 8 previews to show how to do that. In RC2 it will get easier. By the way, if you have an existing Blazor WebAssembly
app or Blazor server app, you don't actually have to change anything to get it
to work with.NET 8, you can just change the
target framework version, update the packages, and it should just work. If it doesn't, let us know, because that should just work. If you then later decide, oh, I want to try some of these
new features that are available only with the
Blazor web app model. We will then provide
you guidance on how you can shuffle things around a bit to use those new features, but it's not required.NET 8 is absolutely backward compatible
with existing Blazor apps. >> That's a really key point, I always talk about that. You can just update. You don't
have to use the features. You can just update your version and you run faster
and you get better, things light up if you want to
use them, but you don't have to. Cool. Let me see. Is data transferred or if so, how between server and Wasm? >> Do you want to speak
to this Mackinnon? >> Well, there's another
question here too on Flux or just state
management in general. How do you folks think about that? >> I can take a step. When you transition that component
from server to WebAssembly, there's nothing that
will then capture state from the server and shuffle
it down to the client for you. We do serialize the
component parameter. The component parameters are the main interface for
how data will flow. Whatever you pass as
parameters to the components, that data will then be available to that component regardless
of where it's rendered. That's why they need
to be serializable. But if you had some
state that you were maintaining while it was a Blazor server component and
then the component goes away, well, that state is
effectively gone now. Then you come back to that
component and you're like, oh, no, I wanted that and I want it
now over on the browser. Those are all exercises for the developer to figure out
how do you want to do that. Blazor in general is fairly unopinionated about how you
manage your component state. It's a class with
fields and properties. There's the DI system, you can put state and services. There are cascading values and parameters where you can cascade
state down through components. But we're not prescriptive about which pattern you use and
how you use those tools. Some people like the
state container patterns like Redux or Flux and there are.NET versions of those that
you can use with Blazor apps. Some people like the
MVVM pattern and you can implement an MVVM pattern with Blazor if that's
what you want to do. But it's not like something that's prescribed by the framework.
We just saw that. Was it Ingus or the framework
from the community? It obviously has a reactive
model for dealing with state. The sky is the limit. We're not prescriptive about it. You do have to decide what works
best for your application, for your development team,
for your team culture. >> Cool. A few more
real quick ones here. If you've got an existing Blazor
Wasm app, can you use SSR? >> Yes. >> Yes, so actually technically
you can do this today. You can already do
it because we have the component tag helper which can do static server rendering from a razor page or
from an MVC view. You can set up a Blazor WebAssembly
app today to do prerendering. We don't do this by
default in the templates, but we have docs on how you can render your Blazor
components from the server and then set them up for interactivity with
WebAssembly on the client. That's how you would typically handle that with a
Blazor WebAssembly app. You can have static server rendered Blazor components that sit beside your Blazor
WebAssembly app as well. You notice I had that map
Razor components call, which is what's rooting looking for all the routable
components in the app and making them available as pages. You specify which root component
you want to use and the assembly, where you want to find
those components. That can live right alongside an existing Blazor WebAssembly
app that's using the old Blazor WebAssembly.js
file. That should work. Yes, you can. If you want the seamless transitions and the
new progressive enhancements, then you'll want to take
that Blazor WebAssembly app and start to massage it into the new Blazor
web app patterns. >> Cool. I'll do two
more quick ones here. Minimal API with Blazor, would that be a separate project, and you just make an HTTP client in your Blazor
app to call back into it? >> The server project is
an ASP.NET Core project. Blazor is part of ASP.NET Core. In your program CS file, you can configure whatever
endpoints you want, including minimal API endpoints, NBC controllers, Razor Pages, they can all live together in
the same ASP.NET Core project. It's one happy web framework. >> Like you said with
routing being united and all that it's one system now. Cool. Last one. This is near and dear to my heart. If you've got an Azure
Static Web static app, do you just continue to do Blazor [inaudible] with functions
on the back end? >> Great question. I
love this question. Static web apps is
for a static site. It's basically a bunch of
files that are going to be put on a CDN and
globally distributed. Standalone Blazor WebAssembly apps where all you have is
Blazor WebAssembly, you have no active server
piece to your app. Those can be hosted on
Azure Static Web apps. We actually are going
to continue to ship a Blazor WebAssembly
standalone app template, specifically for that scenario
where you want to be able to publish a Blazor app to a
static site hosting solution, like Azure Static Web Apps. The Blazor web app template is
oriented around the idea of, hey, I can give my users a much
better experience if I can leverage the server to do cool stuff like static
server rendering, streaming rendering, these enhanced
navigations and form handling. Interactive modes like the
server interactive mode, where I'm leveraging the server
to make things load faster, feel faster, feel smoother. With Azure Static Web apps, the static site hosting
part of it obviously can't host an ASP.NET Core
application by itself. You can't do that just with
Azure Static Web Apps. Now Azure Static Web
Apps does also have this feature where you can bring
your own back end with it. Where you can pair it with Azure App Service or with
Azure Container Apps, and you use both together
as a single solution. We think that will be one way that
you could do a Blazor web app. Definitely the
simplest thing you can do is just take a Blazor web app and publish it to Azure App Service, and that will definitely work. Azure App Service can
host ASP.NET Core processes in [inaudible]
and all that stuff. You're basically then just taking the WebAssembly part and hosting it as static files from
within that app service. Being able to then break, pull
that just the client part out, and put that on Azure
Static Web Apps with the rest of it living on Azure App
Service is something that we're actively talking with our
friends on the Azure team about how we can facilitate
that, make that easier. With a server project, you're going to need something
that actually can run a server. >> Last question, and
hopefully this is something McKinnon is going
to be covering or something. But is there authentication? >> I'll talk to this. In.NET 8 for ASP.NET Core we have
the new ASP.NET Core identity API endpoints that allow you to programmatically
interact with identity, so for logging in users, getting a token, or
setting up a cookie. All the identity flows like password
resets and all these types of things are now manageable using
the Identity API endpoints. For Blazor, we are also trying to build a identity UI around that functionality
using Blazor components. That work is happening right now. McKinnon is nodding
his head because he's been directly involved
with this effort too so that we can then include hopefully that code in the
template. It is coming in hot. RC2 is the last preview
release for.NET 8. But as far as last we talked
about it earlier this week, it is on track and we're
still planning to add it. Having an integrated Blazor
experience for the new of story that's in the
next candidate release. It is not available
with the current one, you'd have to manually
construct it yourself. >> I think with that, I should turn it over to McKinnon and let him get going. You're ready? >> Sounds great. I'm ready. Yes. Awesome. Today I'll be talking about Blazor
Static Server Rendering. What's new, how it works, and what I, or you the developer,
should do about it. The reason I'm doing this
topic is because in.NET 8, the capabilities of Blazor
are elevating dramatically. With that comes a lot of new content to learn a lot from
your functionality, but also maybe some confusion
and ambiguity as well. This presentation is about clearing
up some of the nuances about how static server rendering
works and how those actually impact the way that
you build apps using Blazor. Before I jump into the main content, I want to clear up some
terminology that I'm going to be using in this section. One is static content. When I say static content, I mean static from the
perspective of the browser. It's content that
doesn't change after it's initially loaded or
rendered on the page. Typically, static content yields faster load times because you don't have a bunch of JavaScript
or WebAssembly that has to load and present the
content on the page. The content is just being displayed directly by what the server returns. >> Some examples of
frameworks that took this approach are
Razor Pages and MVC. We also have interactive content. This is content that's
dynamically updated by client side logic that's
running in the browser. This is capable of
reacting to user input and changing content on the page without having to fetch new
pages from the server again. Some examples of this
are Blazor Server and WebAssembly components. Another thing I want to clarify
is static server rendering. This is a term that I don't
think we've used before today, I think publicly, what
I mean by this is rendering static content
from a Blazor endpoint. This is not to be confused
with the Blazor Server, which allows you to render
interactive content where your code is still
running on the server, but it's using SignalR
to update the page without doing HGP requests to update the page content. >> I think static rendering
appears in our code. We have APIs that call
it static rendering. For .NET 8, me in particular, I was using the phrase like server side rendering often to talk about what here we're referring to as
static server rendering. The problem with calling it
server side rendering was, well, what kind of server
side rendering do you mean? Do you mean the Blazor Server kind, or do you mean the static kind? It was unclear. I think it is good as a new term that
helps makes it clear that we're not talking about the Blazor Server version, we're talking about just
rendering to the response. >> It looks there's a comment that has come up about that as well. It's weird to call it SSR, but then say static
server rendering. Yes. Because server side rendering could mean two different
things in Blazor because we already
have Blazor Server which provides interactive rendering but it's still running
on the server. That's where this
clarification comes in. >> Kristopher, I'm
with you initially. I originally thought, well, a lot of the other frontend
JavaScript frameworks used the term server side rendering to refer to the pattern that we're now implementing with laser components in .NET 8. So let's just use that term. Let's just re-use the
existing industry term. But they don't have this problem. Most of the frontend
JavaScript frameworks don't support interactive
server side rendering. When they say server side
rendering, it's very clear. Well, it's the non-interactive kind. We have this unique feature which is the ability
to make a component interactive from the server. We need some way to
clarify that we're talking about either the interactive version or the non-interactive version. Static versus interactive is the current thinking on
how we talk about that? >> Exactly. I think we've
clarified that. Let's move on. Another thing I want to do,
I'm talking about this, is try to call out the
similarities between what exists today and what
is coming new in .NET 8 because there are a
lot of similarities and I think clarifying
what those are can help people understand what's actually going on better. It turns out that
static server rendering isn't really a new
thing in ASP.NET Core. This already how Blazor
apps worked in general. You have some static
content on the page, maybe this includes maybe
some meta tags in the head, and then maybe at the
bottom of the page, you have some footer or maybe the Blazor UI,
that static content. Once it's rendered on the
page, it doesn't change. Then the interactive content is where your Blazor
app actually lives, that's where your components
are getting rendered. That's the stuff that changes as you're switching
between pages in your app. You already have static
content that gets served, and then interactive content that lights up after the
initial page load. An example of this is
Host.cshtml in Blazor Server. In this case we're
using Razor Pages. This is a Razor Page right here. This is all static content. Once this is on the page,
it's not going to change. But then we also have the
component type helper, which allows you to add
interactive content to the page. It's following a similar
pattern where you render from the server and then
later interactivity starts up. This pattern is true not
just for Blazor Server, but for Blazor WebAssembly too. If you have a static site, you have some index HTML file, and then after that gets
loaded on the page, your WebAssembly app starts up. You make some call to, I don't know, something.recomponent.add
to add your re-component and then you get interactive
rendering via Blazor WebAssembly. >> Builder or something?
WebAssemblyHostBuilder, I think it's WebAssemblyHostBuilder. >> Yeah, WebAssemblyHostBuilder.
That's it. Then, now we have this new thing, the Blazor web template, and this follows the same pattern. You have static rendering from your app.razor file and then
you specify somewhere in the component
hierarchy a render mode to indicate the transition
to interactivity, and then interactivity
is carried out, either using Blazor Server or WebAssembly. The cool thing about this
last approach though, which is the new thing,
is that it's all Blazor. You don't have to use two
different pieces of technology to get service side rendering and client side
interactive rendering. What are the advantages of
doing things the new way? Well, one is that you get a
unified way of doing things. It's a single technology stack. You're not mixing Razor
Pages with Blazor and you don't have to worry about slightly different syntax and it's just a consistent
developer experience overall. If you have Blazor libraries, you can use them for service
side rendering if you want to. You don't have to worry, it's
just less stuff to learn overall. Also, you get to
utilize the benefits of both Blazor Server and
Blazor WebAssembly. This is something that Dan actually demoed a little bit earlier with the auto render mode. Blazor Server has the advantage that it generally results in
a faster page load time, like the time to interactivity
at least is smaller. But the disadvantage
is that it requires a constant connection to the server. If you lose that connection, then you lose interactivity in your app. Blazor WebAssembly
on the other hand, it takes a little bit
longer to load initially, but once it's loaded, you don't need a
connection to the server so you're not putting extra load on the server that
you might not want. The auto render mode is great because you can use
Blazor Server at first while the WebAssembly bits are downloading in the background and then switch to WebAssembly to alleviate the server from controlling how the app is rendered. Or if you want to use
both on the same page, maybe some components only work with Blazor Server and similarly work with
Blazor WebAssembly, you can do that as well.
There's a question. >> Let me try and
guess the answer here, but we had historically
two different models. Now we have one unified model. I think the scenario
now we'd recommend basically for everybody
is use the new unified. If you're new to all this, just use the new model. >> There might also be
some aspect of this which is also, like even
within the unified model, there are a bunch of
ways of doing things. I could do static server rendering, I could do Blazor Server rendering, I can do Blazor
WebAssembly rendering, I could pre-render things. It is a lot to reason about and I'm very sympathetic to that additional complexity. In our role as framework
designers and developers, we are trying our
best to make it easy for people trying to build
the best app possible, to use the appropriate architecture that's going to make sense
for your application. With modern web apps, there are nuances and complexities that are now part of the
app development experience in order to make that
app as good as possible. Like should I be using streaming
rendering in this page or should I be handling everything from the client? What should I do? There's not really, unfortunately, one pattern that just fits it all. You often see these arguments on various websites
where people will debate about should you do
everything on the client, should you do everything
on the server? They'll have all the frontend
JavaScript developers arguing with all the
backend server developers who are used to doing
server side rendering on which one way is better. Reality is that both
of those techniques have appropriate places in an app and it's part of the
app designers job to figure out, well,
where should I use each of these features so that my app experience is
as good as possible? Can I avoid having
that loading spinner on my banking website while you're downloading a
giant JavaScript bundle? Would that have been better if I had just done
server side rendering or static server rendering for setting up that initial content? These types of user
experience concerns, unfortunately, involve a
lot of these decisions. We're trying to make
the features available and we know we have work
to do to provide docs and guidance on when
should you use what? How should you think about when each render mode
is most appropriate? >> Cool. >> Absolutely. I hope
that later in this talk, I'll be giving some demos. Hopefully that will
clarify some examples of, when would you want to
enable interactivity on a page or for a component? What are some of the things
that you could run into? But just covering this last point. Another reason to do
things the new way is because we have really nice server side rendering
features coming to Blazor, including something called
enhanced navigation and enhanced form posts
and streaming rendering, which makes your service
side rendered app feel more a spot even
though it isn't. I will get into that deeper later to hopefully clarify
exactly how that works. There are two topics
that I wanted to talk about today and I picked these based on issues that we get
in the ASP.NET Core repo. We get some issues
that indicate that there is a lack of clarity with how some of these things work, with how render modes work, and then how enhanced navigation impacts the functionality
of the app. These are two topics that I'll be going a little bit more
in depth with today. Let's start with render mode. What is a render mode? It just describes how a
component gets rendered. An example could be a component is rendered statically
from the server. It could be a component
is rendered interactively using Adobe Blazor like
Server render mode or using Blazor WebAssembly. The render mode is just how a component gets
rendered on the page. When you use these new
API's map Razor components, the root component starts with an implicit static server
render mode at the root. So if you don't specify any
render modes in your app, it's going to be a static
app all the way through. Then on a component subtree basis, you can enable interactivity. If you have a page or
a certain component that needs to be interactive you can enable interactivity
on a case by case basis. I'll show an example later of how you might realize
that a component needs interactivity and
then go and enable it. But just keep in mind that
static rendering is the default. Going from rendering
statically on the server and rendering inactively
is what we consider crossing the render mode boundary. The reason it's a
boundary is because your code is running in
two different places at two different times even
though it's in the same app. When you render statically,
your Blazor code is only a live for as long
as the response last. Once the response is complete, your Blazor code is
no longer running. After that interactivity can start. >> That's the more long running Blazor state in your app, I guess. But I'll talk more about
that later as well. Then another thing is
at least for a.NET8, the interactive render mode
of sub-tree can't be changed. You can't say of transition from the server to the
client using Blazer Server. Now you want to render another sub-component or another child component
using Blazor WebAssembly, that isn't something we
support at the moment, but we do support having
Blazer Server and Blazor WebAssembly components on
the same page at the same time, as long as they are the first render mode after
transitioning from Blazer Server. >> Siblings can be different. >> Yes, but once you're interactive, your children have to use
the same interactive modes your child components. You'll get an error if
you try to nest like a WebAssembly component instead of a Blazer Server
component, for example. Let's do a quick demo
of how this works. What we have here is this is a
project created from the template. It had server interactivity enabled, but I've commented
out all cases where we actually use
server interactivity. What I'm going to go
ahead is first run this app and show how the app
behaves as a fully static app. I'll opened on my other screen here, but you can see it's the template
we're all familiar with. You've got the Home page, the Counter page, and the
Weather Forecast page. If I go to the Counter page and
click the "Click Me" button, you can see it's not incrementing, which might be surprising, because if we go to
the Counter page, you can see that we have
an onclick handler. Why isn't the onclick handler
running in this case? The answer is because
our Blazor code isn't even running at
this point in time. It only runs to serve
the page initially, and then after that, there's
no code to handle this click. What we need to do in
this case is make the app interactive in order to code
that runs on the client, to be, to be able to react
to those click events. What I'm going to
start with is go to the app component and I'm just going to make the routes
component interactive here. We can say rendermode
= RenderMode.Server. This is using Laser server render mode and I know it might be
confusing because you might think, wait a minute, I thought server
side rendering was the default. Well, static server
rendering is the default. RenderModeServer means interactive server rendering
and you can see that from the XML docs that come up here. >> One of the changes
we're considering actually before we finished.NET8 is should we rename server
to be something like interactive server and change the render modes to make it clear that which ones are interactive or not by putting interactive in
the name, that might help. It's looking like we might
actually try to make that change, but we're still discussing it. >> I'll go ahead and
run this app again. What we can see here is if
we go to the Counter page, we can click and the
counter now increments because we have code
running on the client. It's still running on the
server, but it's interactive. Our code is still active even
after the response completes. It does that using a WebSocket
connection as you can see from the console here. But what's interesting
is that even on pages where we don't need interactivity, the connection is still in
use and it's still alive. If we actually go to
the "Network" tab and I look at the
WebSocket connections. You can see that even though we're
on the Weather Forecast page, we still have the Blazer
Server connection. If we click around,
you can see messages coming through as I
click through the app, even though the Weather
Forecast page and the Home page don't need to be interactive, this is unnecessarily wasting server resources by keeping
this connection open. What we should do in this
case is just to make the Counter page interactive. We can go ahead and
remove this here and the Counter page will add
attribute[RenderModeServer}. What this is going to do is now
the connection will only be active when we're on
the Counter page. If I pull this up again
and pull up the console, I can go to the Counter page
and you can see as soon as I navigate now the
connection starts and now the counter is interactive
and if we click back to the Home page and wait
a couple seconds, the connection disconnects. This isn't actually something
that's available yet in RC 1, but in RC 2, this
will be the behavior that you observe when the
circuit is no longer in use. When that website connection
is not being used anymore, it gets disconnected and your app is fully static server rendering. >> Is this the actual
RC 2 implementation? >> Yes. >> We're seeing RC 2 bits right now. That's the first time
I've actually seen that work in the RC 2 bits. That's cool. Well done,. >> Yes. It's looking into
the future, I guess. >> One question again that I think
people ask is when you rendered the counter component statically initially and it just didn't work, I think some people
might wonder like, why didn't you tell me, why did you let me fail, why don't we provide an error
or a warning in that case? >> Well, so there might be
times when you have a component that you want to work with static rendering or
interactive rendering. It's totally valid for example, if I were to pull the counter functionality
into a separate component, maybe I want to be able to still
render the "Counter" button, but not have it be
interactive in some cases and then let whoever renders the component decide if they
want it to be interactive like we did with the
routes component here. It's not necessarily an error to not have onclick
handlers be available. >> Actually by default we render all interactive components
statically at least once. Because in.NET8, all of the
interactive render modes, Server, WebAssembly, Auto, they all have pre-rendering
enabled by default. Like the initial request to that app dot Blazor component will statically render
everything into the response which then
sets up the script tag and that's what then will trigger
interactivity to be enabled. But everything had to be
statically rendered as part of that pre-rendering step and you
don't want that to be an error. That's why you don't
see a warning error because we don't know like, you might also be rendering it and that might have been
absolutely the intended behavior. >> Totally. Actually
that's something that we've seen people
get confused about. Here I've just override
the uninitialized method, and then I'm just going to output the console initialized like
the component was created. What we can do now
is run this again, and one thing that surprises people is if we go to
the Counter page and I'm also going to pull up the console here so you can see
what I'm talking about. If I go to the counter page you see that initialized
was lodged twice, which can be confusing because
we only see one counter here. Well, the first initialization was
when we were initially sending the pre-rendered content down
to the client and the second time was when the
interactive content or the interactive
component got initialized. There were two components created
at two different points in time, one during pre-rendering and one
after interactivity started. Likewise, if I were to implement
disposable in this component, let me go ahead and close this, then we would actually
see that it gets disposed once before it
even gets created as well. It'll get disposed twice
as well like once when you initialize the page and then once
you navigate away from the page. >> Two instances of that component, like you get an instance created while you're doing
pre-rendering and then you get an instance created for
the actual interactive mode. Like if it's on WebAssembly though those two instances live in
completely different processes. In Blazer Server, they technically live
in the same process. Right now, it is still two
separate instances even if it's pre-rendered and
then Blazer Server, I think we still have an item in
our backlog to look at, like, could we do state full
pre-rendering where we actually somehow maintain
which component is used. It has some complexities
associated with doing that. Right now, it does still
create two instances. >> Absolutely. Another thing that we've seen people get
confused about understandably, is let's say I wanted to make the current count in this component
reflected in the page title. I'll just say, counter and
then current counter here. Intuitively, you
would think that this should work because of
course, like I wouldn't it. But if we go and run the app, you go to the Counter
page and click, we can see that the counter is still listing zero as
the current count, even though in the main content of the app we can see
that it's incrementing. Why is that happening? The reason is because
the way page title works is it uses a
new feature in.NET8 called sections and
this allows you to from one component rendered to a
completely different part of the app. In this case we have
page title which is going to be rendering to
the head outlet component. If we go to App.razor, we can see our head outlet is
placed right in the head over here. But we don't see is an interactive
render mode specified. What's happening is the head
outlet is getting pre-rendered. It's showing the initial page count, but then after the counter starts up as being an
interactive component, it's going to look for an interactive head outlet to
render to and there isn't one. That's why the page
title doesn't update. If you want to have an
updated page title, we need to have both
the component that's up into the page title and the
head outlet itself be interactive. I'll go ahead and
specify rendermode = RenderMode.Server and that will
allow the counter to increment. If we go here, click "Enter", then we can see that it's updating. However, one thing to
keep in mind is that by making the head
outlet interactive, we've just made our
entire app interactive because the head outlet
is present on every page. If we go over to the
Home page again, you can actually see that
the connection is no longer disconnecting because
the circuit is still in use. Something you want to be careful
about when you're working components for interactivity is that they're not
interactive unnecessarily, like you only want the parts
of your app that have to be interactive to be interactive and that will result in the
most efficient app. >> This is going to be interesting
I think because the idea of scoping interactivity
in the app so that you can reduce resource utilization, you reduce the burden
on your server, those types of things, I think is very
appealing but it does also seem like it's very easy to get to a state where you're
really just going to need the whole app to be interactive. If you want any interactive
features in your layout like the head outlet
or anything else, then now the app's going to need
to be interactive from the root. We'll have both options available. I actually don't know yet which
is going to be most common. Are there going to
be people that find that for most apps that
can actually scope the interactivity in such a way
that it's useful and meaningful? Or are we going to find that
most people find, you know what, I'm going to need the whole
thing to be interactive anyway, so I'm just going to
do it at the root. I think that's an
unanswered question for us. Community, let us know what you find as you build apps and start
playing around with these bits. >> Yeah, great points. Jon is saying something
very important. >> Super and that's all I
have to say about that. I'm interested in this
because we used Blazer in.NET website in the live shows and this is something where I personally want to try and play with the
different models on this. How at the component level or, probably for that just a page level. >> Yeah, I think that's a
great example of an app that already exists
today that does have this island of interactivity notion. Most of the.NET website and dot.NET, it's all built on.NET. A lot of it is just
razor pages doing server side rendering and
there's some JavaScript. It's nothing it gets a little
bit added on those pages. Then we have the live.NET page, which uses Blazer and has, full interactive Blazer features. We're actually in the
middle of an exercise to migrate the whole.NET
website to just use Blazer. It will be interesting to see where, we end up having requirements like, "Oh, I run a little widget in the nav menu bar thing
of the.NET Website." And how we deal with those issues. Does the whole website end
up just being interactive anyway and leveraging auto mode? >> Yeah. >> Sometimes, I hate to say it and it's going to offend
some people out there, sometimes it makes sense just to put a little bit of
JavaScript right there because that's just a
lighter weight thing to do. >> That's a good point. Deciding to use Blazer doesn't mean you
can't use some JavaScript. You do have to be thoughtful about Don Management and all
that stuff, but you can. >> Yeah. >> There was one question
which I think is useful here. That example you showed on
initialized was called twice, and it is something you
need to think about. You shouldn't probably be calling an API necessarily on initialized, but it's something to think about, how your events are fired and that. >> Yeah. >> Yeah. >> You can't deal with that though. That is absolutely a pain point. You need the data. You're trying
to render the components. If you're getting the data
from an API endpoint, then you got to go get it. One thing that you might
wonder is, "Okay, well. When I get it the first time, can I just reuse it?
Why go get it again? Can I just save it someplace and then reuse it?"
The answer is yes. We have a feature for persisting,
the pre-rendered state. The state that you used to do
the initial pre-rendering, you save it into the page, basically gets embedded into the HTML so that when the
interactivity is set up, you can then just read
it out of the page again without making the API call, and you're like, "Oh, I
already got the data, I don't need to make another
API call, I'm good to go." That's a persisting
pre-rendered state feature that you can basically
have a little logic and non initialized that says, "Do I have a state already? No? Okay, go get it. Now, save it." Then when you check again, "Do I have it now?" It will find it. >> Yes, this is interesting from Damian here about
static components that weren't tied to the
overall app and render mode and share data between
the app and static islands. A lot of interesting
stuff. All right. >> We have a little bit more. >> All right. >> I'm going to move on to
the last section of this. That's about enhanced navigation. Before I describe what
enhanced navigation is, I just want to first talk about the kind of two types of
navigation that can happen. Someone is like a
traditional page navigation. If you have a server side rendered
site and you click a link, it's going to completely
reload the page, it's going to send
request to the server, the server is going to
respond with some HTML. All state in the page
is going to be lost, or at least all the JavaScript
or document state is going to be lost and replaced with
what the server returns. Compare that to a SPA navigation
that uses client side routing. When you switch pages
within the app, the client side logic determines what your
content gets displayed, and it doesn't require fetching
a new page from the server. As a result, JavaScript and DOM state gets preserved
across navigations. There's a lot less to load
when things work that way. But with Blazer, what we want
to do is have service side routing if you have a
static server rendered app, but then also be able to preserve
state across navigations. That's really useful for cases like, let's say you're building
YouTube actually, because YouTube does this I think, if you have like a mini video player in the corner of your app and you want to switch between pages
still within your application, but keep the video playing, you want that element to be preserved
across navigations, and that's what enhanced
navigation lets you do. It also lets you preserve
interactive components. If you somehow have an
interactive component that gets preserved across page navigations or that stays in the same place
across page navigations, then it will actually
retain its state rather than being obliterated and then recreated when
the page loads again. This is what enhanced
navigation is all about, it's all about sending a request to the server and then using
that to display the new content, but then making it feel
more like a SPA navigation. How it works generally behind
the scenes is it just does an HDP fetch for the new page
content and it does not navigate. It doesn't set window out
location to something, it just gets the new
content and then parses it as a document fragment. Then it runs this fancy algorithm
to compute a difference between the content that's
already on the page and the new content that's
coming in from the server. Then applies the minimal set of changes so that it
preserves as much of the existing DOM state as
possible, between navigations. This has many interesting
implications. One is to get faster, more
efficient navigation. You don't have to reload all the assets when you
move to another page. If they're already in
memory, they can stay there. We also get to preserve
document state, like what I was talking about with
the mini video player example. You also get to preserve
interactive component state. These are all great advantages. It also does come with some
other interesting implications, and that is, dynamic changes
to static content get reset. Let's say you had
some JavaScript that would add some content to the page, let's say it would add a link
tag for things like theming, like if you wanted to
link a style sheet dynamically based on
some like light mode, dark mode, theme setting. If you switch pages,
enhanced navigation will actually remove that
change because it'll say, "The new content coming
from the server doesn't have that link tag because
it was added dynamically." Therefore, that tag gets removed
and then you lose your styling. In.NET eight, this isn't available
in RC one, but at.NET eight, we're going to add a data
permanent attribute that lets you preserve DOM content
on a hierarchy basis. You can mark an element
as data permanent. You can do that dynamically, even
and then when you switch pages, that element will be ignored,
in enhanced navigation. You can preserve elements
through enhanced navigation. The other thing we'll
be addressing is that some page loading
mechanics are skipped. Let's say you had a
reliance on window.load, like the load event, when
you navigated between pages. Well, because enhanced
navigation isn't doing an actual page reload, that load won't run
when you switch pages, so maybe your initialization
logic will get skipped. Or maybe you wanted some inline script to run
when a page was loaded, but now that isn't running, because it existed on the previous page and
it's not going to rerun when you switch
to the new page. For that, we have enhanced
navigation callbacks, or at least we're going to add them, where you can listen to enhanced
navigation events and then run your page specific
initialization logic there. But these are just some
things to be aware of when doing enhanced navigation. We'll also have a way to disable enhanced navigation if you
need to in certain cases, or you can disable it globally, which I'll demonstrate in a minute. But we generally recommend
you don't do that because it's pretty cool. Yeah. >> Wow. >> Let's move on to the DEMO. >> What I'm going to do first is actually show what the
app looks like without enhanced navigation so we
can see why it's so great. What I'm going to do is just set this auto start
property to fault. This is going to prevent Blazor from starting when the
script tag is seen. Then I'm going to have
another script tag that starts Blazor manually. This is so that we can pass an extra option to disable
enhanced navigation. It's going to do
Blazor.start and then I send SSR options,
disableDomPreservation. >> For those of you who are like, wait a minute, Mackinnon, why
are you showing me JavaScript? I thought this was a Blazor,
a community standup. This is code before Blazor
has even started up. There's not even a chance. We haven't started
running.NET code yet. This is the bootstrapping logic. >> Exactly. If I run this, this is going to behave
like Blazor pages app. When we switch pages,
you see a little flicker there where we actually
do a full page reload, and I'm not sure if it's
coming up on the screen share, but every once in a while
you'll actually see a visual flicker
when I switch pages. You can see, if we go to
the Network tab even, let me switch to all, then you can see when
you switch pages it's reloading all the
assets on the page. They're cashed in this
case, so it's okay. But still it's doing
more than it has to. What we want to do is make it so that the only request
that's happening is for the page and nothing else,
just for the page content. Let's comment this
out and remove this. Now, I can show you
what it looks like with enhanced navigation enabled. We have the same page,
and if you go to the Network tab and
click the Counter page, in this case, it's starting
a WebSocket connection. You'll see a little bit more. But if you switch
between, for example, the Home page and the Weather page, it's only requesting the exact
content that it needs to display. It's not losing any
other state on the page, there's no flickering, it's
just a very smooth experience. Also, if we were going to
have an interactive component that persisted across these
navigations, it would keep a state. I can actually show that as well. I'm going to create a new component and I'm just going to
click Counter button. I'm going to copy most of the code in the counter
and just put it in there. Let's take this, paste it in here, and let's remove this, and let's display the count
directly in the button. We do Count, not that. There you go. Then what happens is
if we were to put this, we can put it in the layout. I'm just going to put it
right next to the about link. We can do a counter button and
give it a server render mode. Let's say
rendermode=RenderMode.Server. Now what's really cool about this, actually I'll just
wait until I show you. If I increment the count bunch and
then I click to the next page, you can see it keeps its count even though we fetched a new
page from the server. This was a server side navigation, but the interactive component
is keeping a state on the page. Imagine this was
like a video player, that would keep at state as
well if we were switching between the Home page, the Counter page, and
the Weather page. Whereas if we were to go back and
turn off enhanced navigation, and you can see it does
not work that way. Now, I can increment the count, I can click on Counter, and you can see it just got reset back to zero. That's what enhanced
navigation is doing. Is it's preserving as
much state as possible even though it's a
server side navigation. I think that is about it for
enhanced navigation that I had. Are there any questions? >> There are questions but
we are super over time. I think we should maybe wrap up and then we can go deeper on
some of these for next time. Maybe we can take to look at some of the questions that we got and pick some favorites
for the next standup. >> There are a lot of questions. >> There are so many. It's overwhelming to
even try and pick. > Maybe in addition
to a URL links thing, we also need the after the
fact question answer thing. >> You're right. Tons
of great questions. I think we probably
really can wrap them up. There's some common themes,
there's some discussion. Some people are saying
they don't love the naming of the RenderMode and
they think it should be, I don't know [inaudible]. >> Was there any good counter
proposals for RenderMode? >> Dynamic render. I don't know. Honestly, we'll have to look. >> That debate can be taken
to GitHub feedback like that, file issues, comment
on existing issues. We welcome that discussion. >> One that I just want
to pop up here is, this is pretty cool. I just like seeing this. This is an interactive shopping
basket which totally makes sense. It's in your component and it's preserved during
enhanced navigation. This is really cool to
hear. That's an example of exactly like a super
useful thing there. >> Hi, Marina. Marina
has been helping us out with the Blazor
project on the repo. She's one of our very active
community contributors and issue triager. You may see I'm a bit familiar
with her name as well. >> You know what? Here's one. There's a lot of questions
on authentication. Maybe that's something we could also dig in to a bit in
the next stand up. > That would be awesome. We
could definitely do that. For the RC2 bits should
have the off bits there, and we should be able to show that. I think almost every block post
that we've done for Donna Date, I've had someone ask, where's
the authentication stuff? We know people are
really interested in it, and I apologize it's
coming in so late. There's just been a lot of
stuff to deliver this release. >> What happened in this release? Well, I think let's play us out. I'm officially almost 15 minutes
late for a meeting and so cool. Thanks everybody. This is amazing. Thanks for the amazing demos. Keep the comments coming in. I can dump them out to an Excel file and we'll
try and triage them a bit. >> Bye, everyone. >> [MUSIC]