SignalR - Realtime client/server communication (iSense)

Maarten Balliauw
Maarten BalliauwDeveloper Advocate
SignalR
Realtime client/server
communication
Maarten Balliauw
@maartenballiauw
R
Who am I?
Maarten Balliauw
Antwerp, Belgium
Developer Advocate, JetBrains
Founder, MyGet
AZUG
Focus on web
ASP.NET MVC, Azure, SignalR, ...
Former MVP Azure & ASPInsider
Big passion: Azure
http://blog.maartenballiauw.be
@maartenballiauw
Agenda
Why real-time & how?
Meet SignalR
Connections and Hubs
Clients
.NET Core
Q&A
Why real-time & how?
Users want the latest info, now!
Twitter – live searches/updates
Stock tickers
Auctions
Live scores
Real-time notifications
Collaborative apps
Live user analytics
Online gaming / browser games
… 6
HTTP is and old beast
Never designed for real-time communications
Web is request-response
Web is stateless
Websockets to the rescue!
Websockets
Extension to HTTP
Provide raw sockets over HTTP
Full-duplex, low latency
Traverses proxies
But…
Not every proxy server supports it
Not every webserver supports it
Not every browser supports it
Some antivirus blocks it
They are raw sockets! (protocol: up to you)
http://websocketstest.com/
Forever Frame
Server tells client that response is chuncked
Client keeps connection open untill server closes it
Server pushes data to the client followed by 0
Consumes server threads
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked
<script>eval("... ")</script>0
<script>eval("... ")</script>0
Periodic polling
Poll from time to time using Ajax
Delay in communications due to polling interval
Wastes bandwidth & latency 
Polling interval
Long polling
Poll but don’t respond until there’s data
Poll again after data received or after the connection times out
Consumes server threads & connection resources 
Options!
Forever Frame
Periodic polling
Long polling
Websockets
(Server-Sent events)
SignalR
SignalR
Three-in-one!
“Persistent” client/server connection over best transport
Connection negotiation
Abstracts away the transport
Provides just one programming model
http://github.com/signalr/signalr - open source
C#, JavaScript, UWP
https://github.com/aspnet/signalr - new .NET Core version
Hello, SignalR
DEMO
What just happened?
The server is broadcasting a message every few seconds
Clients are receiving messages
Code looks easy
No polling or whatsoever (at least not in my code)
SignalR decides on transport mechanism used based on client + server
Connections and Hubs
Two programming models
PERSISTENT CONNECTION
Can communicate with 1..N clients
Requires a route to be defined
Limited to sending messages
You define the “protocol”
HUB
Abstraction over PersistentConnection
Can communicate with 1..N clients
Route automatically mapped (/signalr/hubs)
Can send messages and call methods
SignalR defines the protocol
Hello, Hubs
DEMO
Hubs
Hub methods can be called from client
Client methods can be called from hub
Target individual client
Target all clients
Target group of clients
http://shootr.signalr.net/
Clients
So far we have used...
On the server side
Host in any ASP.NET application (SignalR.Server)
On the client side
JavaScript (SignalR.JS)
But there’s more…
Connecting to
SignalR
DEMO
There is more!
On the server side
Host in any ASP.NET application (SignalR.Server) or using self-hosting (OWIN based)
Host on Azure
Scale out (Redis, Azure Service Bus)
(I did a NodeJS server as well, but don’t use it in production)
On the client side
JavaScript (SignalR.JS), Angular (AngularJs.SignalR.Hub)
Any .NET client (SignalR.Client)
UWP
iOS
Android
DeckCast
DEMO
.NET Core
ASP.NET Core Sockets
SignalR in the ASP.NET Core world
Improvements based on SignalR learnings:
No more jQuery
No more iframe transport
No more message replay after reconnect (memory usage, performance)
No more Hub-state (I did not talk about this “ViewState” because it’s evil)
Endpoint per Hub (/signalr/hubs  /signalr/...)
Scale-out now becomes scale-out (and not sending all messages everywhere)
Sticky sessions required (sad )
ASP.NET Core Sockets
New features:
Cross-platform (including things like RaspberryPi)
Binary data support (think sending images etc.)
Host-agnostic (HTTP works but also TCP/UDP/... sockets)
Protocol data format pluggable (JSON, protobuf, ...)
TypeScript client
...
Demo?
Will leave this one for you...
Under development! https://github.com/aspnet/signalr
Preview release mid-year
Release later this year
Conclusion
Conclusion
SignalR is three-in-one!
“Persistent” client/server connection over best transport
Abstracts away the transport
Provides just one programming model
Connections & Hubs
Connect various clients
Thank you!
http://blog.maartenballiauw.be
@maartenballiauw
1 of 32

Recommended

Nerd sniping myself into a rabbit hole... Streaming online audio to a Sonos s... by
Nerd sniping myself into a rabbit hole... Streaming online audio to a Sonos s...Nerd sniping myself into a rabbit hole... Streaming online audio to a Sonos s...
Nerd sniping myself into a rabbit hole... Streaming online audio to a Sonos s...Maarten Balliauw
360 views64 slides
Building a friendly .NET SDK to connect to Space by
Building a friendly .NET SDK to connect to SpaceBuilding a friendly .NET SDK to connect to Space
Building a friendly .NET SDK to connect to SpaceMaarten Balliauw
182 views47 slides
Microservices for building an IDE - The innards of JetBrains Rider - NDC Oslo... by
Microservices for building an IDE - The innards of JetBrains Rider - NDC Oslo...Microservices for building an IDE - The innards of JetBrains Rider - NDC Oslo...
Microservices for building an IDE - The innards of JetBrains Rider - NDC Oslo...Maarten Balliauw
406 views52 slides
Indexing and searching NuGet.org with Azure Functions and Search - .NET fwday... by
Indexing and searching NuGet.org with Azure Functions and Search - .NET fwday...Indexing and searching NuGet.org with Azure Functions and Search - .NET fwday...
Indexing and searching NuGet.org with Azure Functions and Search - .NET fwday...Maarten Balliauw
180 views32 slides
NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain... by
NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain...NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain...
NDC Sydney 2019 - Microservices for building an IDE – The innards of JetBrain...Maarten Balliauw
326 views53 slides
JetBrains Australia 2019 - Exploring .NET’s memory management – a trip down m... by
JetBrains Australia 2019 - Exploring .NET’s memory management – a trip down m...JetBrains Australia 2019 - Exploring .NET’s memory management – a trip down m...
JetBrains Australia 2019 - Exploring .NET’s memory management – a trip down m...Maarten Balliauw
280 views42 slides

More Related Content

More from Maarten Balliauw

NDC Oslo 2019 - Indexing and searching NuGet.org with Azure Functions and Search by
NDC Oslo 2019 - Indexing and searching NuGet.org with Azure Functions and SearchNDC Oslo 2019 - Indexing and searching NuGet.org with Azure Functions and Search
NDC Oslo 2019 - Indexing and searching NuGet.org with Azure Functions and SearchMaarten Balliauw
958 views44 slides
Approaches for application request throttling - Cloud Developer Days Poland by
Approaches for application request throttling - Cloud Developer Days PolandApproaches for application request throttling - Cloud Developer Days Poland
Approaches for application request throttling - Cloud Developer Days PolandMaarten Balliauw
1.1K views55 slides
Indexing and searching NuGet.org with Azure Functions and Search - Cloud Deve... by
Indexing and searching NuGet.org with Azure Functions and Search - Cloud Deve...Indexing and searching NuGet.org with Azure Functions and Search - Cloud Deve...
Indexing and searching NuGet.org with Azure Functions and Search - Cloud Deve...Maarten Balliauw
1.1K views47 slides
Approaches for application request throttling - dotNetCologne by
Approaches for application request throttling - dotNetCologneApproaches for application request throttling - dotNetCologne
Approaches for application request throttling - dotNetCologneMaarten Balliauw
246 views52 slides
CodeStock - Exploring .NET memory management - a trip down memory lane by
CodeStock - Exploring .NET memory management - a trip down memory laneCodeStock - Exploring .NET memory management - a trip down memory lane
CodeStock - Exploring .NET memory management - a trip down memory laneMaarten Balliauw
1.9K views43 slides
ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain... by
ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain...ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain...
ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain...Maarten Balliauw
1.2K views49 slides

More from Maarten Balliauw(20)

NDC Oslo 2019 - Indexing and searching NuGet.org with Azure Functions and Search by Maarten Balliauw
NDC Oslo 2019 - Indexing and searching NuGet.org with Azure Functions and SearchNDC Oslo 2019 - Indexing and searching NuGet.org with Azure Functions and Search
NDC Oslo 2019 - Indexing and searching NuGet.org with Azure Functions and Search
Maarten Balliauw958 views
Approaches for application request throttling - Cloud Developer Days Poland by Maarten Balliauw
Approaches for application request throttling - Cloud Developer Days PolandApproaches for application request throttling - Cloud Developer Days Poland
Approaches for application request throttling - Cloud Developer Days Poland
Maarten Balliauw1.1K views
Indexing and searching NuGet.org with Azure Functions and Search - Cloud Deve... by Maarten Balliauw
Indexing and searching NuGet.org with Azure Functions and Search - Cloud Deve...Indexing and searching NuGet.org with Azure Functions and Search - Cloud Deve...
Indexing and searching NuGet.org with Azure Functions and Search - Cloud Deve...
Maarten Balliauw1.1K views
Approaches for application request throttling - dotNetCologne by Maarten Balliauw
Approaches for application request throttling - dotNetCologneApproaches for application request throttling - dotNetCologne
Approaches for application request throttling - dotNetCologne
Maarten Balliauw246 views
CodeStock - Exploring .NET memory management - a trip down memory lane by Maarten Balliauw
CodeStock - Exploring .NET memory management - a trip down memory laneCodeStock - Exploring .NET memory management - a trip down memory lane
CodeStock - Exploring .NET memory management - a trip down memory lane
Maarten Balliauw1.9K views
ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain... by Maarten Balliauw
ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain...ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain...
ConFoo Montreal - Microservices for building an IDE - The innards of JetBrain...
Maarten Balliauw1.2K views
ConFoo Montreal - Approaches for application request throttling by Maarten Balliauw
ConFoo Montreal - Approaches for application request throttlingConFoo Montreal - Approaches for application request throttling
ConFoo Montreal - Approaches for application request throttling
Maarten Balliauw1.2K views
Microservices for building an IDE – The innards of JetBrains Rider - TechDays... by Maarten Balliauw
Microservices for building an IDE – The innards of JetBrains Rider - TechDays...Microservices for building an IDE – The innards of JetBrains Rider - TechDays...
Microservices for building an IDE – The innards of JetBrains Rider - TechDays...
Maarten Balliauw10.5K views
JetBrains Day Seoul - Exploring .NET’s memory management – a trip down memory... by Maarten Balliauw
JetBrains Day Seoul - Exploring .NET’s memory management – a trip down memory...JetBrains Day Seoul - Exploring .NET’s memory management – a trip down memory...
JetBrains Day Seoul - Exploring .NET’s memory management – a trip down memory...
Maarten Balliauw1.1K views
DotNetFest - Let’s refresh our memory! Memory management in .NET by Maarten Balliauw
DotNetFest - Let’s refresh our memory! Memory management in .NETDotNetFest - Let’s refresh our memory! Memory management in .NET
DotNetFest - Let’s refresh our memory! Memory management in .NET
Maarten Balliauw480 views
VISUG - Approaches for application request throttling by Maarten Balliauw
VISUG - Approaches for application request throttlingVISUG - Approaches for application request throttling
VISUG - Approaches for application request throttling
Maarten Balliauw817 views
What is going on - Application diagnostics on Azure - TechDays Finland by Maarten Balliauw
What is going on - Application diagnostics on Azure - TechDays FinlandWhat is going on - Application diagnostics on Azure - TechDays Finland
What is going on - Application diagnostics on Azure - TechDays Finland
Maarten Balliauw746 views
ConFoo - Exploring .NET’s memory management – a trip down memory lane by Maarten Balliauw
ConFoo - Exploring .NET’s memory management – a trip down memory laneConFoo - Exploring .NET’s memory management – a trip down memory lane
ConFoo - Exploring .NET’s memory management – a trip down memory lane
Maarten Balliauw523 views
Approaches to application request throttling by Maarten Balliauw
Approaches to application request throttlingApproaches to application request throttling
Approaches to application request throttling
Maarten Balliauw1.6K views
NuGet beyond Hello World - DotNext Piter 2017 by Maarten Balliauw
NuGet beyond Hello World - DotNext Piter 2017NuGet beyond Hello World - DotNext Piter 2017
NuGet beyond Hello World - DotNext Piter 2017
Maarten Balliauw702 views
Exploring .NET memory management (iSense) by Maarten Balliauw
Exploring .NET memory management (iSense)Exploring .NET memory management (iSense)
Exploring .NET memory management (iSense)
Maarten Balliauw381 views
Exploring .NET memory management - JetBrains webinar by Maarten Balliauw
Exploring .NET memory management - JetBrains webinarExploring .NET memory management - JetBrains webinar
Exploring .NET memory management - JetBrains webinar
Maarten Balliauw1.3K views
DNS for Developers - ConFoo Montreal by Maarten Balliauw
DNS for Developers - ConFoo MontrealDNS for Developers - ConFoo Montreal
DNS for Developers - ConFoo Montreal
Maarten Balliauw628 views
Get more than a cache back! - ConFoo Montreal by Maarten Balliauw
Get more than a cache back! - ConFoo MontrealGet more than a cache back! - ConFoo Montreal
Get more than a cache back! - ConFoo Montreal
Maarten Balliauw619 views

Recently uploaded

IETF 118: Starlink Protocol Performance by
IETF 118: Starlink Protocol PerformanceIETF 118: Starlink Protocol Performance
IETF 118: Starlink Protocol PerformanceAPNIC
414 views22 slides
hamro digital logics.pptx by
hamro digital logics.pptxhamro digital logics.pptx
hamro digital logics.pptxtupeshghimire
10 views36 slides
information by
informationinformation
informationkhelgishekhar
10 views4 slides
Affiliate Marketing by
Affiliate MarketingAffiliate Marketing
Affiliate MarketingNavin Dhanuka
17 views30 slides
ATPMOUSE_융합2조.pptx by
ATPMOUSE_융합2조.pptxATPMOUSE_융합2조.pptx
ATPMOUSE_융합2조.pptxkts120898
35 views70 slides
Building trust in our information ecosystem: who do we trust in an emergency by
Building trust in our information ecosystem: who do we trust in an emergencyBuilding trust in our information ecosystem: who do we trust in an emergency
Building trust in our information ecosystem: who do we trust in an emergencyTina Purnat
110 views18 slides

Recently uploaded(9)

IETF 118: Starlink Protocol Performance by APNIC
IETF 118: Starlink Protocol PerformanceIETF 118: Starlink Protocol Performance
IETF 118: Starlink Protocol Performance
APNIC414 views
ATPMOUSE_융합2조.pptx by kts120898
ATPMOUSE_융합2조.pptxATPMOUSE_융합2조.pptx
ATPMOUSE_융합2조.pptx
kts12089835 views
Building trust in our information ecosystem: who do we trust in an emergency by Tina Purnat
Building trust in our information ecosystem: who do we trust in an emergencyBuilding trust in our information ecosystem: who do we trust in an emergency
Building trust in our information ecosystem: who do we trust in an emergency
Tina Purnat110 views
The Dark Web : Hidden Services by Anshu Singh
The Dark Web : Hidden ServicesThe Dark Web : Hidden Services
The Dark Web : Hidden Services
Anshu Singh14 views
How to think like a threat actor for Kubernetes.pptx by LibbySchulze1
How to think like a threat actor for Kubernetes.pptxHow to think like a threat actor for Kubernetes.pptx
How to think like a threat actor for Kubernetes.pptx
LibbySchulze15 views
Marketing and Community Building in Web3 by Federico Ast
Marketing and Community Building in Web3Marketing and Community Building in Web3
Marketing and Community Building in Web3
Federico Ast14 views

SignalR - Realtime client/server communication (iSense)

  • 2. R
  • 3. Who am I? Maarten Balliauw Antwerp, Belgium Developer Advocate, JetBrains Founder, MyGet AZUG Focus on web ASP.NET MVC, Azure, SignalR, ... Former MVP Azure & ASPInsider Big passion: Azure http://blog.maartenballiauw.be @maartenballiauw
  • 4. Agenda Why real-time & how? Meet SignalR Connections and Hubs Clients .NET Core Q&A
  • 6. Users want the latest info, now! Twitter – live searches/updates Stock tickers Auctions Live scores Real-time notifications Collaborative apps Live user analytics Online gaming / browser games … 6
  • 7. HTTP is and old beast Never designed for real-time communications Web is request-response Web is stateless Websockets to the rescue!
  • 8. Websockets Extension to HTTP Provide raw sockets over HTTP Full-duplex, low latency Traverses proxies But… Not every proxy server supports it Not every webserver supports it Not every browser supports it Some antivirus blocks it They are raw sockets! (protocol: up to you) http://websocketstest.com/
  • 9. Forever Frame Server tells client that response is chuncked Client keeps connection open untill server closes it Server pushes data to the client followed by 0 Consumes server threads HTTP/1.1 200 OK Content-Type: text/plain Transfer-Encoding: chunked <script>eval("... ")</script>0 <script>eval("... ")</script>0
  • 10. Periodic polling Poll from time to time using Ajax Delay in communications due to polling interval Wastes bandwidth & latency  Polling interval
  • 11. Long polling Poll but don’t respond until there’s data Poll again after data received or after the connection times out Consumes server threads & connection resources 
  • 12. Options! Forever Frame Periodic polling Long polling Websockets (Server-Sent events)
  • 14. SignalR Three-in-one! “Persistent” client/server connection over best transport Connection negotiation Abstracts away the transport Provides just one programming model http://github.com/signalr/signalr - open source C#, JavaScript, UWP https://github.com/aspnet/signalr - new .NET Core version
  • 16. What just happened? The server is broadcasting a message every few seconds Clients are receiving messages Code looks easy No polling or whatsoever (at least not in my code) SignalR decides on transport mechanism used based on client + server
  • 18. Two programming models PERSISTENT CONNECTION Can communicate with 1..N clients Requires a route to be defined Limited to sending messages You define the “protocol” HUB Abstraction over PersistentConnection Can communicate with 1..N clients Route automatically mapped (/signalr/hubs) Can send messages and call methods SignalR defines the protocol
  • 20. Hubs Hub methods can be called from client Client methods can be called from hub Target individual client Target all clients Target group of clients http://shootr.signalr.net/
  • 22. So far we have used... On the server side Host in any ASP.NET application (SignalR.Server) On the client side JavaScript (SignalR.JS) But there’s more…
  • 24. There is more! On the server side Host in any ASP.NET application (SignalR.Server) or using self-hosting (OWIN based) Host on Azure Scale out (Redis, Azure Service Bus) (I did a NodeJS server as well, but don’t use it in production) On the client side JavaScript (SignalR.JS), Angular (AngularJs.SignalR.Hub) Any .NET client (SignalR.Client) UWP iOS Android
  • 27. ASP.NET Core Sockets SignalR in the ASP.NET Core world Improvements based on SignalR learnings: No more jQuery No more iframe transport No more message replay after reconnect (memory usage, performance) No more Hub-state (I did not talk about this “ViewState” because it’s evil) Endpoint per Hub (/signalr/hubs  /signalr/...) Scale-out now becomes scale-out (and not sending all messages everywhere) Sticky sessions required (sad )
  • 28. ASP.NET Core Sockets New features: Cross-platform (including things like RaspberryPi) Binary data support (think sending images etc.) Host-agnostic (HTTP works but also TCP/UDP/... sockets) Protocol data format pluggable (JSON, protobuf, ...) TypeScript client ...
  • 29. Demo? Will leave this one for you... Under development! https://github.com/aspnet/signalr Preview release mid-year Release later this year
  • 31. Conclusion SignalR is three-in-one! “Persistent” client/server connection over best transport Abstracts away the transport Provides just one programming model Connections & Hubs Connect various clients

Editor's Notes

  1. https://pixabay.com
  2. https://pixabay.com/en/tires-used-tires-pfu-garbage-1846674/
  3. https://pixabay.com/en/tires-used-tires-pfu-garbage-1846674/
  4. https://pixabay.com/en/tires-used-tires-pfu-garbage-1846674/
  5. Open VS2017 Create a new ASP.NET Empty Website Install-Package Microsoft.AspNet.SignalR Note server library, client script, jQuery dependency Add startup class: public class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR(); } } Add a class: public class TimeConnection : PersistentConnection { } Map the connection: app.MapSignalR<TimeConnection>("/time"); Add an infinite loop: ThreadPool.QueueUserWorkItem(_ => { var connection = GlobalHost.ConnectionManager.GetConnectionContext<TimeConnection>(); while (true) { connection.Connection.Broadcast(DateTime.UtcNow.ToString()); Thread.Sleep(1000); } }); Add some HTML: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script> <script src="Scripts/jquery.signalR-2.2.1.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function () { var connection = $.connection('time'); connection.received(function(data) { $('h1').text('The time is ' + data); }); connection.start(); }); </script> </head> <body> <h1>The time is now!</h1> </body> </html> Now let’s take things easy… How does all of this work? Note that we are sending data TO THE CLIENT by just broadcasting on the connection View Chrome developer tools, in this case web sockets Add to web.config: (.vs\config\applicationhost.config) <system.webServer> <webSocket enabled="false"/> </system.webServer> View Chrome again, notice now event stream is used instead Install-Package Microsoft.AspNet.SignalR.Sample and show stock ticker in two browsers
  6. https://pixabay.com/en/tires-used-tires-pfu-garbage-1846674/
  7. Add simple chat hub [HubName("simplechat")] public class SimpleChatHub : Hub { private static readonly Dictionary<string, string> _users = new Dictionary<string, string>(); public async Task Join(string username) { _users[Context.ConnectionId] = username; await Clients.All.userJoined(username); } public async Task SendMessage(string message) { await Clients.All.messageReceived( _users[Context.ConnectionId], message); } } Explain: user joins, we store username passed linked to connection id We then call back to all clients, calling a JS function on there Client code: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script> <script src="Scripts/jquery.signalR-2.2.1.min.js" type="text/javascript"></script> <script src="/signalr/hubs"></script> <script type="text/javascript"> $(function () { var username = prompt('What is your name?'); $.connection.hub.logging = true; var hub = $.connection.simplechat; // User joined hub.client.userJoined = function (who) { $("#messages").append('<li><em>' + who + ' joined the chat.</em></li>'); }; // Message received hub.client.messageReceived = function (who, what) { $("#messages").append('<li>' + who + ': ' + what + '</li>'); }; // Join the chat $.connection.hub.start().done(function () { hub.server.join(username); }); // Bind client UI $('#message').change(function () { hub.server.sendMessage($('#message').val()); $('#message').val(''); $('#message').focus(); }); }); </script> </head> <body> <h1>Chat</h1> <ul id="messages"></ul> <input type="text" id="message"/> </body> </html> Explore hubs some more: different properties on the hub (clients all, per group, individual, ...)
  8. Create a new Console application Install-Package Microsoft.AspNet.SignalR.Client Add code var connection = new Connection("http://localhost:51736/time"); connection.Received += data => { Console.Clear(); Console.WriteLine(data); }; connection.Start(); Cool, so connection works! Now let’s try hubs and connect to our simple chat. Add code private static async Task RunAsync(string[] args) { _connection = new HubConnection("http://localhost:51736/signalr"); _hub = _connection.CreateHubProxy("simplechat"); _hub.On <string>("userJoined", userName => { Console.ForegroundColor = ConsoleColor.DarkYellow; Console.WriteLine($"{userName} joined."); Console.ResetColor(); }); _hub.On<string, string>("messageReceived", (userName, message) => { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"{userName}: {message}"); Console.ResetColor(); }); await _connection.Start(); // Join the chat Console.WriteLine("Your username:"); var myName = Console.ReadLine().Trim(); await _hub.Invoke("join", myName); // Send messages while (true) { var myMessage = Console.ReadLine().Trim(); if (!string.IsNullOrEmpty(myMessage)) { await _hub.Invoke("sendMessage", myMessage); } } }
  9. Open DeckCast Show people around and tell them about deck.js Show the presenter mode and client mode on the web Start a console based viewer Start a console based presenter
  10. https://pixabay.com/en/tires-used-tires-pfu-garbage-1846674/