Asp.net signalr application and implementation of group chat function

Time:2021-11-25

Asp.net signalr is a library for asp.net developers, which can simplify the process of developers adding real-time web functions to applications. The real-time web function refers to the function that when the connected client becomes available, the server code can immediately push content to it, rather than making the server wait for the client to request new data. (from the official introduction.)

Signalr official website

 – 1. The reason for writing this article

In the last articleB / S (WEB) real time communication solutionIn, there is no detailed introduction to signalr, so another article specifically introduces signalr. This article focuses on the hub function.  

0. See the final effect first

github:https://github.com/Emrys5/SignalRGroupChatDemo

Online presentation:http://chat.lining.name/

  1. Preparatory work

1.1. First download the package of signalr on nuget.

1.2. Configure owin and signalr

1.2.1. Create a startup class and register signalr


public class Startup
 {
 public void Configuration(IAppBuilder app)
 {
  app.MapSignalR();
 }
 }

Then configure the startup class in web.config and add it in the configuration = > Appsettings node

<add key=”owin:AppStartup” value=”SignalRChat.App_Start.Startup”/>

1.2.2. Import the JS of signalr on the page

1. Since the signalr front end is based on jQuery, jQuery needs to be introduced into the page.

2. Introduce JS of signalr.

3. Introduce the most important hub JS, which does not actually exist. Signalr will reflect and get all methods called by the client into the hub 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 create a new groupchathub class and inherit the hub abstract class

The method in the hub class is the JS method provided to the client to call.

In JS, you can call sendmsg with signalr.


[HubName("simpleHub")]
 public class SimpleHub : Hub
 { 
 public void SendMsg(string msg)
 {
  
 }

 }

In this way, the preliminary preparations are basically completed, followed by specific operations.

2. Principle and simple programming

In fact, it’s easy to understand the principle simply. Because HTTP is stateless, it will disconnect from the server after each request, which means that the client can easily find the server, but if the server wants to send messages to your client, it’s more troublesome. If you don’t understand, you can refer to the previous articleB / S (WEB) real time communication solution

Signalr solves this problem well, that is to say, it realizes the full duplex communication between the browser and the server.

2.1. Client to server (b = > s)

Client code

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

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

 //After the link is completed, you can send a message to the server
 Ticker.server.sendmsg ("message to be sent");
 });
 
</script>

Server code

[HubName("simpleHub")]
 public class SimpleHub : Hub
 {
 public void SendMsg(string msg)
 {
  //Get link ID
  var connectionId = Context.ConnectionId; 
  //Get cookie
  var cookie = Context.RequestCookies;

 }

 }

Simplehub is the inherited hub class simplehub defined by us, and then we can rename it with the attribute hubname.

Then start the link.

After the link is completed, we can call the method invoked in the SimpleHub class. This is a very simple implementation of sending messages from the client to the server.

We can also get what we want in context, such as link ID, cookie, etc.

2.2. Server to client (s = > b)

Server code

[HubName("simpleHub")]
 public class SimpleHub : Hub
 {
 public void SendMsg(string msg)
 {
  Clients.all.msg ("messages sent to clients"); 
 }

 }

Client code


<script type="text/javascript">

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

 ticker.client.msg = function (data) {
 console.log(data);
 } 
</script>

Here is a demonstration of how to send messages to the client, which is also an important function of signalr. Here are two problems to be solved.

Question 1. Here is how to send a message to all connected clients. If it is a single client or a group of clients, how should it be sent.

Problem 2: when we call msg to send a message to a client, we give feedback after receiving the message, and then send the message to the client. This is very similar to Ajax. The server does not take the initiative to send a message to the client.

solve:

Problem 1: clients can send messages to a group of features or a client

//Everyone
Clients.all.msg ("messages sent to clients"); 
//Specific cooectionid
Clients. Client ("connectionid"). MSG ("message sent to client");
//Specific group
Clients. Group ("groupname"). MSG ("messages sent to clients");

These are the three commonly used. Of course, there are many, such as allexcept and clients.

Other, othersingroup, othersingroups, etc. are also added in signalr2.0.

Question 2. We can call globalhost.connectionmanager.gethubcontext < simplehub > (). Clients to get clients where we need to send messages. To get clients and send messages, we’d better write in singleton mode, because this requirement is very consistent with singleton. There are detailed codes in group chat.

3. Signalr implements group chat

The above introduction and code can realize B = > s and S = > B. It is easier to realize group chat and individual chat.

Because the function is relatively simple, I save my user name into a cookie, that is, I need to set a cookie when I come in for the first time.

Another is to implement onconnected, ondisconnected and onreconnected in the hub, and then set the user and connectionid and count online users in the method for chat.

Hub code

/// <summary>
 ///Signalr hub group chat class
 /// </summary>
 [hubname ("groupchathub")] // tag name for JS call
 public class GroupChatHub : Hub
 {
 /// <summary>
 ///User name
 /// </summary>
 private string UserName
 {
  get
  {
  var userName = Context.RequestCookies["USERNAME"];
  return userName == null ? "" : HttpUtility.UrlDecode(userName.Value);
  }
 }

 /// <summary>
 ///Online users
 /// </summary>
 private static Dictionary<string, int> _onlineUser = new Dictionary<string, int>();

 /// <summary>
 ///Start connection
 /// </summary>
 /// <returns></returns>
 public override Task OnConnected()
 {
  Connected();
  return base.OnConnected();
 }


 /// <summary>
 ///Relink
 /// </summary>
 /// <returns></returns>
 public override Task OnReconnected()
 {
  Connected();
  return base.OnReconnected();
 }


 private void Connected()
 {
  //Handling online personnel
  If (! _onlineuser. Containskey (username)) // if the name does not exist, it is a new user
  {

  //Join online people
  _onlineUser.Add(UserName, 1);

  //Send online people to clients
  Clients.All.publshUser(_onlineUser.Select(i => i.Key));

  //Send join chat message to client
  Clients.all.publshmsg (formatmsg ("system message", username + "join chat");
  }
  else
  {
  //If it is an existing user, the number of online links will be increased by 1
  _onlineUser[UserName] = _onlineUser[UserName] + 1;
  }

  //Join the hub group in order to send a separate message
  Groups.Add(Context.ConnectionId, "GROUP-" + UserName);
 }


 /// <summary>
 ///End connection
 /// </summary>
 /// <param name="stopCalled"></param>
 /// <returns></returns>
 public override Task OnDisconnected(bool stopCalled)
 {
  //Number of people links - 1
  _onlineUser[UserName] = _onlineUser[UserName] - 1;

  //Determine whether all links have been disconnected
  if (_onlineUser[UserName] == 0)
  {
  //Remove online personnel
  _onlineUser.Remove(UserName);

  //Send online people to clients
  Clients.All.publshUser(_onlineUser.Select(i => i.Key));

  //Send an exit chat message to the client
  Clients.all.publshmsg (formatmsg ("system message", username + "exit chat");
  }

  //Remove hub group
  Groups.Remove(Context.ConnectionId, "GROUP-" + UserName);
  return base.OnDisconnected(stopCalled);
 }

 /// <summary>
 ///Send a message for the client to call
 /// </summary>
 ///< param name = "user" > user name. If it is 0, it will be sent to everyone < / param >
 ///< param name = "MSG" > message < / param >
 public void SendMsg(string user, string msg)
 {
  if (user == "0")
  {
  //Messages sent to all users
  Clients.All.publshMsg(FormatMsg(UserName, msg));
  }
  else
  {
  ////Send a message to yourself
  //Clients.Group("GROUP-" + UserName).publshMsg(FormatMsg(UserName, msg));

  ////Send to selected person
  //Clients.Group("GROUP-" + user).publshMsg(FormatMsg(UserName, msg));


  //Send a message to yourself
  Clients.Groups(new List<string> { "GROUP-" + UserName, "GROUP-" + user }).publshMsg(FormatMsg(UserName, msg));

  }
 }


 /// <summary>
 ///Format sent messages
 /// </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 code

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

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

  //Receive messages sent by the server
  $.extend(ticker.client, {

  //Receive chat messages
  publshMsg: function (data) {
   $("#msg").append("<li><span class='p'>" + data.Name + ":</span>" + data.Msg + " <span class='time'>" + data.Time + "</span></li>")
   $("#msg").parents("div")[0].scrollTop = $("#msg").parents("div")[0].scrollHeight;
  },

  //Receive online people and join select for individual chat
  publshUser: function (data) {
   $("#count").text(data.length);
   $("#users").empty();
   $("#users"). Append ('< option value = "0" > owner < / option >');
   for (var i = 0; i < data.length; i++) {
   $("#users").append('<option value="' + data[i] + '">' + data[i] + '</option>')
   }

  }
  });

  //Send Message button
  $("#btn-send").click(function () {
  var msg = $("#txt-msg").val();
  if (!msg) {
   Alert ('Please input content! '); return false;
  }
  $("#txt-msg").val('');

  //Actively send messages, incoming messages, who they are sent to, and what they are sent.
  ticker.server.sendMsg($("#users").val(), msg);
  });

 });
 </script>

HTML code

<h2>
 Group chat system (< span > 1 < / span > people online): @ viewbag.username
</h2>


<div style="overflow:auto;height:300px">
 <ul></ul>
</div>

<select style="max-width:150px;">
 < option value = "0" > everyone < / option >
</select>

< input type = "text" onkeydown ='If (event. Keycode = = 13) {$("#btn-send"). Click()} 'placeholder = "content" style = "max width: 400px;" / >
<br />
< button type = "button" > send < / button >

In this way, group chat and chat sent to specific people are enabled.

3.1. Encapsulate a single example of actively sending messages

/// <summary>
 ///Actively send messages to users, single instance mode
 /// </summary>
 public class GroupChat
 {
 /// <summary>
 ///Clients, which is used to actively send messages
 /// </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>
 ///Actively send messages to everyone, and the system calls directly
 /// </summary>
 /// <param name="msg"></param>
 public void SendSystemMsg(string msg)
 {
  Clients. All. Publshmsg (New {name = "system message", MSG = MSG, time = datetime. Now. ToString ("yyyy MM DD HH: mm: SS")});
 }
 }

If you need to send a message, you can directly call sendsystemmsg.

Groupchat.instance.sendsystemmsg (“message”);

  4. Conclusion

Don’t say anything, direct source code

github:https://github.com/Emrys5/SignalRGroupChatDemo

Online presentation:http://chat.lining.name/

Finally, I hope it will help you. This article is original. Welcome to make bricks and recommend.

The above is the whole content of this article. I hope it will be helpful to your study, and I hope you can support developpaer.