>> What do Chuck Norris and
WebAssembly have in common? You'll have to check out
this special episode of ON.NET where we talk about SignalR and Blazor
WebAssembly apps. See you there. [MUSIC]. >> Hello and welcome to
another episode of ON.NET. Today we're going to be talking about SignalR and
Blazor applications. I've got fellow Microsoft
employee, David Pine. David. >> Hi friends. >> There he is. Tell us a little bit about what you
do at Microsoft, David. >> Sure. I'm a Content Developer. I was working on Azure docs for a while and then moved
over to the.NET docs. I'm a huge proponent of open
source,.NET, C-sharp, TypeScript. All the things SignalR, Blazor, love it all. >> You mentioned the last
two, SignalR and Blazor. That's obviously why
we're here today. So tell us about why it's even interesting to me as a.NET
Developer, SignalR and Blazor. >> Well, it's interesting because as a.NET Developer with SignalR, you get real-time web functionality. What that means is, I like to go to the analogy
of, "Are we there yet?" If you have kids, and if you've ever done a
road trip with the kids, you've probably heard,
"Are we there yet?" That's the same concept behind historically
typical web applications, where they'd have to pool for
the server asking for updates. Like, "Hey. Has this changed?" But with SignalR and
real-time web functionality, the server and client actually establish a duplex
communication so they can basically send unsolicited
messages back and forth in real time so
there's no more waiting. As things happen on the server, they instantly are represented
then on the client. So that's super exciting for any of those scenarios where real-time web functionality
is a requirement. I think that's becoming more
and more pressing of an issue now with modern technology
and application development. Then Blazor is super-exciting,
especially with WebAssembly. I'm a huge proponent
of web applications, and with Blazor WebAssembly, this is really Microsoft's and
Blazor server-side actually too, it's Microsoft's first-ever
single-page application framework. You get client-side routing, you get dependency injection,
you get templating. You get all sorts of
things that you'd expect from Angular or React or other
single-page applications, but with.NET so you
get to use all of your existing.NET libraries that
you're comfortable with, and all of your C-Sharp Skills
come along the way for the ride. >> I'm a huge fan of Blazor too. C-Sharp in the browser without a plug-in is basically a
recipe for awesome sauce. Some people may be somewhat
familiar with Blazor. I know that Blazor server
actually works with SignalR. SignalR's how it basically renders
on the server and transmits to the client but what
you're going to be talking about is Blazor WebAssembly. This is something I assume that the Developers are going to
have to set up themselves. It's not the out-of-box
implementation that Blazor server
has. Is that correct? >> That is correct. To allude a little bit
more into what you were just prefacing that
conversation with Jeremy, the Blazor server actually does require SignalR to basically
communicate the Deltas, so the changes in the DOM. It's great, but there are performance considerations
and all sorts of other things that
come along with that. If you are using Blazor WebAssembly, you can host it as a standalone,
statically, if you want, or you can have
ASP.NET Core host it, and then you can have controllers, and then with that scenario, then you can actually open up the
door to having hosted services, and you can have your backend
basically support SignalR, and then you can get that
real-time web functionality inside your WebAssembly-based
Blazor applications. So it is an opt-in thing
and doesn't come out of the box but if you're familiar with SignalR and you're
familiar with Blazor, holistically, it's actually
really easy to put these two things together
and make them a reality. >> It's easy to say, it's easy, but actually [inaudible]. Think you have some code
you can share with us. >> Yeah, absolutely. I've been working on a Blazor demo, and I know that if
Brady Gaster was on he would sigh because one of the things that's been done a lot is the SignalR chat demo but I promise you this isn't
your standard chat demo. This is a little bit more mature
and something more likened to a production enterprise level type of Blazor application with chat. This is, again, WebAssembly. We've got our client
and these servers. This is hosted on ASP.NET Core. Then we've got some
shared libraries. That's one of the nice things
about Blazor, specifically, is that we can have a class
library that is shared. This is.NET 5, and we're basically creating pocos. We've got various records that represent different things
that you might be concerned with, and all of this is shared
between the server and client. The server has an understanding of these different objects and their
shapes and things like that. We got API responses, commands, all these
different things. It's nice because we get to reuse that code both on
the server and the client. The server is just a
web app, essentially. This is web API, and with that, we can have controllers
and things of that nature. Let me minify this. Our startup basically configures our services for
dependency injection. We've got response compression, we have a couple of extension
methods that we've put together for adding
our authentication. In this case, we're leveraging
Azure Active Directory in B2C. Then we have some services. We're configuring cores. We are going to add our SignalR. With SignalR, there's no
package reference here on the server-side because that comes out of the box
but on the client side, we will have to take
on a dependency for the client SignalR connection. We're also specifying that we want
to use message-pack protocol. This is a binary protocol versus
the standard which is JSON. Are there questions or I keep going? >> No. I was just going to say, I love the fact that this example
has everything built into it. It's authentication. Because I'll admit it, I
get lazy sometimes when I'm doing demo apps and just slaps something together
but this will be great for people building Blazor
WebAssembly and Enterprise. I know B2C is a common way
of doing authentication. Just calling out that I love
seeing what you have here. >> Absolutely. Then
we use endpoints, and this is how you
basically configure Blazor. You're going to map your hub, and when you map hubs, it requires a subclass of hub. In this case, we're mapping our chat endpoint to our
chat hub implementation. If I just hit "F12",
that'll take me to it. Our chat hub, we have an authorized
attribute on it. It means that this is all protected. We require a user chat scopes or our B2C skills are being flexed
here. This is all protected. Then we have a whole slew of
various functionality that's cool. In this hub, well, first of all, the hub is a hub of
t so we can actually specify a contract here and a
lot of people don't do this, but this actually
provides a little bit of strong typing around your hub, so you're not just
using magic strings. If you look at the chat client, our chat client interface is saying that we're going to allow a user to log on and that's going
to accept an actor. When the user is logged
off, we have another actor. We actually even have whether
or not the user is typing. With chat applications, one
of the nice thing is you sit there waiting for the person that you're
interacting with to type. We actually have that communication happening in
real time with SignalR. For example, when we do the demo, I'll ask you to log into the
app and I'll be into the app, and when you start typing, we'll be able to see
that you're typing. Then we've got an actor message, which represents a message
as it's being received, and then a command signal. There's various commands. I went a little above and
beyond with this application, and one of the things
that I added was a background hosted service that's sitting there and
it's accepting commands. From the chat window, if no one is around and onboard, I can actually interact
with that hosted service, and that hosted service. I'll pull that up real
quick. It acts as a bot, so a chatbot essentially. It's a background
service and it takes on the IHub context so the
background service, it's in process but it's outside of the request
and response pipeline. What that means is, as requests and responses are
being handled by our middleware, we have this background
service that's just spinning there independently. But we can use various
mechanisms here to intercept commands and
take different actions. What I've done is I've got some jokes that call out
to different HTTP methods, various joke services, and we can basically
command jokes from the client and then those jokes will be uttered on our client browsers. They even have the
capabilities to show that our joke bots are emulating that they're
typing to us and stuff. >> They're typing. >> Yeah. It's a pretty
neat little demo. Let's see here, that's
pretty much the server. The server is going to offer up, and again it's a bit of Razor pages starting off
the app that's hosting. Then the client side, in our client application, we need to take on a dependency
of the SignalR client. This is Microsoft ASP.Net
Core SignalR client, this is actually required for
our WebAssembly application to establish a hub
connection to the server. We also take on the protocols
message pack because we know that our server is specifying
that it wants to talk, it's protocoled to
be in message back, which is again the binary format. Let's go to the very
start of everything here. We have our services that are wired up so we're
going to add HTTP client, this is how we're going to
actually talk to our server. We have to configure our
HTTP client so that it knows the base address for
our hosted scenario. Then this is the B2C configuration for MSAL and then the app starts. Then from there it's basically all just standard Razor
and Blazor syntax, using the Razor view engine. If we look at the index, the index is a super
complex mark-up file, we have our page which
represents the root. We have our authorized view, so this is going to basically say that once we're authorized
we can show the chat room, otherwise you'll just
get the standard layout. Once we have our chat view, this page is a bit more complex, it's got several primary sections, so I'll collapse them
here for readability. We have our chat messages
container and then we have the ability for us to post
messages like in a button, and then we have a modal
for showing voice options. The chat messages container, and one thing that you could
probably do is you can break this up a little bit and you can
have Blazor components. But for simplicity I kept it all
in one place just to show you that within 127 lines of markup, you can have a full
functioning chat application, which is pretty feature-rich. As messages come in, we'll foreach over those and
messages is a dictionary. With dictionaries you
actually get key-value pairs for the entries and then you
can deconstruct those into tuple literals so we have the ID
and the message for each of those and then we're going
to just basically template out our markup here. We've got list items and then we're basically just splatting the
messages into the chat app, our list of messages
as they come in. We have a markup string, so a markup string is
actually a struct from the components Namespace
and it basically says that if you pass a text it will
treat it as markup and it's safe to display in the DOM if you just
splat a certain text in there. >> This is HTML markup? >> Yeah, it's possible
that it can contain that. Yep, Absolutely. >> Okay. Yeah. >> This is how you
basically explicitly opt into stating that
your application has text that potentially
contains HTML and that's the proper
safe way to display it. Then so from here, we have basically a
simple little form. We've got our input
so we're going to let the user click a button to send messages and it's just a simple text input
and that we're binding to. Then we have some of
the logic here for displaying whether or
not multiple people are typing and we've got some of
the tie backs with SignalR. I'm going to show that now because the markup is a
little less exciting. >> Quick question for you
before you dive into that, I noticed that you've got
a font on your system, is it called a ligature? Is that correct, where that goes into the right arrow,
the single arrow, so lots of new language
constructs using records, using the new without
having to be redundant. But if I'm interested in this font, how do I get set up with that? >> Yeah. This is a programming ligature,
you're absolutely correct. This is, if I just put a
space here you'll see, so what it does is basically takes two characters together and when
it recognizes them together, it treats them as a ligature. There's different ligatures that are available within this font setup, I'm using FiraCode and I've been
using that for a long time. >> Good to know. >> Let's see, we've got
a hub connection and we have several private fields
within our partial class. One thing to note here is
that this is a partial class. With Blazor, you can
actually shadow components, and I call it component shadowing, I don't know if there's actually
an official term for it but essentially what it does is
if you have a chatroom.razor, this Razor markup file is actually compiled into a chat
room C-Sharp class. If you have a chatroom.razor.cs, the IDE is smart enough
to collapse those together so it essentially shadows those entities and you end up
putting a partial keyword on your class and then that lets you share that compilation from the markup and then
essentially have what, if you think back to Web Forms, this is like code behind. >> Right. >> Yeah. All of these members are actually available to
us within our markup. If you recall when we
were iterating over or templating for the
messages that come in, we were walking up to
that messages dictionary, that's represented right here. There are a few other things,
so we do have debounce timers. The debounce timer in this
case is essentially in our chat room so for any individual
client that fires up our app, logs into it, is authenticated, and starts typing, there's a debounce timer that will reset after a certain
amount of time. When it first triggers, it's going to send a message through our SignalR letting whoever else is connected know that
that individual is typing, and after a certain amount
of time if they stop typing, it'll basically send like a cancellation that they're
not typing anymore. That's what this is
for, the debounce timer we're wiring in events, and that's handled as, set as typing false after
a certain amount of time. We have some parameters, this parameter attribute
basically let's this property be assigned
to from consumers. If you recall from the
index markup when we were saying our authorized
view has a chat room, we were requiring a user. Once it's authorized there's a contextual user that's
basically plotted on our context so we have that ClaimsPrincipal
user available to us. Additionally with Blazor, when you want to do
dependency injection, there's no notion of dependency
injection through constructors, so you actually have to
use this inject attribute, and then you just do it
basically with properties. We can say inject our
navigation manager, inject our IJSRuntime, the JSRuntime actually
represents our proxy between our clients.net and the
JavaScript runtime for the context of our browser. This is actually really, really cool because we can walk up
to JavaScript and do various Blazor Interop and call
into JavaScript API. I'll show you this real
quick, this is super cool. We've got this Interop folder, we've got JavaScript extensions, and you minimize that, so from here, we have an extension method on
the JSRuntime that says, SpeakAsync and it's asynchronous
returning a value task. We're going to pass a message, a default voice and a voice speed, and then a language
and that's expressed as walking up to our
JavaScript object and saying, InvokeVoidAsync given this name, so app.speak and then passing
in all those arguments. You might be asking yourself, well what is app.speak?
Where is that coming from? This is our client
JavaScript which is part of our www.root which is
registered with our index.html. We're basically
applying an app object to our window like our global scope, so then we can say app.speak, which is this function here. Speak takes a message, defaultVoice, voiceSpeed and language, and that's expressed as with the fat arrow. This is actually using the
native SpeechSynthesisUtterance that's available natively in
JavaScript on the client browser. We can instantiate an
utterance given a message. We can walk to the
window and get all of the speechSynthesis
voices that exist, and we can try to find our corresponding voice for the
utterance that we were specifying. From that we'll set our volume, the rate of speed if
it was passed in, and then we'll ask
the speechSynthesis on the window to
speak that utterance. This is basically how you
do JavaScript Interop. There's all sorts of
little fun bits there. Let's get to the fun part. Once our chat room is initialized, we instantiate a
HubConnectionBuilder. We say we're going to
use this chat app route. If you recall, that's the
server's route for our chat hub. Then we need to specify
an access token provider. This is how we are going to connect our B2C tokens that our
client already has access to, to the hub that we're connecting to. If you recall, our hub is actually requiring that authorize attribute
with that specific scope. The client, once they're logged
in, they have that scope. We're going to attach
the tokens for it. We're going to specify that
we want automatic reconnect. We want to add message
pack protocol. Then we have a few
convenience things. We have a hub registrations, and this is basically just a
[inaudible] of IDisposables, because when you walk up to
a connection and you say, OnMessageReceived, it actually
returns an IDisposable. I want to be able to
hold onto those and then clean those up once our app's done if you navigate
away from this page. Then you just map all
your connections. We're basically saying that on a message received, we're
going to handle it this way, when the user is typing, we're
going to handle it this way, and so on and so forth. Then we've got different ways to notify that users have been logged on and
off with a little toaster. Then we're going to start
our hub connection. Then once it's started,
we're going to focus on our element reference, which is our input for the message. Then once it's focused, we're going to update some voices. This is a little bit beyond the
scope of this conversation, but let's just fire the app
up and take a look at it. >> Sure. >> I've got the app here
and I'm going to log in. It's going to do the B2C flow, I've already signed up for the app. Once I sign in, the app's going to restart and it's going
to notice that I'm authenticated and takes a second
and I get this giant message, this greeting message,
which is nice. This greeting message is the first message that comes
out when you first sign in, and where that is explicitly coming
from is from the server hub. I'm going to go back there just
to show you that real quick. In the chat hub, the first thing that the app does
is I override OnConnectedAsync. This only fires one time per client. When this fires, we walk up to the clients
and we say the caller. The caller is the individual who
connected at that point in time. Then we're going to say
message received and we're going to pass them
that new actor message. It's a greeting and we format
this huge greeting message, which is the markup. As you can see, there's strong, there's breakpoints, line
break, stuff like that. But that basically greets them
with this little message. Then from there it's
just a chat app. Jeremy, on your end, why don't
you fire up the app to login and I'm going to say
testing 1, 2, 3. Make sure this thing works. Bam, now we've got a message here. Then I can actually
edit my own messages. I'll click on my message, can I edit this. Of course I can. It
shows that it's edited. I can actually select
different voices. Make this sound here.
That's perfect. I can actually walk
up to this and say, oh, look at that, hey Jeremy. Jeremy Likness logged on. Jeremy's typing. I can see
that you're typing now. As you type messages, wow, am I really here? I think so. Now, if you recall, I mentioned that we have that really entertaining little part
where we can actually walk up to joke bots and stuff like that, and
they will be uttered. I'm going to say "jokeChuckNorris". This is a special command syntax. When the command is
received on our hub, there's that little
service that sends there, and the command signal
sees this and says, is this a signal? Is this like a specific command? If it's recognized as that command, then it takes a different action
rather than posting it to chat. This is a command signal to
tell my chat bot to wake up, tell a joke for the
Chuck Norris joke bot. Let's post it. You'll see that
Chuck Norris joke bot is typing. >> Scientists have estimated
that the energy given off during the Big Bang is roughly
equal to 1CNRHK. Chuck Norris roundhouse kick. >> Right? Then there's the dad Joke. >> How does the moon cut
his hair? He clips it. >> You did the dad one, right? >> Yeah. That's basically the
application in a nutshell. We have emojis. You can edit your own stuff, I can't edit yours. You can have emoji support. There's different joke bots, those things are being uttered. This app shows a whole lot of
different things coming together. It's been a lot of fun to work on. This is using Blazor
WebAssembly, SignalR, and it shows off the
interop capabilities, it shows native speech synthesis
through the client browser, it shows how to actually get these voices that
are available right here, like this drop-down list
is bound from a client. We actually have to go ask the client browser for the
voices that it recognizes before it can populate
these and then the JavaScript actually
calls back into our.NET. There's all different examples of the moving parts of
Blazor WebAssembly, SignalR, JavaScript Interop, and real-time Web functionality. This has been a lot of fun. >> The burning question is, where can I find the code? What is the repo for this? >> Absolutely. There is
a fork me link on this. But if you go to
github.com/Ievangelist/signalr-chat, that'll take you to the source code. >> Perfect. Nice. Very
cool application. I'll tell you what,
Blazor, in my mind, is a game changer because it's not is JavaScript
good or bad or evil. It's that I'm a C# developer, I've been developing with C#, and I have my libraries and my
code and all that history there. So being able to use it
to develop an app like this as a single-page application without having to jump into different languages and using
what we have, very cool. Thanks for putting this together. >> Awesome. Thanks for
having me. This was great. >> Well, that is SignalR
Blazor, David pine. Thank you, everyone. We will see you on the
next episode of on.NET. [MUSIC]