Real-Time Web Chat Applications

栏目: IT技术 · 发布时间: 4年前

内容简介:We explore SignalR server/client technologies to build chat applications for the web.In this day and age, software systems have an undeniable need for real-time communications. Thankfully despite the hurdles, there are severalLet's pick one of the most pop

We explore SignalR server/client technologies to build chat applications for the web.

In this day and age, software systems have an undeniable need for real-time communications. Thankfully despite the hurdles, there are several techniques to enable real-time communications and polished frameworks that do much of the heavy lifting for developers. However, it is 2020, and software isn't siloed to specific platforms. As developers try to bring on newer platforms/devices to connect in real time, flexibility is key for technology stacks.

Let's pick one of the most popular real-time communication frameworks to dig into — the beloved SignalR on top of ASP.NET Core. And just like every human for the past million years, let's use chat apps as our playground. In a way, chat applications are the "Hello world" examples to prove real-time actually works. But let's use some fun APIs and try to build the same app across variety of platforms to see how SignalR caters to modern cross-platform needs, starting with web clients. And a little sprinkle of some polished UI never hurt good ole chat apps. Let's go.

SignalR

SignalR facilitates adding real-time communication to web applications running on ASP.NET and connected clients across wide variety of platforms. While SignalR started years back with ASP.NET MVC, the latest reboot is called SignalR Core, which runs on ASP.NET Core and brings a ton of maturity. Developers benefit from SignalR providing a uniform API canvas for connection and client management, as well as scaling to handle increased traffic.

SignalR provides APIs for bidirectional remote procedure calls (RPCs) between server and client and abstracts away real-time communication complexities. This is, by far, the biggest benefit of bringing in SignalR to facilitate real time communications — shield developers from having to deal with network layer implementations. Given a specific server/client pair, SignalR expertly chooses the best transport mechanism for real-time exchanges. The most common techniques used are: WebSockets, Server-Sent Events and Long Polling, in order of gracious fall-back plans.

SignalR Back End

SignalR uses the concept of hubs on the server side — a literal hub in a hub-spoke model. The SignalR Hub works as an in-memory object on the server side that all clients connect up to for real time communications. The hub allows SignalR to send and receive messages across machine boundaries, thus allowing clients to call methods on the server and vice versa. In addition to method invocation across programming paradigms, hubs allows transport of named and strongly typed parameters. SignalR automatically provides object serialization/deserialization to aid the process.

Let's build a quick demo chat application with a SignalR backend. Yes, yet another chat app — but demonstrating quick developer tricks and taking the chat app cross-platform. First, we have to begin with our server-side SignalR Hub. We'll start with a new ASP.NET Core Web Application running on .NET Core 3.0 — you can do this in VS on Windows, VS Code, VS for Mac or plain old CLI commands. We'll define our ChatHub on the server-side like below. If you envision having multiple hubs, it may make sense to organize them in a hubs folder:

using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;

namespace SignalRChat.Hubs
{
    public class ChatHub : Hub
    {
        public async Task SendMessage(string user, string message)
        {
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }
    }
}

Essentially, we're defining a method called SendMessage() on the server that all connected clients can call and send in parameter values. When invoked, this server-side method turns around and tries to call ReceiveMessage() method on clients — in particular, every connected client through Clients.All.SendAsync() . The client-side methods would need to be defined in each client across platforms. Next up is a little bit of configuration in the ASP.NET Core app's Startup.cs file - essentially adding a middleware to route appropriate requests to the SignalR Hub, like so:

using SignalRChat.Hubs;

namespace SignalRChat
{
    public class Startup
    {
        ...

        public void ConfigureServices(IServiceCollection services)
        {
            ...
            services.AddSignalR();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
              ...

            app.UseEndpoints(endpoints =>
            {
                ...
                endpoints.MapHub<ChatHub>("/chatHub");
            });
        }
    }
}

Web Client

With our SignalR server side backend all squared up, we'll begin with clients across various platforms, starting with web. While the SignalR bits to power hubs server side is included in ASP.NET Core 3.0 shared framework, the client side packages need to be brought in manually. Sure NuGet packages can be brought into projects, but a smarter way is to use Library Manager to get the client side dependencies through Unpkg . This ensures the SignalR JS files are being delivered through the Unpkg Content Delivery Network (CDN) — close to anywhere in the world where your users may be. Two CLI commands do the trick, adding the dependencies and moving them into the static files repository:

dotnet tool install -g Microsoft.Web.LibraryManager.Cli

libman install @microsoft/signalr@latest -p unpkg -d wwwroot/js/signalr --files dist/browser/signalr.js --files dist/browser/signalr.min.js

Once done, you should see the static dependencies brought in, as well as, a libman.json file which provides details of provider, packages and destination, like so:

{
  "version": "1.0",
  "defaultProvider": "unpkg",
  "libraries": [
    {
      "library": "@microsoft/signalr@latest",
      "destination": "wwwroot/js/signalr",
      "files": [
        "dist/browser/signalr.js",
        "dist/browser/signalr.min.js"
      ]
    }
  ]
}

Now, let's write some boilerplate code, like in the SignalR docs , to have some UI for our SignalR-powered chat frontend. We essentially need a couple of input controls for chat, and a list to show to display chat messages. This goes in the ASP.NET site's Index.cshtml file in Pages directory:

@page
    <div>
        <div> </div>
        <div>
            <div>User</div>
            <div><input type="text" id="userInput" /></div>
        </div>
        <div>
            <div>Message</div>
            <div><input type="text" id="messageInput" /></div>
        </div>
        <div> </div>
        <div>
            <div>
                <input type="button" id="sendButton" value="Send Message" />
            </div>
        </div>
    </div>
    <div>
        <div>
            <hr />
        </div>
    </div>
    <div>
        <div>
            <ul id="messagesList"></ul>
        </div>
    </div>
<script src="~/js/signalr/dist/browser/signalr.js"></script>
<script src="~/js/chat.js"></script>

And now we'll add the JavaScript code to power web clients to talk to our SignalR Hub. This could go in a chat.js file:

"use strict";

var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();

document.getElementById("sendButton").disabled = true;

connection.on("ReceiveMessage", function (user, message) {
    var msg = message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
    var encodedMsg = user + " says " + msg;
    var li = document.createElement("li");
    li.textContent = encodedMsg;
    document.getElementById("messagesList").appendChild(li);
});

connection.start().then(function () {
    document.getElementById("sendButton").disabled = false;
}).catch(function (err) {
    return console.error(err.toString());
});

document.getElementById("sendButton").addEventListener("click", function (event) {
    var user = document.getElementById("userInput").value;
    var message = document.getElementById("messageInput").value;
    connection.invoke("SendMessage", user, message).catch(function (err) {
        return console.error(err.toString());
    });
    event.preventDefault();
});

The code above essentially does three basic things:

SendMessage()
ReceiveMessage()

That's it for a basic chat application powered by SignalR on both server and client side. Let's fire up two browser instances of our local app — real time chat just works.

Real-Time Web Chat Applications

Connection Management

SignalR Hubs on the server side offer a plethora of APIs for connection management. Some really useful ones are:

  • Hubs expose a context property that carries a wealth of information about connection with clients, including unique identifiers for each connection/user
  • A clients property holds the collection of all connected clients and allows for fine tuned management
  • SignalR Hubs can be strongly typed through hub where client methods need to implement interfaces
  • SignalR Hubs raise events when clients connect/disconnect, as well as, having reconnect functionality for select client platforms

Since we started with a chat application, a common business scenario is to build a chatroom. Thankfully, SignalR Hubs offer granular control over how messages are distributed to connected clients. As clients connect up to the hub, they can be put into groups and messages can be streamed to the caller/everyone connected/named groups etc. Here's some sample code in our SignalR Hub:

public Task SendMessageToCaller(string message)
{
    return Clients.Caller.SendAsync("ReceiveMessage", message);
}

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "ChatRoom");
    await base.OnConnectedAsync();
}

public override async Task OnDisconnectedAsync(Exception exception)
{
    await Groups.RemoveFromGroupAsync(Context.ConnectionId, "ChatRoom");
    await base.OnDisconnectedAsync(exception);
}

public Task SendMessageToGroup(string message)
{
    return Clients.Group("ChatRoom").SendAsync("ReceiveMessage", message);
}

The code above should be self-explanatory; we're simply grouping clients and sending messages selectively. Here's the result, after some UI cleanup:

Real-Time Web Chat Applications

Transport Configuration

One other interesting aspect of modern SignalR is configurability of network stack. As mentioned before, SignalR chooses the best possible fit for network transport given the server-client pair, gracefully switching between WebSockets, Server-Sent Events and Long Polling. For most modern web clients using evergreen browsers, the obvious transport choice is WebSockets. You get dependable bi-directional communication between client/server. Developers should never be in doubt as to what SignalR is doing under the covers with network transport. While most browser developer tools will show traffic patterns and content, sophisticated network proxies likeFiddlerprovide developers with even more ammunition to manipulate/test/record SignalR communications.

SignalR also has serialization/deserialization built-in, so that developers need not be constrained to passing strings back and forth. Full objects can be transported and flattened/hydrated across platform barriers. The most common way to pass around seriliazed data is JSON and SignalR is pre-configured to use JSON - the default is JSON serialization/deserialization built into .NET, but one can also switch to using NewtonSoft.Json. Even with WebSockets network, one can look under the covers to see human-readable JSON being sent across the wire, as seen in Chromium DevTools here:

Real-Time Web Chat Applications

Have performance and bandwidth concerns for passing too much data around for your SignalR app? MessagePack is a popular binary serialization format that is much more compact than JSON, and SignalR supports MessagePack with a tiny bit of configuration on server and client. Binary serialization, however, means that SignalR message content is no longer readable, unless the bytes are passed through a MessagePack parser. So developers lose a bit of transparency, but the app gains efficacy and performance.

To configure MessagePack usage in SignalR communications, developers need to pull in the Microsoft.AspNetCore.SignalR.Protocols.MessagePack NuGet package server-side and explicitly mention the MessagePack protocol when adding the SignalR Middleware, like so:

services.AddSignalR().AddMessagePackProtocol();

One can also customize how MessagePack formats data and simple attributes can define how objects are serialized. On the web client side, MessagePack support with SignalR is provided by the @microsoft/signalr-protocol-msgpack npm package, which can be brought in like so:

npm install @microsoft/signalr-protocol-msgpack

We're essentially referencing some Node modules, which can be linked or the corresponding JS files brought in directly into the web project, like below:

Real-Time Web Chat Applications

Once our dependencies are in place, we can initialize the use of MessagePack as our web client goes up to connect to the SignalR Hub on server, like so:

var connection = new signalR.HubConnectionBuilder()
                .withUrl("/chatHub")
                .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol())
                .build();

With MessagePack protocol in use, we should see network traffic serialized in binary format - better performance through smaller byte packages for the win!

Real-Time Web Chat Applications

Conversational UI

Hello world chat applications are fun first steps for real time apps. More realistic real-time apps can help automate complex enterprise workflows and the chat backend could like be an intelligent chatbot. There are a plethora of fabulous bot frameworks to hook up your chat apps to — all with rich tooling and SDKs for most platforms. And SignalR is happy to be the abstraction developers love over network complexities.

One other thing developers may need when building real-world chat apps — yes, polished and performant UI. When your goal is to automate workflows intelligently and deliver value, building chat UI by hand is too laborious and time consuming. EnterConversational UI - modern UI components for chatbots across Telerik/Kendo UI technologies. With wide framework compatibility, polished chat UI with detailed documentation and flexible APIs, developers can be on their way to implementing natural chat conversational flow quickly.

For SignalR powered web clients, Conversational UI can be brought in for a wide variety of platforms: through Telerik UI for ASP.NETAjax/ MVC /Core or Kendo UI forjQuery/ Angular / React /Vue. And these being web apps, they do not need to constrained to desktop browsers. Developers can absolutely build mobile-first PWA apps with polished chat UI. Hallelujah. Check out some of the quick demos of what's possible with real time chat applications that can automate workflows:

Real-Time Web Chat Applications

Real-Time Web Chat Applications

Wrap-Up

Life happens in real time and information exchange should be the same way. Turns out, there are countless modern applications that don't just benefit, but actively depend on real-time communications to be functional. SignalR has tremendous promise as a framework that aids in building real-time apps. With a ton of configurability, SignalR Hubs are easy to set up server-side. And building web clients connected to SignalR Hubs is just as easy, with flexible APIs and wonderful abstraction of network complexities. So SignalR powered web apps are a done deal — easy peasy.

But could we stretch real-time apps to other platforms, like desktop or mobile? Yes, Absolutely. While we take on other platforms to support SignalR in subsequent articles, the web continues to enjoy ubiquity and real time apps grow to be more valuable each day. Developers and consumers rejoice.


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

创新者的解答

创新者的解答

【美】克莱顿•克里斯坦森、【加】迈克尔·雷纳 / 中信出版社 / 2013-10-10 / 49.00

《创新者的解答》讲述为了追求创新成长机会,美国电信巨子AT&T在短短10年间,总共耗费了500亿美元。企业为了保持成功记录,会面对成长的压力以达成持续获利的目标。但是如果追求成长的方向出现偏误,后果往往比没有成长更糟。因此,如何创新,并选对正确方向,是每个企业最大的难题。 因此,如何创新,并导向何种方向,便在于创新结果的可预测性─而此可预测性则来自于正确的理论依据。在《创新者的解答》中,两位......一起来看看 《创新者的解答》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

html转js在线工具
html转js在线工具

html转js在线工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具