From d876eaeef029cbba9f39fc0e2a3698e4eccf9534 Mon Sep 17 00:00:00 2001 From: Rachel Appel Date: Wed, 7 Mar 2018 16:59:22 -0800 Subject: [PATCH] Draft signalr core intro (#5559) * Draft signalr core intro * mods from feedback * acrolinx mods * acrolinx updates * feedback mods * feedback mods --- .../signalr/introduction-signalr-core.md | 63 ++++++++++++++++++ .../_static/signalr-core-architecture.png | Bin 0 -> 15945 bytes aspnetcore/toc.md | 3 + 3 files changed, 66 insertions(+) create mode 100644 aspnetcore/signalr/introduction-signalr-core.md create mode 100644 aspnetcore/signalr/introduction-signalr-core/_static/signalr-core-architecture.png diff --git a/aspnetcore/signalr/introduction-signalr-core.md b/aspnetcore/signalr/introduction-signalr-core.md new file mode 100644 index 0000000000..83b0be3347 --- /dev/null +++ b/aspnetcore/signalr/introduction-signalr-core.md @@ -0,0 +1,63 @@ +--- +title: Introduction to SignalR on ASP.NET Core +author: rachelappel +description: Learn how the ASP.NET Core SignalR library simplifies adding real-time web functionality to apps. +manager: wpickett +ms.author: rachelap +ms.custom: mvc +ms.date: 03/07/2018 +ms.prod: aspnet-core +ms.technology: aspnet +ms.topic: article +uid: signalr/introduction-signalr-core +--- +# Introduction to SignalR + +By [Rachel Appel](https://twitter.com/rachelappel) + +## What is SignalR? + +ASP.NET Core SignalR is a library that simplifies adding real-time web functionality to apps. Real-time web functionality enables server-side code to push content to clients instantly. + +Good candidates for SignalR: + +* Apps that require high frequency updates from the server. Examples are gaming, social networks, voting, auction, maps, and GPS apps. +* Dashboards and monitoring apps. Examples include company dashboards, instant sales updates, or travel alerts. +* Collaborative apps. Whiteboard apps and team meeting software are examples of collaborative apps. +* Apps that require notifications. Social networks, email, chat, games, travel alerts, and many other apps use notifications. + +SignalR provides an API for creating server-to-client [remote procedure calls (RPC)](https://wikipedia.org/wiki/Remote_procedure_call). The RPCs call JavaScript functions on clients from server-side .NET Core code. + +SignalR for ASP.NET Core: + +* Handles connection management automatically. +* Enables broadcasting messages to all connected clients simultaneously. For example, a chat room. +* Enables sending messages to specific clients or groups of clients. +* Is open-sourced at [GitHub](https://github.com/aspnet/SignalR). +* Scales nicely. + +The connection between the client and server is persistent, unlike an HTTP connection. + +## Transports + +SignalR abstracts over a number of techniques for building real-time web applications. [WebSockets](https://tools.ietf.org/html/rfc7118) is the optimal transport, but other techniques like Server-Sent Events and Long Polling can be used when those aren't available. SignalR will automatically detect and initialize the appropriate transport based on features supported on the server and client. + + +## Hubs and Endpoints + +SignalR uses Hubs and Endpoints to communicate between clients and servers. The Hubs API covers the most scenarios. + +A hub is a high-level pipeline built upon the Endpoint API that allows your client and server to call methods on each other. SignalR handles the dispatching across machine boundaries automatically, allowing clients to call methods on the server as easily as local methods, and vice versa. Hubs allow passing strongly-typed parameters to methods, which enables model binding. SignalR provides two built-in hub protocols: a text protocol based on JSON and a binary protocol based on [MessagePack](https://msgpack.org/). MessagePack generally creates smaller messages than when using JSON. Older browsers must support [XHR level 2](https://caniuse.com/#feat=xhr2) to provide MessagePack protocol support. + +Hubs call client-side code by sending messages using the active transport. The messages contain the name and parameters of the client-side method. Objects sent as method parameters are deserialized using the configured protocol. The client tries to match the name to a method in the client-side code. When a match happens, the client method runs using the deserialized parameter data. + +Endpoints provide a raw socket-like API, enabling them to read and write from the client. It's up to the developer to handle grouping, broadcasting, and other functions. The Hubs API is built on top of the Endpoints layer. + +The following diagram shows the relationship between hubs, endpoints, and clients. + +![SignalR map](introduction-signalr-core/_static/signalr-core-architecture.png) + + +## Related Resources + +[Get Started with SignalR for ASP.NET Core](get-started-signalr-core) \ No newline at end of file diff --git a/aspnetcore/signalr/introduction-signalr-core/_static/signalr-core-architecture.png b/aspnetcore/signalr/introduction-signalr-core/_static/signalr-core-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..2db8c5e5e6cc39ceadc6d6578debc9786064eeb5 GIT binary patch literal 15945 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