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服务器

    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启动类

    class Startup

    {

        public void Configuration(IAppBuilder app)

        {

            //允许所有域名跨域访问

            app.UseCors(CorsOptions.AllowAll);

 

            //启动SignalR

            app.MapSignalR();

        }

    }

添加Hub代码

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

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';

最终网页代码

<!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之后,我们可以实现一个很酷炫的功能,在控制台程序中监控用户的输入

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}");

                }

            }

        }

    }

SignalR学习笔记(三)Self-Host的更多相关文章

  1. JSP学习笔记(三):简单的Tomcat Web服务器

    注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...

  2. VSTO学习笔记(三) 开发Office 2010 64位COM加载项

    原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...

  3. angular学习笔记(三十一)-$location(2)

    之前已经介绍了$location服务的基本用法:angular学习笔记(三十一)-$location(1). 这篇是上一篇的进阶,介绍$location的配置,兼容各版本浏览器,等. *注意,这里介绍 ...

  4. angular学习笔记(三十一)-$location(1)

    本篇介绍angular中的$location服务的基本用法,下一篇介绍它的复杂的用法. $location服务的主要作用是用于获取当前url以及改变当前的url,并且存入历史记录. 一. 获取url的 ...

  5. JAVA WEB学习笔记(三):简单的基于Tomcat的Web页面

    注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...

  6. iView学习笔记(三):表格搜索,过滤及隐藏列操作

    iView学习笔记(三):表格搜索,过滤及隐藏某列操作 1.后端准备工作 环境说明 python版本:3.6.6 Django版本:1.11.8 数据库:MariaDB 5.5.60 新建Django ...

  7. openresty 学习笔记三:连接redis和进行相关操作

    openresty 学习笔记三:连接redis和进行相关操作 openresty 因其非阻塞的调用,令服务器拥有高性能高并发,当涉及到数据库操作时,更应该选择有高速读写速度的redis进行数据处理.避 ...

  8. Oracle学习笔记三 SQL命令

    SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)  

  9. [Firefly引擎][学习笔记三][已完结]所需模块封装

    原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读:        笔记三主要就是各个模块的封装了,这里贴 ...

  10. java之jvm学习笔记三(Class文件检验器)

    java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...

随机推荐

  1. 树莓派B+使用入门&RPI库安装&wringPi库安装

    最近看看试用一下树莓派进行一些开发操作,于是入手一块Raspberry Pi B+的板子来玩.由于没有显示器,没有备用的键盘和鼠标,所以想到用SSH来控制树莓派,刚开始还很担心已经安装好的操作系统到底 ...

  2. 南京邮电大学//bugkuCTF部分writeup

    WEB 1.签到题 nctf{flag_admiaanaaaaaaaaaaa} 右键查看源代码或按f12即可. 2.这题不是web nctf{photo_can_also_hid3_msg} 下载图片 ...

  3. jQuery各类选择器

  4. CentOS7更换国内源

    前言 CentOS 有个很方便的软件安装工具yum,但是默认安装完CentOS,系统里使用的是国外的CentOS更新源,这就造成了我们使用默认更新源安装或者更新软件时速度很慢的问题,甚至更新失败. 为 ...

  5. 在VB中动态执行VBS代码,可操控窗体控件

    通过执行一段VBS代码来操控窗体内的控件也可以使用AddObject方法添加自己的类,那么在动态VBS代码中也一样可以使用在增加程序扩展性或是有脚本化需求的时候,这个方法还是不错的. Option E ...

  6. delegate异步

    using System; using System.Runtime.Remoting.Messaging; using System.Threading; using System.Threadin ...

  7. h5适配的解决方案

    一. 流程 设计师以750pt×1334pt尺寸进行设计(当然高度随内容变化),最后用该尺寸的设计稿进行标注.切图,前端采用淘宝的开源方案flexible进行适配. 二. flexible使用方法 F ...

  8. 【C语言】多项式加法(mooc第七周测试题)

    这个小题目吧我折磨的够呛,,主要在于特殊情况考虑不周,测试用例老是通不过.. 小结: 做法:用一个数组来存储多项式,用下标表示幂次数,数组元素值表示对应系数 输出特殊格式考虑:系数和幂次数为0,1,- ...

  9. [LeetCode] Score of Parentheses 括号的分数

    Given a balanced parentheses string S, compute the score of the string based on the following rule: ...

  10. 快速搭建react项目骨架(按需加载、redux、axios、项目级目录等等)

    一.前言 最近整理了一下项目骨架,顺便自定义了一个脚手架,方便日后使用.我会从头开始,步骤一步步写明白,如果还有不清楚的可以评论区留言.先大致介绍一下这个骨架,我们采用 create-react-ap ...