SignalR学习笔记(三)Self-Host

SignalR可以借助Owin摆脱对IIS的依赖,实现Self-Host,使得SignalR有了部署在非Windows平台的可能。

 

什么是Owin

Owin的英文全称是Open Web Interface for .NET, 他定义了Web应用程序和Web服务器之间的接口。他的作用就是解除了Web应用程序与Web服务器之间的耦合,从而使Web应用程序不再依赖于具体的Web服务器,已ASP.NET应用程序为例,以前需要依赖于IIS,  引入Owin之后,他只依赖与Owin提供的接口,所以所有实现Owin接口的Web服务器都可以替换掉IIS。

 

如何在控制台程序中实现SignalR Self-Host

 #

创建一个空的控制台程序#

 

引入SignalR SelfHost包#

打开Package Manager Console面板,输入以下命令安装SignalR Self Host包。

Install-package Microsoft.AspNet.SignalR.SelfHost

 

其他可能需要引入的包#

因为如果使用Self-Host, 通常会指定一个独立的端口或者独立ip,这样就会出现跨域的问题,如果出现跨域问题,请引入Owin的CORS包

Install-package Microsoft.Owin.Cors

使用Owin启动一个Web服务器#

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    class Program
 
    {
 
        static void Main(string[] args)
 
        {
 
            string url = "http://localhost:9021";
 
            using (WebApp.Start(url))
 
            {
 
                Console.WriteLine("Server running on {0}", url);
 
                Console.ReadKey();
 
            }
 
        }
 
}

 

 

添加Owin启动类#

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    class Startup
 
    {
 
        public void Configuration(IAppBuilder app)
 
        {
 
            //允许所有域名跨域访问
 
            app.UseCors(CorsOptions.AllowAll);
 
  
 
            //启动SignalR
 
            app.MapSignalR();
 
        }
 
    }


 

 

添加Hub代码#

这里我们可以直接把学习笔记(一)中的Hub代码直接Copy过来,最终的的Self Host代码如下

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
using Microsoft.AspNet.SignalR;
 
using Microsoft.Owin.Cors;
 
using Microsoft.Owin.Hosting;
 
using Owin;
 
using System;
 
using System.Collections.Generic;
 
using System.Linq;
 
  
 
namespace SignalRSelfHost
 
{
 
    class Program
 
    {
 
        static void Main(string[] args)
 
        {
 
            string url = "http://localhost:9021";
 
            using (WebApp.Start(url))
 
            {
 
                Console.WriteLine("Server running on {0}", url);
 
                Console.ReadKey();
 
            }
 
        }
 
    }
 
  
 
    class Startup
 
    {
 
        public void Configuration(IAppBuilder app)
 
        {
 
            //允许所有域名跨域访问
 
            app.UseCors(CorsOptions.AllowAll);
 
  
 
            //启动SignalR
 
            app.MapSignalR();
 
        }
 
    }
 
  
 
    public class ChatRoomHub : Hub
 
    {
 
        private static Dictionary<string, string> _nickNames = new Dictionary<string, string>();
 
  
 
        public void SetNickName(string nickName)
 
        {
 
            //当Hub启动完毕,每个连接到这个Hub的客户端都会自动分配一个唯一的ConnectionId。
 
            //当SignalR向指定客户端推送消息的时候,需要指定ConnectionId, 所以这里需要记录一下每个昵称对应的客户端ConnectionId
 
            _nickNames.Add(Context.ConnectionId, nickName);
 
  
 
            //当用户设置昵称之后,需要发送欢迎信息到所有的用户客户端,调用客户端receiveWelcomeMessage方法显示欢迎信息
 
            Clients.All.ReceiveWelcomeMessage($"{nickName}进入聊天室。");
 
        }
 
  
 
        public void Send(string nickName, string message)
 
        {
 
            if (string.IsNullOrWhiteSpace(nickName) || string.IsNullOrWhiteSpace(message))
 
            {
 
                //如果用户昵称或者消息不存在,就不做任何操作
 
                return;
 
            }
 
  
 
            if (message.StartsWith("to") && message.Split(' ').Length == 3)
 
            {
 
                //私聊消息
 
                var toUserName = message.Split(' ')[1];
 
  
 
                if (_nickNames.ContainsValue(toUserName))
 
                {
 
                    var connectionId = _nickNames.First(p => p.Value == toUserName).Key;
 
  
 
                    if (!string.IsNullOrWhiteSpace(connectionId) && connectionId != Context.ConnectionId)
 
                    {
 
                        Clients.Client(connectionId).ReceivePrivateMessage(nickName, message.Split(' ')[2]);
 
                    }
 
                }
 
            }
 
            else
 
            {
 
                //普通广播消息
 
                if (_nickNames.ContainsValue(nickName))
 
                {
 
                    Clients.All.ReceiveBroadcastMessage(nickName, message);
 
                }
 
            }
 
        }
 
    }
 
}


 

运行程序#

按Ctrl+F5启动控制台程序, 显示Server running on xxxxx.表明服务器启动成功。

 

 

添加聊天室网页#

 

这里需要重新创建一个空的Web程序

添加所需SignalR库#

因为SignalR服务器已经移到了控制台程序当中,所以这里不需要应用Microsft.AspNet.SignalR库了

 

这里仅需要引入SignalR的客户端脚本

Install-package Microsoft.AspNet.SignalR.JS

 

添加聊天网页#

这里我们将学习笔记(一)的代码直接copy过来,稍作修改。

  1. 原先我们引用<script src="signalr/hubs"></script>需要替换为<script src="http://localhost:9021/signalr/hubs"></script>
  2. 在创建Hub代理之前,需要设置SignalR服务器的地址

$.connection.hub.url = 'http://localhost:9021/signalr';

 

 

最终网页代码#

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
<!DOCTYPE html>
 
<html>
 
<head>
 
    <title>SignalR Simple Chat</title>
 
    <style type="text/css">
 
        .container {
 
            background-color: #99CCFF;
 
            border: thick solid #808080;
 
            padding: 20px;
 
            margin: 20px;
 
        }
 
    </style>
 
</head>
 
<body>
 
    <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>
 
    <script src="Scripts/jquery-1.6.4.min.js"></script>
 
    <script src="Scripts/jquery.signalR-2.2.2.min.js"></script>
 
    <!--<script src="signalr/hubs"></script>-->
 
    <script src="http://localhost:9021/signalr/hubs"></script>
 
  
 
    <script type="text/javascript">
 
        $(function () {
 
  
 
            $.connection.hub.url = 'http://localhost:9021/signalr';
 
  
 
            //使用代理模式, 创建客户端的hub代理
 
            var chat = $.connection.chatRoomHub;
 
  
 
            //服务器Hub中, 调用ReceiveWelcomeMessage方法时, 会执行客户端的chat.client.receiveBroadcastMessage方法
 
            chat.client.receiveBroadcastMessage = function (name, message) {
 
  
 
                //防JS输入
 
                var encodedName = $('<div />').text(name).html();
 
                var encodedMsg = $('<div />').text(message).html();
 
  
 
                $('#discussion').append('<li><strong>' + encodedName
 
                    + '</strong>:  ' + encodedMsg + '</li>');
 
            };
 
  
 
            //服务器Hub中, 调用ReceiveWelcomeMessage方法时, 会执行客户端的chat.client.receiveWelcomeMessage方法
 
            chat.client.receiveWelcomeMessage = function (message) {
 
                var encodedMsg = $('<div />').text(message).html();
 
  
 
                $('#discussion').append('<li><strong style="color:blue">' + encodedMsg
 
                    + '</strong></li>');
 
            };
 
  
 
            //服务器Hub中, 调用ReceivePrivateMessage方法时, 会执行客户端的chat.client.receivePrivateMessage方法
 
            chat.client.receivePrivateMessage = function (name, message) {
 
                var encodedName = $('<div />').text(name).html();
 
                var encodedMsg = $('<div />').text(message).html();
 
  
 
                $('#discussion').append('<li><strong style="color: green">' + encodedName
 
                    + '偷偷的跟你说</strong>:  ' + encodedMsg + '</li>');
 
            };
 
  
 
            //通过代理连接到服务器Hub
 
            $.connection.hub.start().done(function () {
 
                $('#sendmessage').click(function () {
 
                    chat.server.send($('#displayname').val(), $('#message').val());
 
  
 
                    $('#message').val('').focus();
 
                });
 
  
 
                //连接成功后, 需要用户立刻输入昵称
 
                $('#displayname').val(prompt('Enter your name:', ''));
 
                chat.server.setNickName($('#displayname').val());
 
                $('#message').focus();
 
            });
 
        });
 
    </script>
 
</body>
 
</html>


 

 

启动程序,效果如下#

 

酷炫功能

使用Self-Host之后,我们可以实现一个很酷炫的功能,在控制台程序中监控用户的输入

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
public class ChatRoomHub : Hub
 
    {
 
        private static Dictionary<string, string> _nickNames = new Dictionary<string, string>();
 
  
 
        public void SetNickName(string nickName)
 
        {
 
            //当Hub启动完毕,每个连接到这个Hub的客户端都会自动分配一个唯一的ConnectionId。
 
            //当SignalR向指定客户端推送消息的时候,需要指定ConnectionId, 所以这里需要记录一下每个昵称对应的客户端ConnectionId
 
            _nickNames.Add(Context.ConnectionId, nickName);
 
  
 
            //当用户设置昵称之后,需要发送欢迎信息到所有的用户客户端,调用客户端receiveWelcomeMessage方法显示欢迎信息
 
            Clients.All.ReceiveWelcomeMessage($"{nickName}进入聊天室。");
 
            Console.WriteLine($"{nickName}进入聊天室。");
 
        }
 
  
 
        public void Send(string nickName, string message)
 
        {
 
            if (string.IsNullOrWhiteSpace(nickName) || string.IsNullOrWhiteSpace(message))
 
            {
 
                //如果用户昵称或者消息不存在,就不做任何操作
 
                return;
 
            }
 
  
 
            if (message.StartsWith("to") && message.Split(' ').Length == 3)
 
            {
 
                //私聊消息
 
                var toUserName = message.Split(' ')[1];
 
  
 
                if (_nickNames.ContainsValue(toUserName))
 
                {
 
                    var connectionId = _nickNames.First(p => p.Value == toUserName).Key;
 
  
 
                    if (!string.IsNullOrWhiteSpace(connectionId) && connectionId != Context.ConnectionId)
 
                    {
 
                        Clients.Client(connectionId).ReceivePrivateMessage(nickName, message.Split(' ')[2]);
 
                        Console.WriteLine($"{nickName}偷偷对{toUserName}说:{message}");
 
                    }
 
                }
 
            }
 
            else
 
            {
 
                //普通广播消息
 
                if (_nickNames.ContainsValue(nickName))
 
                {
 
                    Clients.All.ReceiveBroadcastMessage(nickName, message);
 
                    Console.WriteLine($"{nickName}对大家说:{message}");
 
                }
 
            }
 
        }
 
    }


 

posted @   LamondLu  阅读(583)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示
主题色彩