 I'm David Fowler and I'm Stefan Halter. We're going to talk about what's new in SignalR in.NET Core 3.0. All right. So here's our agenda. We're going to start off by doing a small version of what is a SignalR, a one-on-one for those of you who are familiar with the platform. We'll talk about our new NPM organization. So we made a small change to where we store the package in 3.0 and that's important. We'll talk about the new feature client-to-server and server-to-client stream that's a pretty cool feature that we have a demo for in 3.0. The most after-feature in SignalR has been reconnects. If you use SignalR before, you know it's a source of pain. So in 3.0, we have a new feature called automatic reconnect. We have a demo for that as well. That's definitely a show in a few seconds. If you're familiar with Dynacore 3.0, we have a feature called server-side blazer, which is powered by SignalR as well. Finally, if you want to scale your application in Azure, use the Azure SignalR service. All right. So what is SignalR? SignalR is a client, we call it a persistent connection abstraction. What that really means is any place you want to use WebSockets or get live updates, you could use SignalR instead. It's an abstraction because we have multiple transports backing the actual connection. It can be long polling, service and events or WebSockets. So why not just always use WebSockets? Some clients aren't capable of doing WebSockets. So depending on your client and service capabilities, you may have to downgrade to different transports. So let's talk about how each of those work before we go into a quick demo of how SignalR works. So for long polling, the client sends a request to the server-side saying, do you have data? The server will respond after some time with I have data or I don't have data. The reason it's called long polling is because that poll could last for up to a minute without getting data. The server will reply with data and then after the server replies, the client sends a new request, asking for more information. So this is better than regular polling. Better than, yeah. It's better than asking every second, but it is still not sufficient as other transports. So server-send events or SSE for short, is an API in the browser where you send a request using an event source API. It's long-running request and the server can send responses over that single request. So it's really good for a server to client throughput but it's not great for a client to server. That still requires a request per message. Then the big Kuhuna is WebSockets. So you send a single request that says, I want to upgrade this connection to WebSockets. Then the server says, okay, cool. Let's change protocols and then we have a single connection that goes server-client-client server over the whole lifetime of the connection. Do I have to pick which one I want to use? The signal are smart enough to pick the best transport based on your server and client capabilities. We call that process negotiation. Now we're going to do my classic favorite signaler one-on-one, which is a chat program. So in case you want to do replace Slack or Microsoft Teams, here's your end. So we're going to start with having a file new project. Here's my Hello World project so far. I already prepared since we don't have much time in this demo. So I used a new client-side package manager to add signaler. So I can go to, sorry, that was kind of fast. So again, right-click the project file, add client-side library. So this is new? This is new and VS 16 point, I don't know the version 16 or something. I can choose a bunch of different providers. So there's CDN, JS, a popular CDN library manager for JavaScript packages. I can get it from disk, I can use JS deliver or unpackage. Unpackage mirrors packages in a CDN format from NPM. So I can use that to search for, for example, Microsoft signaler. So it's not at ASPnet signaler? It's not and that was our old organization. We want to be where the other packages for Microsoft were. So we went to the same org. You can see here Microsoft has a bunch of packages. I can search for signal R and if the internet is willing, it will work like a charm. But if it isn't, I already prepared the application because this could happen. All right. So that works, trust me. Normally, you would see the files and you could select which one you want from the NPM package. So quick segue, this is the older version of the package. It's under ASPnet slash signaler, and the version is 114. Going forward, it is under Microsoft slash signaler, and it was published 15th, well, I should reflect, but probably today right at some point. So for 3.0 and on all words, you want to use the Microsoft org on NPM. We didn't duplicate the old because we still have people using the old package. We haven't figured out what to do there yet. So that's the current state of the world. All right. So that was not interesting. So out of the package, here I have Microsoft signal R, disk browser, and a bunch of files, a map file, a min file, typical things you see for a client-set application. On the server side, I'm going to wire up signal R and L. So I'm going to wire up my already built chat hub. I actually have a copy, because I'm lazy, the endpoint. So there's a new feature in ASP.NET Core 3 called endpoint routing. I'm going to wire up signal R to those routes. This is different from 2.0 where we had an app.U signal R, there was a middleware for signal R in the pipeline. App.U signal R is still there, but it's deprecated now. Can you see that, that zoom in? It's in the tool tip deprecated for those who can't see the small text. I was zoom in, but I don't want to risk it. So now instead of calling use signal R, you do use endpoints, map hub chat. So I'm mapping the chat hub to the chat endpoint. I'll hit F12 to see the actual hub. The hub is very simple, it has the hub is where all the clients connect to, it's the central hub on the server side. There's a public method called send. What send does is send will send to every client that's connected. It's all because I'm sending to every single client. I'm calling this method, passing the message that was sent to me, some kind of an echo broadcast to all clients. On the JavaScript side, I have a simple page here that has some pretty fancy UI, a text box, a button, and a UL for messages. This is the height of my UI skills. Not even bootstrap. Not even bootstrap. Wow. I have a clean area to write some code from scratch. Boom. Wow, that was fast. Yeah. So let's go through the code very quickly. I'm creating a hub connection builder, passing in URL slash chat what we had on the server side. Whenever someone calls send from server to client, it will call this function and then we'll create a new entry in the list of messages. I see it's not case sensitive, is it? It is not because that would be user hostile. All right. Now, we use vanilla.js the library to warp the event. So whenever someone clicks on the send button, I'll add an event listener. Whoa. Whoa. IntelliSense. I'll add the click handler to get the text from the text box and then send it to the server side. So calling invoke here ends up calling invoke, passing in send is calling the send method. All right. Those map. Let's run this. I hope it works the first time. All right. To demo signal art, I need at least two people, otherwise it's kind of boring talking to myself in the same window. So I'll talk to myself in a different window. So hello. Yay. Works. All right. All good. Cool. Working fight. All right. It's working. All right. Good. Awesome. All right. So that was your Signal 101. If you want to get started to make a Slack competitor, our Teams competitor, that's how you get started. All right. Let's continue from there. That was a quick demo, I hope. Let's talk about how Signal are broadcast to different groups of clients. Just know we did a broadcast. So going to everyone currently on the hub. You can also go to a single user, and the user may have more than one device. So I'm David. I may have an, well, we have Anthony here. So this is Anthony. Anthony has a desktop, an iPad, or a tablet, or a surface, maybe a surface, and a phone. And we can target all of those devices, or we can target a single device. Or we can target arbitrary groups. So imagine you had a chat application that had chat rooms. A group could be a different chat room. So I can send to everyone, to a user, to a connection, or to a group. So one client can be in a bunch of groups, right? That's right. So I can be in two chat rooms. I can be in many groups. So Stefan will show us his super awesome Uber demo that shows pretty much all the new features. No pressure, Stefan. Yeah, thanks, David. No pressure. So, you know, since David showed you the sample that you all already saw, I was tasked with creating a new sample. So one of the big new features in client-to-server is client-to-server streaming in SignalR 3.0. So we have another Visual Studio instance, which is a SignalR 3.0 sensor demo. So to show you what client-to-server streaming looks like, we're going to have a C-sharp client. So this uses a SignalR client very similar to the JavaScript one that David just showed you in the chat sample. But instead of showing you chat and allowing you to chat, what this is doing is this is publishing sensor data to the server. So because I'm on David's computer right here, and we are short on time, I'm going to have to describe this part of the demo to you because I don't trust myself to type it accurately. But you have what you saw before, hub connection builder. And in this case, it's connecting to a sensor hub. Just like on the JavaScript client, we have this builder pattern. So you create a hub connection builder. Pay no attention to the man behind the curtain. What's that region? All right, it's actually not that complicated. But we're not doing anything too tricky. We're just trying to have a no-op callback. Hide it, hide it. Sorry, I should have skipped it. So after we start it, this quickly goes into using our client-to-server streaming ability. So you'll notice that we have a single method call. So in this case, we're calling a hub method called publishSensorData. And then we're passing as an argument an iasync and neural. So this is kind of new. It's in .NET 3. And then we also have async iterator support in C sharp 8. So this is pretty cool. What it allows you to do is, every second is creating a new iasync and neural item to double from 0 to 10. And then it publishes it to the server. And unlike a regular iasync and neural, where you might call like, and neural will get next and it's going to block an entire thread, this is all async. And so it's very scalable. What is the await using var? Ooh. Some new syntax there. That's a good catch. C sharp 8. So our hub connection has an implements iasync disposable. Not very cool. So not only do we have a using that scope to the method, so that means that it gets disposed from the method ends, since it's await using, it's calling disposeAsync. So that allows us to, without blocking, without wasting thread pool threads, shut down our hub connection. We hit blocking threads. Yes, especially in ASP.NET. So if you ever have .result or something, try to figure out how to do less of that. So we can quickly take a look at what this is doing on the server when we call publishSensorData. We're using another C sharp 8 feature, which is await for each. So we can take this iasync and neural, you just saw us pass it. So it gets nicely serialized, deserialized in real time as new data arrives. And we can asynchronously iterate over it. So again, like this await for each is basically calling a numerator moveNextAsync. It's very efficient. And then we can use our sensor collection service. So if you go and look at our startup class here, this is just like we call addSignalR, we have this service here, that basically allows us to publish our sensor data and then we can subscribe to it using getSensorData. So I can show how you can stream server to client. So this is already a feature in SignalR 2x, but you can combine these together nicely. So inside of our web app, we are going to have this chart, which is going to show us the sensor data. And we're going to use streaming to download the stream. So here we have this chart div in our body and we're going to use new, I think it's iasync await. And we're going to update this object of XYZ sensor data. So again, hub connection builder, connect to the same sensor hub. And then after we await and start the connection, we try to see like what are all the sensors that are connected to our web app. Once we get, this is an array of strings, all of our sensor names, we call subscribe to sensor for each sensor, call getSensorData. And then this is returning like an RXJS observable. We didn't pull in the RXJS library. If you did, you have a lot of cool helper things to do like filtering and things like that. But what we're worried about here mostly is every time we get a new sensor, a piece of sensor data, we're just updating this object and that's going to ultimately update a line chart. And one last thing is you'll see that the subscribe to sensor we're calling connection.stream instead of like connection.invoke or something. So this is like when you're doing server to client streaming, you call that stream API. And then this is returning the same iasync and new rule that we published. So without further ado, we're going to control f5 this and we're going to quickly see a browser pop-up without any sensors. But fortunately, we already have the folder where we had that program. So yes, we have that async iterator that's giving us random numbers from 0 to 10 every time. So we're going to run sensor with a name X because we're using the first argument as the name of our sensor. And we're going to run a sensor with name Y. We can call the sensor whatever we want. As long as it's XYZ, it should end up showing up on this chart. And we can go full screen here because this is one of the few single-art demos that doesn't really need side-by-side. If it was side-by-side, all the browsers would be seeing the exact same sensor data. What is that data? Random doubles from 0 to 10. Like an earthquake chart. Yeah, it's pretty fancy. That sensor is kind of getting crazy, but it was really simple to write. So that was my favorite part of it. That was pretty short. So what happens now, though? Actually, there's a slide for this. In practice, I missed it every time. So we just did server-to-client streaming as well. But what happens if the connection... breaks? And there are a lot of reasons this could happen. You could have some mobile client going through a tunnel. You could be redeploying your web app. The quick way for us to sample it here is just to close the server. We can pretend we're redeploying. If we go back to our app, you'll see we're no longer getting new data if we were to restart the server with CTRL-F5, nothing's going to reconnect. So people who might be used to previous versions of SignalR might expect this graph to start moving again. But SignalR core, up until 3.0, had no way to automatically reconnect. We told customers that write a closed event handler, dart the connection manually. But that ends up being a lot of code. I don't know about you, but when I write a lot of code, it's more likely that I'm going to write a bug. After, like you said, it was highly requested, we added some automatic reconnect functionality. In this part, I'm going to try to kind of write. So let's see if we can pull it off. Hopefully it's simple enough that I'll be able to do it. So to make the sensor automatically reconnect, we go into our HubConnectionBuilder and anywhere you want, like with URL, it's like, you know, you can chain it. We can call with automatic reconnect. Why is it not on by default? We're worried about making breaking changes. We don't want people who expect the client to disconnect suddenly after they upgrade to SignalR 3.0 to start reconnecting without them realizing anything's going on. So you have to specifically opt into this, but we try to make it as easy as possible. So we have this with automatic reconnect extension method. We're going to use the default overload, which we'll try to reconnect as soon as the connection goes away, and then we'll try again after a few delays. If you want to control the delays, you can pass in your own array of time spans, or if you want even further control, you can look up iRetryPolicy on MSDN. So we would like it if that was the only thing you had to do, but there's one or two gotchas when reconnecting. One thing you'll notice is like after we connected here initially, we called publishSensorData. As soon as you reconnect, any ongoing method calls end. So what this means is that you need to, if you want to continue publishSensorData, you need to call that method again. This part, I am going to write an un-reconnected handler. So what this is, is hub connection now has a reconnected event. So if you use with automatic reconnect, it will call this once the client successfully reconnects. And it's exactly what we did after we called startAsync. We just called publishSensorData with our async iterator. And that should be enough to have the sensors automatically reconnect. Now we have to do something very similar in JavaScript. So again, to save me some typing, we're going to just pass in with auto-reconnect. We're going to use that method on the hub connection builder. And with the client, with the chart client, we ended up having many streams. So we called getSensorData for each sensor. So there were two that we just used. So for each of those sensors, we're going to want to call getSensorData again when we reconnect. So JavaScript also has a reconnect event. It's a very similar pattern. And just like we did after we connected, we can call getSensorNames and then for each of them, subscribe again. One thing that you'll notice, I kind of glossed over this really quickly in the C-Shark client, is that we actually pass in a connection ID every time you reconnect. What this is indicating to the user, because you can actually, if you want to, have a hub connection dot connection ID, and it will be the same value. So it's not strictly necessary, but it's more like we're trying to highlight that this is a brand new connection from the perspective of a server. So onConnect is going to be called again. You've got to resubscribe to any groups that you want to be called. You need to start all your methods. The one big thing that you don't have to do again is you don't have to resubscribe to any onCallbacks. So now that we've enabled, that's all you need. That should be everything to do reconnect. Magic-reliable signal interconnection that lasts forever. One thing you'll notice is we only made client changes to do this. So we can leave the server running once we get it running again. So then, we now have to restart the .NET clients because they stopped because we didn't have automatic reconnect earlier and now we do. I'm going to make sure they're both stopped when they're like recompiling or whatever. So we're going to start our X-sensor. We're going to start our Y-sensor. And so far, it's what you saw before. So nothing too surprising. But the question is, what happens when the connection is lost? The earthquake hits. Right. So right now, we have three single-hour clients connected to our web app. We have both sensors and then we have this web page that's showing us the data. So we have the X-sensor to client and they all need to restart. So we close it. Cross your fingers. It stops. It flat lines. Everything's dead. Yeah. All right. We control F5 again. Don't pay attention to the new tab because obviously that's going to work but apparently the sensor's reconnected and okay, it's still flatlining. There might be a delay, hopefully. There's a delay as it's trying to reconnect. I'm suspecting that we're in a 20-second delay right now. So we're going to go back to the old tab and we can see some of the logs from this. Did we refresh this? Did I save? That would be funny too. Did you refresh it? Did you refresh that old page with the new... All right. So normally we would try to be seeing reconnect events. So let's look at this again. All right. So that's just the favicon. That's the only error. So this should have auto-reconnect because I save. So we're going to do this one more time. If it doesn't work, we're going to pretend. There's a word before. Yeah. So you can see the sensors are trying to reconnect. That's what those logs were. And then, boom! So now you can see it went from flatline to the lines are moving again. I don't know if you can see the screen. So we killed the client and the client's flatline. That's kind of a visceral. All right. So now we're going to go back to David to talk about the SignalR service. A little bit of time left to talk about the service. All right. So you finish your application and put it to Azure Now. And the issue with that is that you need to scale both long-running connections and short-lived connections in the same application. So what the service was designed to offload your concurrent connections to a different service so your app can scale the web traffic independently. There's a free turn in the service. You can get up to 20 connections and you can pay for more scale if you want up to 100,000 connections. And in 3.0, we actually improved the experience where you add a package to do so before it was 2.0, it's 1.0. So a huge improvement. Two is too difficult. So before, in the olden days of hosting SignalR, you would host everything in an app service or an IKS cluster and you would put your pages and your hub in the same application. All good and fine. The issue is you're trying to scale the long-running connections in the same app as your short-lived connections and that can get kind of tricky. So the SignalR service, you add it and what happens is it moves the SignalR traffic off to the service side and then your app can batch handle connections over a different pipe than the actual ingress traffic. So you're turning a thousand connections into five as an example. And I'm going to turn Stefan's demo into a connected SignalR service application with just a single line of code. One line of code. Are you sure it's only one line? Maybe. Are you going to get stash pop and hide some stuff? So the first thing you do is you install this package that you installed previously. It's going to be RTM today. People have to wake up on a different side of the world to upload a new package. So I have Microsoft address SignalR 1.1.0 preview, blah, blah, blah, blah. It'll change to something else eventually. I think 1.1.0 RTM will ship today. And then in my start-up class, I can do add SignalR add address SignalR. And then that's the whole thing. So how do we prove that it works? Okay, so what is the service doing even actually? Web scale. Web scale, okay. Independent scaling. Yeah, still works, right? That's all good. Did our client just reconnect? It did reconnect. If you look at the log it started off at look at that. It started at local host 5000 sensors and it went offline, came back online and ended up going to SignalR Hello Service, SignalR Service, Client Hub, blah, blah, blah, more things. So you had a web app in two sensors that were connected to local host. You typed in .addAzureSignalR redeployed and then everything just kept on working using the service. So it's going from my client to Azure to my machine, which is super inefficient because it should be both in Azure but in Azure it's way more efficient. And you don't have to like scale up your Azure app service just because you have like 10,000 concurrent connections. And actually I believe the conference is using the Azure SignalR Service to show notifications on the actual stuff below this video, right? That's pretty cool. Awesome. I believe we have to take questions soon or something. That's the thing. That's the whole thing. Are you ready Scott? Hello. That's live television people. We're trying to raise a lot of money for the kids here. Sorry. That's okay. So a couple of questions and one of the questions I've actually had and there's at least three or four different examples of this on Twitter are people are saying they want to understand if they're using Blazor and WebAssembly, how do they call SignalR? Are they using because they're in WebAssembly, they're on the client side are they using the .net SignalR client? Are they using JavaScript? I think it was even so sassy as to say I challenge you to do this in Blazor without using JavaScript. So what's the relationship between Blazor WebAssembly, SignalR, WebSock? Go. Super interesting question. That you have no doubt thought about deeply in the past? We have. So there are multiple. So currently I believe there's a third party SignalR client written with JS interop to make a .net based client to make an end to end scenario work, right? That's what we don't want to ship that. We actually want to ship the foot on that client as it is today running on my machine compiled into well, I guess interpreted in the browser. The only thing that we would shim is WebSockets. So you shim the transport layers. So you need to shim HB client WebSockets to use fetch or WebSockets in the browser. But the actual C sharp logic from the client should run in the browser like a normal C sharp library. But not yet. So far it doesn't run and you have to kind of use JS interop to talk to the JavaScript SignalR client from C sharp which feels kind of insane because you're going like C sharp interpreted called into JavaScript to do stuff and then getting events about the C sharp and then like the whole end to end. So what would you recommend to people today as we release .net 3.0 who are enthusiastic about Blazor because you've got Blazor client side you've got Blazor server side, you've got SignalR who are excited but they don't know what the correct way to go is. So for server side the situation is a little bit unfortunate because it's not very efficient. You could use the C sharp client but what will end up happening is you will spend an entire connection, TCP connection per client, per browser client you'd have one per server. But one, one WebSocket client on the server side per browser client which isn't super efficient. Right, so right now a server side Blazor uses SignalR. So it's kind of bridge the server and the client. But adding extra connections between the server and the client is a little unnecessary. So we're looking at ways to optimize that. So today is inefficient and you can use the client on the server side but it's not great. We're going to talk about that I think like before we ship FIVO. Okay, so there will be guidance and prescription on how to do that? Of course. Okay, another question. Here's an interesting one. So with SignalR help understand how Kestrel would work. If you were just doing Kestrel and you know, can Kestrel talk SignalR and handle lots and lots of connections or do you need to have Azure or IIS or something big in front of it? No, so Kestrel works fine. It's actually probably more efficient than all the other servers that we have for SignalR and it can handle a ton of concurrent connections. We're not the best at memory but we actually made a ton of improvements in for connections over WebSockets to reduce memory footprint and improve throughput. And there is a Redis, you know, horizontal scaling so you can scale that way but I would say like how many connections are supported will depend on the activity of the connection. Oftentimes you're bandwidth limited with these SignalR applications. And memory. Memory, yeah. It depends but like those broadcast scenarios can easily consume a lot of... CPU. Yeah. Here's an interesting one. With the focus, the new focus on GRPC... Oh, wait for this one. Are there plans to have SignalR work with GRPC Stream? What is that relationship? Very early. What is GRPC Stream for those of us who might not know? So... It's funny. So GRPC supports streaming. Is it funny, David? It's pretty hilarious. Funny ha-ha. I knew it was going to happen. Funny like... Uncomfortable. No, but what is GRPC Stream? GRPC supports streaming from client-server and server-to-client. And server-to-client. It supports both directions. They're picking back on top of HTTP request, which is interesting. And it pretty much... Let's just say the feature of SignalR, except ours is a little bit nicer because we were kind of like... We used ISAC in the removal on both sides so it kind of looks more native. But the feature... The feature set is pretty much the same feature set between both things. Except for SignalR, of course, also provides the PubSub kind of groups and podcasts and things like that. Yeah. All right. So there is overlap, but there's no current thinking around merging the two features. Maybe that's a conversation that you might want to have on Twitter. I would encourage everyone to go to Twitter and crush at David Fowle and friends with questions about SignalR because he has nothing better to do today than answer these questions. And I want you to go ahead and just absolutely flood him. Thank you very much, David and Stefan.