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服务器
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过来,稍作修改。
- 原先我们引用<script src="signalr/hubs"></script>需要替换为<script src="http://localhost:9021/signalr/hubs"></script>
- 在创建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的更多相关文章
- JSP学习笔记(三):简单的Tomcat Web服务器
注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...
- VSTO学习笔记(三) 开发Office 2010 64位COM加载项
原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...
- angular学习笔记(三十一)-$location(2)
之前已经介绍了$location服务的基本用法:angular学习笔记(三十一)-$location(1). 这篇是上一篇的进阶,介绍$location的配置,兼容各版本浏览器,等. *注意,这里介绍 ...
- angular学习笔记(三十一)-$location(1)
本篇介绍angular中的$location服务的基本用法,下一篇介绍它的复杂的用法. $location服务的主要作用是用于获取当前url以及改变当前的url,并且存入历史记录. 一. 获取url的 ...
- JAVA WEB学习笔记(三):简单的基于Tomcat的Web页面
注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...
- iView学习笔记(三):表格搜索,过滤及隐藏列操作
iView学习笔记(三):表格搜索,过滤及隐藏某列操作 1.后端准备工作 环境说明 python版本:3.6.6 Django版本:1.11.8 数据库:MariaDB 5.5.60 新建Django ...
- openresty 学习笔记三:连接redis和进行相关操作
openresty 学习笔记三:连接redis和进行相关操作 openresty 因其非阻塞的调用,令服务器拥有高性能高并发,当涉及到数据库操作时,更应该选择有高速读写速度的redis进行数据处理.避 ...
- Oracle学习笔记三 SQL命令
SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)
- [Firefly引擎][学习笔记三][已完结]所需模块封装
原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读: 笔记三主要就是各个模块的封装了,这里贴 ...
- java之jvm学习笔记三(Class文件检验器)
java之jvm学习笔记三(Class文件检验器) 前面的学习我们知道了class文件被类装载器所装载,但是在装载class文件之前或之后,class文件实际上还需要被校验,这就是今天的学习主题,cl ...
随机推荐
- K-means算法性能评估及其优化
1. SSE误差平方和(Sum of Square due to Error): 聚类情况: 计算公式: 注:SSE参数计算的内容为当前迭代得到的中心位置到各自中心点簇的欧式距离总和,这个值越小表示当 ...
- URL控制器
自定义路由 from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^books/$', view ...
- C# 串口操作系列(5)--通讯库雏形
C# 串口操作系列(5)--通讯库雏形 标签: 通讯c#数据分析byteclassstring 2010-08-09 00:07 21378人阅读 评论(73) 收藏 举报 分类: 通讯类库设计(4 ...
- [Python]CentOS - ImportError: No module named '_curses'
网上搜了不少答案, 基本都是说Windows环境下curses包不适用的问题. 作为碰到这个问题的linux用户,实在感到无奈. 起因是在CentOS上部署uwsgi,想要使用uwsgitop来监控. ...
- Python的使用方法
1 安装turtle Python2安装命令: pip install turtule Python3安装命令: pip3 install turtle 因为turtle库主要是在Python2中使用 ...
- 信息学奥赛辅导经验谈 & 问题教学法中的学生思维能力培养
转载来自朱全民名师工作室 信息学奥赛辅导经验谈 全国青少年信息学奥林匹克分区竞赛(简称NOI)是经中国科协.国家教育部批准,由中国计算机学会主办的一项全国性的青少年学科竞赛活动.随着信息学奥林匹克竞赛 ...
- go 统计目录大小
文件大小获取 // 这里获取的是 FileInfo 对象 fi, _ := os.Stat(filepath) FileInfo 定义如下: type FileInfo interface { Nam ...
- 学习--->更新集合/内存/深浅拷贝
一.计算机基础 1..软件(应用程序) 2.解释器/编译器 - 解释型语言:将代码每一行传递给计算机一行,常用编程语言python,PHP,Ruby. - 编译型语言:将代码完全执行完后会形成一个文 ...
- linux configure 应用
linux下configure命令详细介绍 2018年01月11日 15:02:20 冷月霜 阅读数:705 标签: configure 更多 个人分类: 数据库技术 Linux环境下的软件安装, ...
- 自己封装element-ui树组件的过滤
前言:vue开发项目时用到了element-ui的树组件,但是发现一执行过滤事件,树就全部都展开了,为了解决这个问题,只能自己先过滤数剧,再赋值给树组件的data,就避免了一上来全部展开的尴尬. 一. ...