ホームページ > バックエンド開発 > C#.Net チュートリアル > Asp.net SignalRの応用とグループチャット機能の実装について詳しく解説

Asp.net SignalRの応用とグループチャット機能の実装について詳しく解説

Y2J
リリース: 2017-04-27 15:58:45
オリジナル
1985 人が閲覧しました

この記事は主に Asp.net SignalR アプリケーションを共有し、グループ チャット機能を実装しています。興味のある友人は参照してください。

ASP.NET SignalR のプロセスを簡素化するライブラリです。開発者はリアルタイム Web 機能をアプリケーションに追加できます。リアルタイム Web 機能は、クライアントが新しいデータを要求するまでサーバーに待機させるのではなく、サーバー コードが接続されたクライアントが利用可能になるとすぐにコンテンツをプッシュできる機能です。 (公式紹介文より)

SignalR 公式サイト

-1. この記事を書いた理由

前回の記事 B/S (Web) リアルタイム通信ソリューションでは、SignalR の詳しい紹介がなかったので、新しい記事を開始しました。特に SignalR について紹介します。この記事ではハブ機能に焦点を当てます。

0. まずは最終的な実装を見てみましょう

github.com/Emrys5/SignalRGroupChatDemo

1. 準備作業

1.1をダウンロードします。 NuGet の alR パッケージ。

1.2. Owin と SignalR を構成する

1.2.1. 新しい Startup クラスを作成し、SignalR を登録します

public class Startup
 {
 public void Configuration(IAppBuilder app)
 {
  app.MapSignalR();
 }
 }
ログイン後にコピー

次に、web.config で Startup クラスを構成し、configuration= に追加します。 >appSettings ノード

1.2.2. SignalR フロントから SignalR js を導入します。 -end は jQuery をベースにしているため、ページには jQuery を導入する必要があります。

2. SignalR の js を紹介します。

3. 最も重要なハブ js を導入します。この js は、クライアントが呼び出してハブ js に配置するすべてのメソッドを反映します。

<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script> 
<script src="~/signalr/hubs"></script>
ログイン後にコピー

1.2.3. 新しい GroupChatHub クラスを作成し、Hub 抽象クラスを継承します

Hub クラスのメソッドは、呼び出し用にクライアントに提供される js メソッドです。

signalr を使用して js で SendMsg を呼び出すことができます。

[HubName("simpleHub")]
 public class SimpleHub : Hub
 { 
 public void SendMsg(string msg)
 {
 }
 }
ログイン後にコピー

このようにして、事前準備作業は基本的に完了し、続いて具体的な操作を行っていきます。

2. 原理と簡単なプログラミング


実際、原理を理解するのは非常に簡単です。http はステートレスであるため、クライアントはリクエストのたびにサーバーから切断されます。簡単にサーバーを見つけるのは簡単ですが、サーバーがクライアントにメッセージを送信する場合はさらに面倒です。理解できない場合は、前の記事「B/S (Web) リアルタイム通信ソリューション」を参照してください。

SignalR はこの問題をうまく解決し、ブラウザとサーバー間の全二重通信を実現します。

2.1、クライアントからサーバー (B=>S)

クライアントコード

<script type="text/javascript"> 
 var ticker = $.connection.simpleHub;
 $.connection.hub.start();

 $("#btn").click(function () {

 // 链接完成以后,可以发送消息至服务端
 ticker.server.sendMsg("需要发送的消息");
 });
 
</script>
ログイン後にコピー

サーバーコード

[HubName("simpleHub")]
 public class SimpleHub : Hub
 {
 public void SendMsg(string msg)
 {
  // 获取链接id
  var connectionId = Context.ConnectionId; 
  // 获取cookie
  var cookie = Context.RequestCookies;

 }

 }
ログイン後にコピー

SimpleHub は定義した継承されたハブクラス SimpleHub であり、HubName の名前が変更された特性を使用できます。

それからリンクを開始します。

リンクが完了したら、SimpleHubクラスで呼び出されるメソッドを呼び出すことができます。これにより、クライアントからサーバーへのメッセージの送信が非常に簡単になります。

リンク ID、Cookie など、Context で必要なものを取得することもできます。

2.2、サーバーからクライアント (S=>B)

サーバーコード

[HubName("simpleHub")]
 public class SimpleHub : Hub
 {
 public void SendMsg(string msg)
 {
  Clients.All.msg("发送给客户端的消息"); 
 }
 }
ログイン後にコピー

クライアントコード

<script type="text/javascript">

 var ticker = $.connection.groupChatHub;
 $.connection.hub.start();

 ticker.client.msg = function (data) {
 console.log(data);
 } 
</script>
ログイン後にコピー

ここでは、クライアントにメッセージを送信する方法のデモを示します。 SignalR の比較 重要な機能ですが、ここでは解決する必要がある問題が 2 つあります。

質問 1. 接続されているすべてのクライアントにメッセージを送信する方法は、単一のクライアントまたはクライアントのグループの場合、どのように送信されるべきですか?

質問 2: メッセージをクライアントに送信するために msg を呼び出すとき、メッセージを受信した後にフィードバックを返し、メッセージをクライアントに送信します。これは、サーバーが積極的にメッセージを送信するわけではありません。クライアント。

解決策:

問題 1. クライアントは機能のグループまたはクライアントにメッセージを送信できます

// 所有人
Clients.All.msg("发送给客户端的消息"); 
// 特定 cooectionId
Clients.Client("connectionId").msg("发送给客户端的消息");
// 特定 group
Clients.Group("groupName").msg("发送给客户端的消息");
ログイン後にコピー

これらは最も一般的に使用される 3 つですが、もちろん、AllExcept や Clients など、他にもたくさんあります。

Others、OthersInGroup、OthersInGroups なども SignalR2.0 で追加されました。

質問 2. メッセージを送信する必要がある GlobalHost.ConnectionManager.GetHubContext().Clients を呼び出すことでクライアントを取得できます。クライアントを取得してメッセージを送信するには、シングルトン モードで作成することをお勧めします。この要件はシングルトンと非常に一致しており、グループ チャットには詳細なコードがあるためです。

3. SignalR はグループ チャットを実装します

上記の紹介とコードはすでに b=>s と s=>b を実装できるため、グループ チャットと個人チャットを実装するのは比較的簡単です。

由于功能比较简单,所有我把用户名存到了cookie里,也就说第一次进来时需要设置cookie。

还有就是在hub中要实现OnConnected、OnDisconnected和OnReconnected,然后在方法中设置用户和connectionid和统计在线用户,以便聊天使用。

hub代码

/// <summary>
 /// SignalR Hub 群聊类
 /// </summary>
 [HubName("groupChatHub")] // 标记名称供js调用
 public class GroupChatHub : Hub
 {
 /// <summary>
 /// 用户名
 /// </summary>
 private string UserName
 {
  get
  {
  var userName = Context.RequestCookies["USERNAME"];
  return userName == null ? "" : HttpUtility.UrlDecode(userName.Value);
  }
 }

 /// <summary>
 /// 在线用户
 /// </summary>
 private static Dictionary<string, int> _onlineUser = new Dictionary<string, int>();

 /// <summary>
 /// 开始连接
 /// </summary>
 /// <returns></returns>
 public override Task OnConnected()
 {
  Connected();
  return base.OnConnected();
 }


 /// <summary>
 /// 重新链接
 /// </summary>
 /// <returns></returns>
 public override Task OnReconnected()
 {
  Connected();
  return base.OnReconnected();
 }


 private void Connected()
 {
  // 处理在线人员
  if (!_onlineUser.ContainsKey(UserName)) // 如果名称不存在,则是新用户
  {

  // 加入在线人员
  _onlineUser.Add(UserName, 1);

  // 向客户端发送在线人员
  Clients.All.publshUser(_onlineUser.Select(i => i.Key));

  // 向客户端发送加入聊天消息
  Clients.All.publshMsg(FormatMsg("系统消息", UserName + "加入聊天"));
  }
  else
  {
  // 如果是已经存在的用户,则把在线链接的个数+1
  _onlineUser[UserName] = _onlineUser[UserName] + 1;
  }

  // 加入Hub Group,为了发送单独消息
  Groups.Add(Context.ConnectionId, "GROUP-" + UserName);
 }


 /// <summary>
 /// 结束连接
 /// </summary>
 /// <param name="stopCalled"></param>
 /// <returns></returns>
 public override Task OnDisconnected(bool stopCalled)
 {
  // 人员链接数-1
  _onlineUser[UserName] = _onlineUser[UserName] - 1;

  // 判断是否断开了所有的链接
  if (_onlineUser[UserName] == 0)
  {
  // 移除在线人员
  _onlineUser.Remove(UserName);

  // 向客户端发送在线人员
  Clients.All.publshUser(_onlineUser.Select(i => i.Key));

  // 向客户端发送退出聊天消息
  Clients.All.publshMsg(FormatMsg("系统消息", UserName + "退出聊天"));
  }

  // 移除Hub Group
  Groups.Remove(Context.ConnectionId, "GROUP-" + UserName);
  return base.OnDisconnected(stopCalled);
 }

 /// <summary>
 /// 发送消息,供客户端调用
 /// </summary>
 /// <param name="user">用户名,如果为0,则是发送给所有人</param>
 /// <param name="msg">消息</param>
 public void SendMsg(string user, string msg)
 {
  if (user == "0")
  {
  // 发送给所有用户消息
  Clients.All.publshMsg(FormatMsg(UserName, msg));
  }
  else
  {
  //// 发送给自己消息
  //Clients.Group("GROUP-" + UserName).publshMsg(FormatMsg(UserName, msg));

  //// 发送给选择的人员
  //Clients.Group("GROUP-" + user).publshMsg(FormatMsg(UserName, msg));


  // 发送给自己消息
  Clients.Groups(new List<string> { "GROUP-" + UserName, "GROUP-" + user }).publshMsg(FormatMsg(UserName, msg));

  }
 }


 /// <summary>
 /// 格式化发送的消息
 /// </summary>
 /// <param name="name"></param>
 /// <param name="msg"></param>
 /// <returns></returns>
 private dynamic FormatMsg(string name, string msg)
 {
  return new { Name = name, Msg = HttpUtility.HtmlEncode(msg), Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") };
 }
 }
ログイン後にコピー

js代码

<script type="text/javascript">
 $(function () {

  // 链接hub
  var ticker = $.connection.groupChatHub;
  $.connection.hub.start();

  // 接收服务端发送的消息
  $.extend(ticker.client, {

  // 接收聊天消息
  publshMsg: function (data) {
   $("#msg").append("<li><span class=&#39;p&#39;>" + data.Name + ":</span>" + data.Msg + " <span class=&#39;time&#39;>" + data.Time + "</span></li>")
   $("#msg").parents("p")[0].scrollTop = $("#msg").parents("p")[0].scrollHeight;
  },

  // 接收在线人员,然后加入Select,以供单独聊天选中
  publshUser: function (data) {
   $("#count").text(data.length);
   $("#users").empty();
   $("#users").append(&#39;<option value="0">所有人</option>&#39;);
   for (var i = 0; i < data.length; i++) {
   $("#users").append(&#39;<option value="&#39; + data[i] + &#39;">&#39; + data[i] + &#39;</option>&#39;)
   }

  }
  });

  // 发送消息按钮
  $("#btn-send").click(function () {
  var msg = $("#txt-msg").val();
  if (!msg) {
   alert(&#39;请输入内容!&#39;); return false;
  }
  $("#txt-msg").val(&#39;&#39;);

  // 主动发送消息,传入发送给谁,和发送的内容。
  ticker.server.sendMsg($("#users").val(), msg);
  });

 });
 </script>
ログイン後にコピー

html代码

<h2>
 群聊系统(<span id="count">1</span>人在线):@ViewBag.UserName
</h2>


<p style="overflow:auto;height:300px">
 <ul id="msg"></ul>
</p>

<select id="users" class="form-control" style="max-width:150px;">
 <option value="0">所有人</option>
</select>

<input type="text" onkeydown=&#39;if (event.keyCode == 13) { $("#btn-send").click() }&#39; class="form-control" id="txt-msg" placeholder="内容" style="max-width:400px;" />
<br />
<button type="button" id="btn-send">发送</button>
ログイン後にコピー

这样就消息了群聊和发送给特定的人聊天功能。

3.1、封装主动发送消息的单例

/// <summary>
 /// 主动发送给用户消息,单例模式
 /// </summary>
 public class GroupChat
 {
 /// <summary>
 /// Clients,用来主动发送消息
 /// </summary>
 private IHubConnectionContext<dynamic> Clients { get; set; }

 private readonly static GroupChat _instance = new GroupChat(GlobalHost.ConnectionManager.GetHubContext<GroupChatHub>().Clients);

 private GroupChat(IHubConnectionContext<dynamic> clients)
 {
  Clients = clients;
 }

 public static GroupChat Instance
 {
  get
  {
  return _instance;
  }
 }


 /// <summary>
 /// 主动给所有人发送消息,系统直接调用
 /// </summary>
 /// <param name="msg"></param>
 public void SendSystemMsg(string msg)
 {
  Clients.All.publshMsg(new { Name = "系统消息", Msg = msg, Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") });
 }
 }
ログイン後にコピー

如果需要发送消息,直接调用SendSystemMsg即可。

GroupChat.Instance.SendSystemMsg("消息");

 4、结语

啥也不说了直接源码

github.com/Emrys5/SignalRGroupChatDemo

以上がAsp.net SignalRの応用とグループチャット機能の実装について詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート