1. Einführung
Signal ist ein von Microsoft unterstütztes HTML-Websocket-Framework, das auf der Dot NET-Plattform läuft. Der Hauptzweck seines Erscheinens besteht darin, dem Server zu ermöglichen, Nachrichten aktiv an die Clientseite zu senden (Push), sodass der Client die Anfrage nicht erneut senden oder Polling-Technologie verwenden muss, um die Nachricht zu erhalten.
Sie können die offizielle Website besuchen: https://github.com/SignalR/ für weitere Informationen.
2. Was ist Asp.net SignalR?
Asp.net SignalR ist eine Klassenbibliothek von Microsoft zur Realisierung von Echtzeitkommunikation. Unter normalen Umständen verwendet SignalR die lange Abfragemethode von JavaScript, um die Client- und Serverkommunikation zu implementieren. Mit dem Aufkommen von WebSockets in HTML5 unterstützt SignalR auch die WebSockets-Kommunikation. Darüber hinaus können die von SignalR entwickelten Programme nicht nur in IIS gehostet werden, sondern können auch in jeder Anwendung gehostet werden, einschließlich Konsolen, Client-Programmen und Windows-Diensten. Sie unterstützen auch Mono, was bedeutet, dass sie übergreifender Einsatz sein können -Plattform auf Linux-Umgebung.
Es gibt zwei Arten von Objekten in SignalR:
Http Persistent Connection-Objekt: Wird zur Lösung der Funktion langfristiger Verbindungen verwendet. Der Client kann auch aktiv Daten vom Server anfordern, und der Server muss nicht zu viele Details implementieren. Er muss nur die fünf in PersistentConnection bereitgestellten Ereignisse verarbeiten: OnConnected, OnReconnected, OnReceived, OnError und OnDisconnect.
Hub (Hub)-Objekt: Wird zur Lösung der Funktion des Echtzeit-Informationsaustauschs verwendet. Der Server kann die URL verwenden, um einen oder mehrere Hubs zu registrieren. Solange er mit diesem Hub verbunden ist, kann er mit allen geteilt werden Clients und Informationen an den Server gesendet, und der Server kann das Skript des Clients aufrufen.
SignalR kapselt den gesamten Informationsaustausch, um alle auf dem Server deklarierten Hub-Informationen zu generieren. NET ist auf Proxy angewiesen, um Proxy-Objekte zu generieren konvertiert JSON in Objekte.
Da SignalR für den Echtzeiteinsatz konzipiert ist, bestimmt dies seine Verwendung. Die konkret anwendbaren Szenarien sind wie folgt:
Chatrooms, wie Online-Kundendienstsysteme, IM-Systeme usw.
Aktualisierungen von Aktienkursen in Echtzeit
Nachrichten-Push-Dienste
Echtzeit-Push von Charakterstandorte im Spiel
Mein Unternehmen entwickelt derzeit ein Online-Kundendienstsystem.
3. Implementierungsmechanismus
Der Implementierungsmechanismus von SignalR ähnelt .NET WCF oder Remoting, beide werden mithilfe von Remote-Agenten implementiert. In Bezug auf die spezifische Verwendung gibt es zwei Schnittstellen mit unterschiedlichen Zwecken: PersistentConnection und Hubs implementieren eine langfristige Javascript-Abfrage (ähnlich wie Comet), und Hub wird verwendet, um das Problem des Echtzeit-Informationsaustauschs zu lösen dynamisch laden Durch Eingabe der Ausführungsmethode implementiert. SignalR kapselt den gesamten Verbindungs- und Informationsaustauschprozess sehr schön. Der Client und der Server verwenden alle JSON, um Daten auszutauschen.
Das Folgende ist der gesamte Prozess der Verwendung der Hubs-Schnittstelle:
1. Definieren Sie die entsprechende Hub-Klasse auf der Serverseite.
2. Definieren Sie die Proxy-Klasse, die der Hub-Klasse auf dem Client entspricht Seite;
3. Stellen Sie eine Verbindung zwischen dem Client und dem Server her
4 5. Nach Erhalt der Anfrage kann der Server eine Nachricht an einen bestimmten Client/eine bestimmte Gruppe oder an alle Clients senden (Broadcast).
Verwenden Sie Visual Studio 2013, um ein MVC-Projekt zu erstellen.
Installieren Sie das SignalR-Paket über Nuget. Klicken Sie mit der rechten Maustaste auf die Referenz „Nuget-Pakete verwalten auswählen“. Geben Sie SignalR in das angezeigte Fenster ein, um das SignalR-Paket für die Installation zu finden.
Nach erfolgreicher Installation von SignalR werden die Skripte der SignalR-Bibliothek zum Ordner „Skripte“ hinzugefügt. Wie unten gezeigt:
using System; using Microsoft.AspNet.SignalR; namespace SignalDemo { public class ServerHub : Hub { private static readonly char[] Constant = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; /// <summary> /// 供客户端调用的服务器端代码 /// </summary> /// <param name="message"></param> public void Send(string message) { var name = GenerateRandomName(4); // 调用所有客户端的sendMessage方法 Clients.All.sendMessage(name, message); } /// <summary> /// 产生随机用户名函数 /// </summary> /// <param name="length">用户名长度</param> /// <returns></returns> public static string GenerateRandomName(int length) { var newRandom = new System.Text.StringBuilder(62); var rd = new Random(); for (var i = 0; i < length; i++) { newRandom.Append(Constant[rd.Next(62)]); } return newRandom.ToString(); } } }
using Microsoft.Owin; using Owin; [assembly: OwinStartupAttribute(typeof(SignalDemo.Startup))] namespace SignalDemo { public partial class Startup { #region MyRegion public void Configuration(IAppBuilder app) { app.MapSignalR(); ConfigureAuth(app); } #endregion } }
using System.Web.Mvc; namespace SignalDemo.Controllers { public class HomeController : Controller { public ActionResult Chat() { return View(); } } }
@{ ViewBag.Title = "Chat"; } <h2>Chat</h2> <div class="container"> <input type="text" id="message" /> <input type="button" id="sendmessage" value="Send" /> <input type="hidden" id="displayname" /> <ul id="discussion"></ul> </div> @section scripts { <!--引用SignalR库. --> <script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script> <!--引用自动生成的SignalR 集线器(Hub)脚本.在运行的时候在浏览器的Source下可看到 --> <script src="~/signalr/hubs"></script> <script> $(function () { // 引用自动生成的集线器代理 var chat = $.connection.serverHub; // 定义服务器端调用的客户端sendMessage来显示新消息 chat.client.sendMessage = function (name, message) { // 向页面添加消息 $('#discussion').append('<li><strong>' + htmlEncode(name) + '</strong>: ' + htmlEncode(message) + '</li>'); }; // 设置焦点到输入框 $('#message').focus(); // 开始连接服务器 $.connection.hub.start().done(function () { $('#sendmessage').click(function () { // 调用服务器端集线器的Send方法 chat.server.send($('#message').val()); // 清空输入框信息并获取焦点 $('#message').val('').focus(); }); }); }); // 为显示的消息进行Html编码 function htmlEncode(value) { var encodedValue = $('<div />').text(value).html(); return encodedValue; } </script> }
修改App_Start文件夹内的RoutConfig类,将Action方法默认设置为Chat
using System.Web.Mvc; using System.Web.Routing; namespace SignalDemo { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Chat", id = UrlParameter.Optional } ); } } }
到此,我们的例子就实现完成了,接下来我们先来看看运行效果,之后再来解释到底SignalR是如何来完成广播消息的。运行的运行结果如下。
从运行结果,你可以发现,在任何一个窗口输入信息并发送,所有客户端将收到该消息。这样的效果在实际应用中很多,如QQ,一登录QQ的时候都会推送腾讯广告消息。
看完了运行结果,接下来我们来分析下代码,进而来剖析下SignalR到底是如何工作的。
按照B/S模式来看,运行程序的时候,Web页面就与SignalR的服务建立了连接,具体的建立连接的代码就是:$.connection.hub.start()。这句代码的作用就是与SignalR服务建立连接,后面的done函数表明建立连接成功后为发送按钮注册了一个click事件,当客户端输入内容点击发送按钮后,该Click事件将会触发,触发执行的操作为: chat.server.send($('#message').val())。这句代码表示调用服务端的send函数,而服务端的Send韩式又是调用所有客户端的sendMessage函数,而客户端中sendMessage函数就是将信息添加到对应的消息列表中。这样就实现了广播消息的功能了。
看到这里,有人是否会有疑问,前面的实现都只用到了集线器对象,而没有用到持久连接对象。其实并不是如此,$.connection这句代码就是使用持久连接对象,当然你也可以在重新OnConnected方法来查看监控客户端的连接情况,更新的代码如下所示:
public class ServerHub : Hub { private static readonly char[] Constant = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; /// <summary> /// 供客户端调用的服务器端代码 /// </summary> /// <param name="message"></param> public void Send(string message) { var name = GenerateRandomName(4); // 调用所有客户端的sendMessage方法 Clients.All.sendMessage(name, message); } /// <summary> /// 客户端连接的时候调用 /// </summary> /// <returns></returns> public override Task OnConnected() { Trace.WriteLine("客户端连接成功"); return base.OnConnected(); } /// <summary> /// 产生随机用户名函数 /// </summary> /// <param name="length">用户名长度</param> /// <returns></returns> public static string GenerateRandomName(int length) { var newRandom = new System.Text.StringBuilder(62); var rd = new Random(); for (var i = 0; i < length; i++) { newRandom.Append(Constant[rd.Next(62)]); } return newRandom.ToString(); } }
这样在运行页面的时候,将在输出窗口看到“客户端连接成功”字样。运行效果如下图所示:
在第二部分介绍的时候说道,在服务端声明的所有Hub信息,都会生成JavaScript输出到客户端,为了验证这一点,可以在Chrome中F12来查看源码就明白了,具体如下图所示:
看到上图,你也就明白了为什么Chat.cshtml页面需要引入"signalr/hubs"脚本库了吧。
五、在桌面程序中如何使用Asp.net SignalR
上面部分介绍了SignalR在Asp.net MVC 中的实现,这部分将通过一个例子来看看SignalR在WPF或WinForm是如何使用的。其实这部分实现和Asp.net MVC中非常相似,主要不同在于,Asp.net MVC中的SignalR服务器寄宿在IIS中,而在WPF中应用,我们把SignalR寄宿在WPF客户端中。
下面让我们看看SignalR服务端的实现。
/// <summary> /// 启动SignalR服务,将SignalR服务寄宿在WPF程序中 /// </summary> private void StartServer() { try { SignalR = WebApp.Start(ServerUri); // 启动SignalR服务 } catch (TargetInvocationException) { WriteToConsole("一个服务已经运行在:" + ServerUri); // Dispatcher回调来设置UI控件状态 this.Dispatcher.Invoke(() => ButtonStart.IsEnabled = true); return; } this.Dispatcher.Invoke(() => ButtonStop.IsEnabled = true); WriteToConsole("服务已经成功启动,地址为:" + ServerUri); } public class ChatHub : Hub { public void Send(string name, string message) { Clients.All.addMessage(name, message); } public override Task OnConnected() { // Application.Current.Dispatcher.Invoke(() => ((MainWindow)Application.Current.MainWindow).WriteToConsole("客户端连接,连接ID是: " + Context.ConnectionId)); return base.OnConnected(); } public override Task OnDisconnected(bool stopCalled) { Application.Current.Dispatcher.Invoke(() => ((MainWindow)Application.Current.MainWindow).WriteToConsole("客户端断开连接,连接ID是: " + Context.ConnectionId)); return base.OnDisconnected(true); } } public class Startup { public void Configuration(IAppBuilder app) { // 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888 // 允许CORS跨域 //app.UseCors(CorsOptions.AllowAll); app.MapSignalR(); } }
通过上面的代码,我们SignalR服务端的实现就完成了,其实现逻辑与Asp.net MVC的代码类似。
接下来,让我们看看,WPF客户端是如何连接和与服务器进行通信的。具体客户端的实现如下:
public IHubProxy HubProxy { get; set; } const string ServerUri = "http://localhost:8888/signalr"; public HubConnection Connection { get; set; } public MainWindow() { InitializeComponent(); // 窗口启动时开始连接服务 ConnectAsync(); } /// <summary> /// 发送消息 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ButtonSend_Click(object sender, RoutedEventArgs e) { // 通过代理来调用服务端的Send方法 // 服务端Send方法再调用客户端的AddMessage方法将消息输出到消息框中 HubProxy.Invoke("Send", GenerateRandomName(4), TextBoxMessage.Text.Trim()); TextBoxMessage.Text = String.Empty; TextBoxMessage.Focus(); } private async void ConnectAsync() { Connection = new HubConnection(ServerUri); Connection.Closed += Connection_Closed; // 创建一个集线器代理对象 HubProxy = Connection.CreateHubProxy("ChatHub"); // 供服务端调用,将消息输出到消息列表框中 HubProxy.On<string, string>("AddMessage", (name, message) => this.Dispatcher.Invoke(() => RichTextBoxConsole.AppendText(String.Format("{0}: {1}\r", name, message)) )); try { await Connection.Start(); } catch (HttpRequestException) { // 连接失败 return; } // 显示聊天控件 ChatPanel.Visibility = Visibility.Visible; ButtonSend.IsEnabled = true; TextBoxMessage.Focus(); RichTextBoxConsole.AppendText("连上服务:" + ServerUri + "\r"); }
上面的代码也就是WPF客户端实现的核心代码,主要逻辑为,客户端启动的时候就调用Connection.Start方法与服务器进行连接。然后通过HubProxy代理类来调用集线器中Send方法,而集线器中的Send方法又通过调用客户端的addMessage方法将消息输出到客户端的消息框中进行显示,从而完成消息的推送过程。
其效果和Asp.net MVC上的效果是一样的。
总结
到这里,本专题的所有内容就结束了,这篇SignalR快速入门也是本人在学习SignalR过程中的一些心得体会,希望可以帮助一些刚接触SignalR的朋友快速入门。本篇主要实现了SignalR的广播消息的功能,可以实现手机端消息推送的功能,接下来一篇将介绍如何使用SignalR实现一对一的聊天。
Weitere Artikel zur Verwendung von SignalR zur Implementierung der Push-Funktion in Asp.NET MVC finden Sie auf der chinesischen PHP-Website!