Using SignalR in your Blazor applications

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
>> 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]
Info
Channel: dotnet
Views: 15,194
Rating: undefined out of 5
Keywords: .NET, dotnet, aspnet, asp.net, signalr, real-time, realtime, websockets, C#, csharp, Microsoft, programming, Web, Web development, coding
Id: caE5VZD5XNk
Channel Id: undefined
Length: 30min 19sec (1819 seconds)
Published: Thu Aug 19 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.