加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

Asp.net SignalR 应用并实现群聊功能 开源代码

发布时间:2020-12-15 21:23:39 所属栏目:asp.Net 来源:网络整理
导读:ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程。实时 Web 功能是指这样一种功能:当所连接的客户端变得可用时服务器代码可以立即向其推送内容,而不是让服务器等待客户端请求新的数据。(来自官

ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程。实时 Web 功能是指这样一种功能:当所连接的客户端变得可用时服务器代码可以立即向其推送内容,而不是让服务器等待客户端请求新的数据。(来自官方介绍。)

?-1、写这篇的原因

在上篇文章中,并没有详情介绍SignalR,所以另起一篇专门介绍SignalR,本文的侧重点是Hub功能。

0、先看最终实现效果

github:

在线演示:

1、准备工作

1.1、在NuGet上首先下载SignalR的包。

1.2、配置Owin与SignalR

1.2.1、新建Startup类,注册SignalR

}

然后在web.config配置Startup类,在configuration=>appSettings节点中添加

1.2.2、在页面引入SignalR的js

1、由于SignalR前端是基于jQuery的,所以页面需引入jQuery。

2、引入SignalR的js 。

3、引入最重要的hubs js,这个js其实并不存在,SignalR会反射获取所有供客户端调用的方法放入hubs js中。

1.2.3、新建GroupChatHub类,并继承Hub抽象类

在hub类中的方法就是提供给客户端调用的js方法。

在js中就可以用signalr调用SendMsg。

[HubName( SendMsg( } }</span></pre>

?这样基本上前期准备工作就做完了,后面就是具体的操作。

2、原理与简单的编程

其实原理如果简单点理解就很简单,因为http是无状态的,所以每次请求以后都会与服务器断开链接,那就是说客户端可以很容易找到服务器,但是服务器如果想给你客户端发送消息就比较麻烦,如果不明白的可以参考上一篇文章?。

SignalR就很好的解决了这个问题,也就说实现了实现了浏览器与服务器的全双工通信。

2.1、客户端至服务端(B=>S)

客户端代码

服务端代码

  [HubName( SendMsg( connectionId = cookie = } }</span></pre>

其中SimpleHub就是我们定义的继承HubSimpleHub,然后我们可以用特性HubName进行重命名。

然后开始链接。

在链接完成以后,我们就可以调用在SimpleHub类中调用的方法。这就就很简单的实现了客户端至服务端发送消息。

我们还可以在Context中获取我们想要的东西,比如链接id,cookie等。

2.2、服务端至客户端(S=>B)

服务端代码

[HubName( SendMsg(}</span></pre>

客户端代码

这里演示了怎么发送消息至客户端,也是SignalR比较重要的功能,这里有两个问题需要解决。

问题一、这里是发送消息给所有连着的客户端,如果是单个客户端或者是一批客户端应该怎么发送。

问题二、我们在调用msg给个客户端发送消息时是在接收消息以后做的反馈,然后发送消息给客户端,这样就很类似ajax了,服务端并没有主动给客户端发送消息。

解决:

问题一、Clients可以给特性的一群或者一个客户端发送消息

Clients.All.msg( </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 特定 cooectionId</span> Clients.Client(<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;connectionId</span><span style="color: #800000;"&gt;"</span>).msg(<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;发送给客户端的消息</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;); </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 特定 group</span> Clients.Group(<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;groupName</span><span style="color: #800000;"&gt;"</span>).msg(<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;发送给客户端的消息</span><span style="color: #800000;"&gt;"</span>);</pre>

这是比较常用的三个,当然还有很多,比如AllExcept,Clients。

在SignalR2.0中还添加了Others,OthersInGroup,OthersInGroups等等。

问题二、我们可以在需要发送消息的地方调用GlobalHost.ConnectionManager.GetHubContext().Clients中获取Clients。获取Clients并发送消息我们最好写成单例模式,因为这种需求很符合单例,群聊中有详细的代码。

3、SignalR实现群聊

以上的介绍和代码已经可以实现b=>s和s=>b了,那实现群聊和单独聊天就比较简单了。

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

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

hub代码

[HubName()] userName = Context.RequestCookies[ userName == ? </span><span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<summary></span> <span style="color: #808080;"&gt;///</span><span style="color: #008000;"&gt; 在线用户 </span><span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;</summary></span> <span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;static</span> Dictionary<<span style="color: #0000ff;"&gt;string</span>,<span style="color: #0000ff;"&gt;int</span>> _onlineUser = <span style="color: #0000ff;"&gt;new</span> Dictionary<<span style="color: #0000ff;"&gt;string</span>,<span style="color: #0000ff;"&gt;int</span>><span style="color: #000000;"&gt;(); </span><span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<summary></span> <span style="color: #808080;"&gt;///</span><span style="color: #008000;"&gt; 开始连接 </span><span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;</summary></span> <span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<returns></returns></span> <span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;override</span><span style="color: #000000;"&gt; Task OnConnected() { Connected(); </span><span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;base</span><span style="color: #000000;"&gt;.OnConnected(); } </span><span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<summary></span> <span style="color: #808080;"&gt;///</span><span style="color: #008000;"&gt; 重新链接 </span><span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;</summary></span> <span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<returns></returns></span> <span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;override</span><span style="color: #000000;"&gt; Task OnReconnected() { Connected(); </span><span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;base</span><span style="color: #000000;"&gt;.OnReconnected(); } </span><span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;void</span><span style="color: #000000;"&gt; Connected() { </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 处理在线人员</span> <span style="color: #0000ff;"&gt;if</span> (!_onlineUser.ContainsKey(UserName)) <span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 如果名称不存在,则是新用户</span>

<span style="color: #000000;"> {

            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 加入在线人员</span>
            _onlineUser.Add(UserName,<span style="color: #800080;"&gt;1</span><span style="color: #000000;"&gt;);

            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 向客户端发送在线人员</span>
            Clients.All.publshUser(_onlineUser.Select(i =><span style="color: #000000;"&gt; i.Key));

            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 向客户端发送加入聊天消息</span>
            Clients.All.publshMsg(FormatMsg(<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;系统消息</span><span style="color: #800000;"&gt;"</span>,UserName + <span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;加入聊天</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;));
        }
        </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt;
        {
            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 如果是已经存在的用户,则把在线链接的个数+1</span>
            _onlineUser[UserName] = _onlineUser[UserName] + <span style="color: #800080;"&gt;1</span><span style="color: #000000;"&gt;;
        }

        </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 加入Hub Group,为了发送单独消息</span>
        Groups.Add(Context.ConnectionId,<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;GROUP-</span><span style="color: #800000;"&gt;"</span> +<span style="color: #000000;"&gt; UserName);
    }



    </span><span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<summary></span>
    <span style="color: #808080;"&gt;///</span><span style="color: #008000;"&gt; 结束连接
    </span><span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;</summary></span>
    <span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<param name="stopCalled"&gt;</param></span>
    <span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<returns></returns></span>
    <span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;override</span> Task OnDisconnected(<span style="color: #0000ff;"&gt;bool</span><span style="color: #000000;"&gt; stopCalled)
    {
        </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 人员链接数-1</span>
        _onlineUser[UserName] = _onlineUser[UserName] - <span style="color: #800080;"&gt;1</span><span style="color: #000000;"&gt;;

        </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 判断是否断开了所有的链接</span>
        <span style="color: #0000ff;"&gt;if</span> (_onlineUser[UserName] == <span style="color: #800080;"&gt;0</span><span style="color: #000000;"&gt;)
        {
            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 移除在线人员</span>

<span style="color: #000000;"> _onlineUser.Remove(UserName);

            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 向客户端发送在线人员</span>
            Clients.All.publshUser(_onlineUser.Select(i =><span style="color: #000000;"&gt; i.Key));

            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 向客户端发送退出聊天消息</span>
            Clients.All.publshMsg(FormatMsg(<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;系统消息</span><span style="color: #800000;"&gt;"</span>,UserName + <span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;退出聊天</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;));
        }

        </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 移除Hub Group</span>
        Groups.Remove(Context.ConnectionId,<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;GROUP-</span><span style="color: #800000;"&gt;"</span> +<span style="color: #000000;"&gt; UserName);
        </span><span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;base</span><span style="color: #000000;"&gt;.OnDisconnected(stopCalled);
    }

    </span><span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<summary></span>
    <span style="color: #808080;"&gt;///</span><span style="color: #008000;"&gt; 发送消息,供客户端调用
    </span><span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;</summary></span>
    <span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<param name="user"&gt;</span><span style="color: #008000;"&gt;用户名,如果为0,则是发送给所有人</span><span style="color: #808080;"&gt;</param></span>
    <span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<param name="msg"&gt;</span><span style="color: #008000;"&gt;消息</span><span style="color: #808080;"&gt;</param></span>
    <span style="color: #0000ff;"&gt;public</span> <span style="color: #0000ff;"&gt;void</span> SendMsg(<span style="color: #0000ff;"&gt;string</span> user,<span style="color: #0000ff;"&gt;string</span><span style="color: #000000;"&gt; msg)
    {
        </span><span style="color: #0000ff;"&gt;if</span> (user == <span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;0</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;)
        {
            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 发送给所有用户消息</span>

<span style="color: #000000;"> Clients.All.publshMsg(FormatMsg(UserName,msg));
}
<span style="color: #0000ff;">else<span style="color: #000000;">
{
<span style="color: #808080;">///<span style="color: #008000;">/ 发送给自己消息
<span style="color: #008000;">//<span style="color: #008000;">Clients.Group("GROUP-" + UserName).publshMsg(FormatMsg(UserName,msg));

            <span style="color: #808080;"&gt;///</span><span style="color: #008000;"&gt;/ 发送给选择的人员</span>
            <span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt;Clients.Group("GROUP-" + user).publshMsg(FormatMsg(UserName,msg));


            </span><span style="color: #008000;"&gt;//</span><span style="color: #008000;"&gt; 发送给自己消息</span>
            Clients.Groups(<span style="color: #0000ff;"&gt;new</span> List<<span style="color: #0000ff;"&gt;string</span>> { <span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;GROUP-</span><span style="color: #800000;"&gt;"</span> + UserName,<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;GROUP-</span><span style="color: #800000;"&gt;"</span> +<span style="color: #000000;"&gt; user }).publshMsg(FormatMsg(UserName,msg));

        }
    }


    </span><span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<summary></span>
    <span style="color: #808080;"&gt;///</span><span style="color: #008000;"&gt; 格式化发送的消息
    </span><span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;</summary></span>
    <span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<param name="name"&gt;</param></span>
    <span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<param name="msg"&gt;</param></span>
    <span style="color: #808080;"&gt;///</span> <span style="color: #808080;"&gt;<returns></returns></span>
    <span style="color: #0000ff;"&gt;private</span> <span style="color: #0000ff;"&gt;dynamic</span> FormatMsg(<span style="color: #0000ff;"&gt;string</span> name,<span style="color: #0000ff;"&gt;string</span><span style="color: #000000;"&gt; msg)
    {
        </span><span style="color: #0000ff;"&gt;return</span> <span style="color: #0000ff;"&gt;new</span> { Name = name,Msg = HttpUtility.HtmlEncode(msg),Time = DateTime.Now.ToString(<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;yyyy-MM-dd HH:mm:ss</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;) };
    }
}</span></pre>

js代码