この記事では主にリアルタイム Web チャット用の Asp.net SignalR のサンプル コードを紹介します。興味のある方は参考にしてください。
この章で共有する内容は、Signal R フレームワークを使用して行うことです。グループチャット機能は主に.NetのMVCでのこのフレームワークの使い方を説明するもので、このプロジェクトは公式ドキュメント(もちろんすべて英語)があるため、後で共有することを主な目的としています。必要なときにリアルタイムで Web を使用できるようにするためのソリューションは他にもありますが、これは Microsoft が推進するソリューションの 1 つです。
SignalR オンライン紹介
ASP.NET SignalR は、リアルタイム Web 機能をアプリケーションに追加するプロセスを簡素化する、ASP.NET 開発者向けのライブラリです。リアルタイム Web 機能は、クライアントが新しいデータを要求するまでサーバーに待機させるのではなく、サーバー コードが接続されたクライアントが利用可能になるとすぐにコンテンツをプッシュできる機能です。もちろん、SignalR は非常にシンプルで使いやすい高レベル API も提供します。これにより、サーバーはクライアント上で JavaScript 関数を個別またはバッチで呼び出すことができ、次のような接続管理を実行するのに非常に便利です。クライアントのサーバーへの接続または切断 接続、クライアントのグループ化、およびクライアントの承認はすべて、SignalR を使用して非常に簡単に実装できます。
SignalR は、クライアントとのリアルタイム通信を ASP .NET にもたらします。もちろん使いやすく、拡張性も十分です。以前は、ユーザーはデータのリアルタイム表示を実現するためにページを更新するか、Ajax ポーリングを使用する必要がありました。現在では、SignalR を使用するだけで済みます。最も重要なことは、プロジェクトを再作成する必要がなく、既存の ASP .NET プロジェクトを使用して SignalR をシームレスに使用できることです。
グループ チャット インスタンスの効果最初にテスト ケースの効果、レンダリングを見てみましょう:
インターフェイスは非常にシンプルで、ここではスタイルは考慮されません。主に表示するためです。ここで使用する機能は次のとおりです:
1. オンラインの人数をカウントします
2. オンラインの人のニックネームと接続方法を表示します (このテスト ケースは webSocket と longPolling (長時間接続) をサポートします)
3.グループ チャット情報
MVC で SignalR を使用する方法まず、通常は MVC Web プロジェクトを作成し、次に Nuget コンソール コマンド: Inst
all-package Microsoft.AspNet.SignalR を使用して SignalR の依存関係を追加します。自動的に追加されるパッケージは次のとおりです: <package id="Microsoft.AspNet.SignalR" version="2.2.2" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Core" version="2.2.2" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.JS" version="2.2.2" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="2.2.2" targetFramework="net45" />
そして、関連する js ファイルを MVC プロジェクトの Script フォルダーに自動的に追加します:
.signalR-2.2.2.min.js
jquery.signalR-2.2 .2.js
次に、プロジェクトの第 1 レベルのディレクトリに Startup.cs というファイル名でクラスを作成する必要がありますが、そのメインコンテンツは完成できません:
[assembly: OwinStartup(typeof(Stage.Api.Extend.Startup))] namespace Stage.Api.Extend { public class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR("/chat", new Microsoft.AspNet.SignalR.HubConfiguration { EnableDetailedErrors = true, EnableJavaScriptProxies = true }); } } }
まず、注意すべき点を分析します。上から下:
1. OwinStartup(Type)
コンストラクター
namespace Stage.Api.Extend
は、私のプロジェクトの 名前空間 、これは自由に定義できます; OwinStartup(Type)
构造函数传递的是一个类型,而这个类型对应的就是我们创建的Startup类,这个通过这个构造函数类标记起始位置;
2. namespace Stage.Api.Extend
是我项目的命名空间,这个可以随便定义;
3. public void Configuration(IAppBuilder app)
函数是固定必须的,这里程序会首先进入这个方法执行里面的逻辑代码;
4. app.MapSignalR
是扩展的IAppBuilder接口方法,他有多种表现形式,这里我选择的是 public <a href="http://www.php.cn/wiki/188.html" target="_blank">static</a> IAppBuilder MapSignalR(this IAppBuilder builder, <a href="http://www.php.cn/wiki/57.html" target="_blank">string</a> path, HubConfiguration configuration);
3. public void Configuration(IAppBuilder app)
関数は修正されており、必要です。ここでのプログラムは最初にこれを入力します。このメソッドは内部のロジック コードを実行します
app.MapSignalR
は拡張された IAppBuilderInterface メソッドには、さまざまな表現形式があります。ここでは public <a href="http://www.php.cn/" wiki target="_blank">静的 </a><a href="http://www.php.cn/code/6064.html" target="_blank"> IAppBuilder MapSignalR(この IAppBuilder ビルダー、</a><a href="http://www.php.cn/wiki/57.html" target="_blank">文字列</a>) path、HubConfiguration 構成);
、こちらを参照してください。これは、MVC の
public class ChatHub : Hub { // public int Num = 10001; public static List<MoHubUser> _Users = new List<MoHubUser>(); /// <summary> /// 添加聊天人 /// </summary> /// <param name="user"></param> public void AddUser(MoHubUser user) { user.Id = Context.ConnectionId; if (!_Users.Any(b => b.Id == user.Id)) { _Users.Add(user); } //Clients.All.newUser(user); Clients.All.userList(_Users); } /// <summary> /// 发送信息 /// </summary> /// <param name="user"></param> /// <param name="message"></param> public void SendAll(MoHubUser user, string message) { Clients.All.addNewMessageToPage(user, message); } /// <summary> /// 某个聊天人退出是,通知所有在线人重新加载聊天人数 /// </summary> /// <param name="stopCalled"></param> /// <returns></returns> public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled) { var user = _Users.SingleOrDefault(x => x.Id == Context.ConnectionId); if (user != null) { _Users.Remove(user); Clients.All.userList(_Users); } return base.OnDisconnected(stopCalled); } }
上面的3个方法分别做了:添加聊天人到List,发送信息到客户端,某个连接失效后通知各个有效的聊天人重新加载信息;这里值得关注的是通过重新 public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
方法来实现捕获并移除失效连接(这里是聊天人的信息);整篇测试用例通过Context.ConnectionId来保证连接的唯一性,只要有新的链接请求,那么服务端就会分配一个唯一串给这个链接,当客户端关闭页面或关闭链接这个是有就能在OnDisconnected方法中捕获到这个失效的链接的ConnectionId,这样就达到了移除失效聊天人的要求了;为了代码的方便性,这里创建了一个聊天人信息类:
public class MoHubUser { public string Id { get; set; } public string NickName { get; set; } public string TransportMethod { get; set; } }
到这里后台的聊天室代码就完成了就是这么简单;我们再来看试图中如何来写代码,这里我先给出我的html布局代码:
@{ ViewBag.Title = "神牛聊天室 - SignalR"; } <style type="text/css"> .p_left { width: 70%; float: left; } .p_right { width: 28%; float: left; } .ul { list-style: none; border: 1px solid #ccc; height: 500px; overflow-y: scroll; color: black; } .ul li { padding-top: 5px; padding-right: 25px; } .ul_user { list-style: none; } .ul_user li { padding-top: 5px; } .send { position: relative; background: #eae7e7; border-radius: 5px; /* 圆角 */ padding-top: 4px; padding-left: 5px; margin-top: 13px; } .send .arrow { position: absolute; top: -16px; font-size: 0; border: solid 8px; border-color: #fff #fff #eae7e7 #fff; } </style> <h3>@ViewBag.Title 在线人数:<span id="sapnUserTotal">0</span>人</h3> <p class="container text-left"> <p class="p_left"> <ul class="ul" id="discussion"></ul> <textarea rows="5" class="form-control" id="message" maxlength="500" placeholder="开始聊天. . ." style="max-width: 100%"></textarea><br /> <input type="button" id="sendmessage" value="发 送" class="btn btn-default" /> <input type="hidden" id="displayname" /> </p> <p class="p_right"> <ul id="users" class="ul_user"></ul> </p> </p> <script src="~/Scripts/jquery.signalR-2.2.2.min.js"></script> @*<script src="~/chat/hubs"></script>*@
客户端这里写法大致有两种选择,一种直接使用生成的代理来操作,一种不用自动生成的代理采用手动创建代理的方式;为了内容的简洁性,这里只简单讲解下自动生成的代理方式,而更多的是分享手动创建代理链接的方式;
使用生成的代理获取链接
首先,我们需要通过Script标签来引用一下自动生成代理的路径: 6b7e0e3e57921579395ce622aff978262cacc6d41bbb37262a98f745aa00fbf0
,注意啦这里的路径/chat对应的就是咋们在前面Startup.cs文件中配置 app.MapSignalR("/chat"
路径,而后面/hubs固定的写法(至少目前我还没更多的试验过),只有先应用了这个~/chat/hubs,才能在后面使用生成的代理,先上段代码:
var chat = $.connection.chatHub; chat.client.newUser = function (user) { $("#users").append(' <li><strong>' + user.NickName + '[' + user.TransportMethod + ']</strong></li>'); }; chat.client.userList = function (users) { console.log(users); $("#sapnUserTotal").html(users.length); $.each(users, function (i, item) { $("#users").append(' <li>[' + item.TransportMethod + '] <strong>' + item.NickName + '</strong>(' + item.Id + ')</li>'); }); }; chat.client.addNewMessageToPage = function (user, message) { console.log(user); $("#discussion").append(' <li ><span><strong>' + user.NickName + '[' + user.TransportMethod + ']</strong>:</span><p class="send">' + message + '<p class="arrow"></p></p></li>'); }; //connection.hub.start({ transport: ['webSockets', 'longPolling'] }).done(function () { // my.TransportMethod = connection.hub.transport.name; // chat.server.addUser(my); // $('#sendmessage').click(function () { // //console.log(chat); // var content = $.trim($('#message').val()); // if (content.length <= 0) { $('#message').val('').focus(); return; } // chat.server.sendAll(my, content); // $('#message').val('').focus(); // }); //}).fail(function () { // alert("链接聊天室失败,请重新刷新页面。"); //});
咋们逐步来解析下代码注意点:
1. var chat = $.connection.chatHub;
这里的chatHub对应的就是咋们创建的并继承Hub的ChatHub类,由于js变量开头都是小写,所以这里是chatHub,这句活就表示链接到咋们后端了ChatHub类了,然后就可以使用里面的方法啦(这种有点类似于早期的webform中某种ajax请求的写法)
2. 通过chat.client.xxx来接收服务端通知的消息,而这个xxx对应的方法名称和咋们后端的Clients.All.xxx,本章实例对应的是:chat.client.userList = function (users){}对应Clients.All.userList(_Users);这样后端就能直接通知客户端的对应方法了;注意这里我后端Clients.All用的是通知全部客户端的意思,如果您需要通知指定的链接需要用到的是: T Client(string connectionId);
方法
3. chat.client是后端调用客户端,那相对的chat.server就是客户端请求服务端,和上面一样通过chat.server.xxx来指定请求的服务端方法,注意这个时候服务端方法指的是继承类Hub的子类的公共方法(本篇对应的是:chat.server.sendAll(my, content)对应ChatHub.cs文件中的 public void SendAll(MoHubUser user, string message)
函数)
4. connection.hub.start({ transport: ['webSockets', 'longPolling'] })
来指定运行的交互协议
以上就是使用生成代理的方式,按照上面的注意点来写应该不是问题;
使用手动创建反向代理来链接
不采用生成的代码的方式,我们只需要修改前端就行了,后台代码不用变或设置不用变动;首先我们把上面说的Script引用自动代理的代码去掉,因为这个时候不需要了,我们还是先上代码:
var my = { NickName: "神牛001", TransportMethod: "" }; var connection = $.hubConnection("/chat/hubs"); var chat = connection.createHubProxy('chatHub'); chat.on("userList", function (users) { console.log(users); $("#sapnUserTotal").html(users.length); $("#users").html(""); $.each(users, function (i, item) { $("#users").append(' <li>[' + item.TransportMethod + '] <strong>' + item.NickName + '</strong>(' + item.Id + ')</li>'); }); }); chat.on("addNewMessageToPage", function (user, message) { console.log(user); $("#discussion").append(' <li ><span><strong>' + user.NickName + '[' + user.TransportMethod + ']</strong>:</span><p class="send">' + message + '<p class="arrow"></p></p></li>'); var p = document.getElementById('discussion'); //p.scrollTop = p.scrollHeight; p.scrollTop = 999999; }); var nickName = prompt("请输入一个昵称:", my.NickName); my.NickName = nickName.length > 0 ? nickName : my.NickName; $('#displayname').val(nickName); $('#message').focus(); connection.start({ transport: ['webSockets', 'longPolling'] }).done(function () { my.TransportMethod = connection.transport.name; //console.log(my.TransportMethod); chat.invoke("addUser", my); $('#sendmessage').click(function () { var content = $.trim($('#message').val()); if (content.length <= 0) { $('#message').val('').focus(); return; } chat.invoke("sendAll", my, content); $('#message').val('').focus(); }); });
同样列出如下注意点:
1. var connection = $.hubConnection("/chat/hubs");
创建链接,这里的path同样对应后端的 app.MapSignalR("/chat" ,路径保持一致
2. var chat = connection.createHubProxy('chatHub');
来创建反向代理链接,这里的name:chatHub对应的是后端的ChatHub类名称
3. 通过on("xxx",function(){})函数来绑定服务端通知客户端的事件,xxx对应Clients.All.xxx中的xxx
4. connection.start({ transport: ['webSockets', 'longPolling'] })
来设置允许的链接方式,并开始链接
5. connection.transport.name来获取链接的方式名称,默认start不设置的话有这么几种:webSockets,foreverFrame,serverSentEvents,longPolling
6. chat.invoke("xxx", param1, param2) は、invoke を使用して、Hub クラスを継承するクラスのパブリック メソッドをマップします。 chat.invoke("sendAll", my, content)
对应 public void SendAll(MoHubUser user, string message)
以上がSignalR を使用してリアルタイム Web チャットを実装するためのコード例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。