Asp.Net SignalR 使用记录 技术回炉重造-总纲 动态类型dynamic转换为特定类型T的方案 通过对象方法获取委托_C#反射获取委托_ .net core入门-跨域访问配置
Asp.Net SignalR 使用记录
工作上遇到一个推送消息的功能的实现。本着面向百度编程的思想。网上百度了一大堆。主要的实现方式是原生的WebSocket,和SignalR,再次写一个关于Asp.Net SignalR 的demo
这里简单的介绍一下Signalr,SignalR 封装了WebSocket、ForeverFrame、ServerSentEvents、LongPolling四种主要的传输协议。兼容性比较好,WebSocket 是有要求的,IIS服务需要系统是Win8或者 Server 2012 以上。下面开始撸代码。
1.首先建立一个项目。

2.通过包管理工具,引入SignalR

3.引入之后,需要手动添加两个类。
PushHub 集线器类,Singlarl类的主要操作都由这个类实现。
1 public class PushHub : Hub
2 {
3 /// <summary>
4 /// 第一次连接
5 /// </summary>
6 /// <returns></returns>
7 public override Task OnConnected()
8 {
9 return base.OnConnected();
10 }
11
12 /// <summary>
13 /// 断开连接
14 /// </summary>
15 /// <param name="stopCalled"></param>
16 /// <returns></returns>
17 public override Task OnDisconnected(bool stopCalled)
18 {
19 string user = ConnectManager.GetUserName(Context.ConnectionId);
20 ConnectManager.RemoveUser(user);
21 Show(string.Format("{0}退出", user));
22
23 return base.OnDisconnected(stopCalled);
24 }
25
26 /// <summary>
27 /// 获取当前的用户标识
28 /// </summary>
29 /// <returns></returns>
30 private string GetUserId()
31 {
32 return Context.QueryString["userId"];
33 }
34
35 /// <summary>
36 /// 发送消息
37 /// </summary>
38 /// <param name="content"></param>
39 /// <param name="receiveUser"></param>
40 public void Show(string content,string receiveUser="")
41 {
42 string user = ConnectManager.GetUserName(Context.ConnectionId);
43 if (string.IsNullOrEmpty(receiveUser))
44 {
45 Clients.All.show(content);
46 }
47 else {
48 Clients.Client(ConnectManager.GetUserConnect(receiveUser)).show(string.Format("{0}发消息:{1}",user, content));
49 }
50
51 }
52
53 /// <summary>
54 /// 登录操作
55 /// </summary>
56 /// <param name="user"></param>
57 public void Login(string user)
58 {
59
60 ConnectManager.OnlineInit(user, Context.ConnectionId);
61 Show(string.Format("{0}:登录成功", user));
62 }
63
64 }
4.Startup类

public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR(); //声明注册集线器映射
}
}
5.连接管理类
1 /// <summary>
2 /// 连接管理类
3 /// </summary>
4 public class ConnectManager
5 {
6 /// <summary>
7 /// 连接记录池
8 /// </summary>
9 private readonly static ConcurrentDictionary<string, string> _connectPool = new ConcurrentDictionary<string, string>();
10
11 /// <summary>
12 /// 添加用户
13 /// </summary>
14 /// <param name="userKey"></param>
15 /// <param name="connection"></param>
16 public static void AddUser(string userKey, string connection)
17 {
18 _connectPool[userKey] = connection;
19 }
20
21 /// <summary>
22 /// 删除用户
23 /// </summary>
24 /// <param name="userKey"></param>
25 public static void RemoveUser(string userKey)
26 {
27 string connection = null;
28 _connectPool.TryRemove(userKey, out connection);
29 }
30
31 /// <summary>
32 /// 是否存在连接(是否在线)
33 /// </summary>
34 /// <param name="receiverId"></param>
35 /// <returns></returns>
36 public static bool IsOnline(string receiverId)
37 {
38 return _connectPool.Keys.Contains(receiverId);
39 }
40
41 /// <summary>
42 /// 推送消息给个人
43 /// </summary>
44 /// <param name="receiveId"></param>
45 /// <param name="msg"></param>
46 public static void PushSingleMessage(string receiveId, string msg)
47 {
48 try
49 {
50 GetHubContext().Clients.Client(_connectPool[receiveId]).show(msg);
51 }
52 catch (Exception ex)
53 {
54 var errMsg = ex.Message;
55 }
56 }
57
58 /// <summary>
59 /// 获取推送上下文
60 /// </summary>
61 /// <returns></returns>
62 public static IHubContext GetHubContext()
63 {
64 return GlobalHost.ConnectionManager.GetHubContext<PushHub>();
65 }
66
67 /// <summary>
68 /// 上线初始化
69 /// </summary>
70 /// <param name="userId">用户ID</param>
71 /// <param name="connectionId">连接ID</param>
72 public static void OnlineInit(string userId, string connectionId)
73 {
74 AddUser(userId, connectionId);
75 }
76
77 public static string GetUserName(string value)
78 {
79 return _connectPool.Where(a => a.Value == value).FirstOrDefault().Key;
80 }
81
82 public static string GetUserConnect(string userName)
83 {
84 return _connectPool[userName];
85 }
86 }
6.前台代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<div>
用户名称:<input type="text" id="user" placeholder="输入用户名" class="input" /><input type="button" id="login" value="登录" class="btn btn-sm btn-info" /><br />
接收人:<input type="text" id="receiveUser" placeholder="接收人(不填默认群发)" class="input" /><br />
<input type="text" id="content" placeholder="发送内容" class="input" /> <input type="button" value="发送" class="btn btn-sm btn-info" id="send" />
<div>
<h4>接收到的信息:</h4>
<ul id="dataContainer"></ul>
</div>
</div>
<script src="Scripts/jquery-3.3.1.min.js"></script>
<script src="Scripts/jquery.signalR-2.4.1.min.js"></script>
<script src="signalr/hubs"></script> ///这个要注意默认就是这样写,不要问为什么。哈哈
<script language="javascript">
$(function () {
var chat = $.connection.pushHub;
console.log(chat);
//连接服务端集线器,demoHub为服务端集线器名称,js上首字母须改为小写(系统默认)
//定义客户端方法,此客户端方法必须与服务端集线器中的方法名称、参数均一致。
//实际上是服务端调用了前端的js方法(订阅)
//若多个参数,服务端也需要一致
chat.client.show = function (content) {
var html = '<li>' + htmlEncode(content) + "</li>";
$("#dataContainer").append(html);
}
//定义推送
$.connection.hub.start()
.done(function () {
$("#login").click(function () {
chat.server.login($("#user").val()); //将客户端的content内容发送到服务端
$("#user").val("");
});
$("#send").click(function () {
chat.server.show($("#content").val(), $("#receiveUser").val()); //将客户端的content内容发送到服务端
$("#content").val("");
});
});
});
//编码
function htmlEncode(value) {
var encodedValue = $('<div />').text(value).html();
return encodedValue;
}
</script>
</body>
</html>
这就是所有的demo的代码
demo代码:https://github.com/chaorending/Demo.SignalR.git
技术回炉重造-总纲
前言
工作有些年了,总是忙忙碌碌。也用到好些个技术和优秀框架,却不曾深入学习,基础知识又慢慢忘记了,导致现在总感觉空落落的。上个月,经过技术经理的提议及动员,决定部门内部开启每周一次的技术交流会议,大家轮流主持。所以,是时候总结汇总一下了。
正文
.NET平台:
.NET简介;.NET体系结构组件;目标框架;.NET术语表;开放源代码库指南;为服务器应用选择 .NET Core 或 .NET Framework;公共语言运行时 (CLR);.NET 类库;处理和引发异常;垃圾回收;泛型类型;委托和 lambda;LINQ;常规类型系统和公共语言规范;集合和数据结构;.NET中的数字;日期、时间和时区;事件;托管执行过程;元数据和自描述组件;生成控制台应用程序;应用程序要点;文件和流 I/O;全球化和本地化;特性;框架设计准则;XML 文档和数据;安全性;序列化;开发多平台应用程序;
C#语言基础篇:
C#概述;C#环境配置;C#程序结构;C#基本语法;C#数据类型;C#类型转换;C#变量;C#常量和文字;C#运算符;C#判断;C#循环;C#封装;C#方法;C#可空类型;C#数组;C#字符串;C#结构体;C#枚举;C#类;C#继承;C#多态性;C#运算符重载;C#接口;C#命名空间;C#预处理指令;C#正则表达式;C#异常处理;C#文件 I/O
C#语言进阶篇:
C#特性;C#反射;C#属性;C#索引器;C#委托;C#事件;C#集合;C#泛型;C#匿名方法;C#不安全代码;C#多线程
拓展篇:
动态语言拓展;内存管理和指针;错误和异常;程序集;线程 任务和同步 安全性;本地化;事务;网络 windows服务;互操作性;文件和注册表操作;核心ado.net;处理xml;缓存;序列化;编码 过滤器;ICO; DI; AOP; 数据验证;大数据;机器学习;设计模式;
WEB:
Razor;webAPI;MVC;ASP.NET;asp.net Core;Route;
工具&中间件:
Git;Redis Quartz.NET;RabbitMQ;Log4Net;IOC;ORM;Socket;Swagger;
前端篇:
HTML;CSS;javascript;DOM;Json;Ajax;Jquery;Bootstrap;Vue.js;LayUI;node.js;webpack;Chart;
数据库:
mssql;mysql;oracle;mongodb;
动态类型dynamic转换为特定类型T的方案
需求场景:有时候我们抓到一段请求数据,JSON格式的字符串数据,需要放在接口里重现问题,我们就可能会用dynamic先接受数据,然后再转换成特定数据发出请求。
方案一:直接使用特定对象T,来接受请求数据,不可以吗? 当然可以,不过当JSON数据包含子对象时,我遇到了子数据对象丢失的问题。如果你们没有遇到,可以使用。
方案二:使用字符串接受JSON格式的字符串数据,然后反序列化成对象,不过这个你需要对字符串进行处理,加反斜杠,如果你不嫌麻烦,可以使用。
方案三:我个人推荐:使用dynamic类型先接受数据,然后再转换成T对象,比较方便,实用,下面是关键代码:
思路:使用dynamic.ToString()方法,得到Json的字符串,然后使用反序列化方法,可以避免方案一的数据丢失问题。好用!!!推荐!!!

/// <summary>
/// 模拟请求
/// </summary>
/// <param name="fromBody">接收响应结果为加密之后的值</param>
/// <returns>得到解密之后返回的响应结果值</returns>
[HttpPost]
public HttpResponseMessage Test(dynamic fromBody)//dynamic JObject
{
string a = fromBody.ToString();
T t= Newtonsoft.Json.JsonConvert.DeserializeObject<T>(a);
return result;
}

通过对象方法获取委托_C#反射获取委托_
前言:时间紧,先写关键代码,以后优化:
在此感谢其他博友分享的文章,参考文章:C#反射委托创建器
1-定义含有委托的类:

public class TimeCycle
{
/// <summary>
/// 唯一标识
/// </summary>
public int ID { get; set; }
/// <summary>
/// 静态方法委托(只定义委托参数即可)
/// </summary>
public Action<TimeCycle, string> Action { get; set; }
/// <summary>
/// 实例方法委托(实例类型+定义委托参数)
/// </summary>
public Action<MyTipsService, TimeCycle, string> Action2 { get; set; }
}

2-初始化类:
创建委托方法1--创建静态方法的委托,只需要2个参数:委托类型和方法信息:
Delegate.CreateDelegate(typeof(Action<TimeCycle, string>), myTipType.GetMethod("SendTipsToDingding"))
创建委托方法2--创建实例方法的委托,需要2+1个参数:除了上面的委托类型和方法信息;还有,,,还有被委托方法对应的实例类型!!!
即:Action<TimeCycle, string> 类型必须改为含有实例类型的委托:Action<MyTipsService,TimeCycle, string>,至于为什么? 应该是因为,非静态方法的委托调用需要实例依托在实例的基础上,只有实例才能权利调用实例方法。
所以,实例方法创建的委托必须得包含实例类型才能正常创建。
备注:创建委托失败常出现的一个错误,需要对委托的是否静态方法和对应参数进行检查:
System.ArgumentException:“无法绑定到目标方法,因其签名或安全透明度与委托类型的签名或安全透明度不兼容。”

public partial class MyTipsService : ServiceBase
{
public void Test()
{
Type myTipType = typeof(MyTipsService);
//创建静态方法委托1:
TimeCycle timeCycle1 = new TimeCycle
{
ID = 1,
Action = (Action<TimeCycle, string>)Delegate.CreateDelegate(typeof(Action<TimeCycle, string>), myTipType.GetMethod("MyProjectBugTips")),
};
//创建实例方法委托2:
TimeCycle timeCycle2 = new TimeCycle
{
ID = 1,
Action2 = (Action<MyTipsService, TimeCycle, string>)Delegate.CreateDelegate(typeof(Action<MyTipsService, TimeCycle, string>), myTipType.GetMethod("SendTipsToDingding")),
};
var a = 1;
}
#region 获取提醒消息
/// <summary>
/// 每天上下班提醒
/// </summary>
public void SendTipsToDingding(TimeCycle timeCycle, string typeStr)
{
}
/// <summary>
/// 我的项目BUG的提醒
/// </summary>
public static void MyProjectBugTips(TimeCycle timeCycle, string typeStr)
{
}
#endregion
}

.net core入门-跨域访问配置
Asp.net Core 跨域配置
一般情况WebApi都是跨域请求,没有设置跨域一般会报以下错误
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:48057' is therefore not allowed access.

ASP.net Core 跨域有两种,全局和区域
全局跨域:
打开Startup.cs文件.在ConfigureServices方法中添加以下代码
1.配置跨域处理,允许所有来源:
//配置跨域处理,允许所有来源:
services.AddCors(options =>
options.AddPolicy("自定义的跨域策略名称",
p => p.AllowAnyOrigin())
);
2.允许一个或多个具体来源:

//允许一个或多个具体来源:
services.AddCors(options =>
{
// Policy 名稱 CorsPolicy 是自訂的,可以自己改
options.AddPolicy("跨域规则的名称", policy =>
{
// 設定允許跨域的來源,有多個的話可以用 `,` 隔開
policy.WithOrigins("http://localhost:3000","http://127.0.0.1")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});

以上两种按需求选择一种即可.
Configure方法中添加以下代码
app.UseCors("自定义的跨域策略名称");//必须位于UserMvc之前 app.UseMvc();
局部跨域第一种用法:
1.ConfigureServices方法不变,删去Configure中的app.UseCors()方法
2.在Controller顶部或者Action方法顶部加上[EnableCors("自定义的跨域策略名称")]特性,例如
[EnableCors("自定义的跨域策略名称")][Route("api/[controller]")] public class ContactController : Controller
以上就可实现指定某个controller或者action跨域
禁止跨域:
禁止跨域在Controller或者Action加上[DisableCors]特性即可禁止跨域
[HttpGet("{id}")]
[DisableCors]
public string Get(int id)
{
return "value";
}
Asp.Net SignalR 使用记录 技术回炉重造-总纲 动态类型dynamic转换为特定类型T的方案 通过对象方法获取委托_C#反射获取委托_ .net core入门-跨域访问配置的更多相关文章
- .net core入门-跨域访问配置
Asp.net Core 跨域配置 一般情况WebApi都是跨域请求,没有设置跨域一般会报以下错误 No 'Access-Control-Allow-Origin' header is prese ...
- Web Api跨域访问配置及调用示例
1.Web Api跨域访问配置. 在Web.config中的system.webServer内添加以下代码: <httpProtocol> <customHeaders> &l ...
- geoserver源码学习与扩展——跨域访问配置
在 geoserver源码学习与扩展——restAPI访问 博客中提到了geoserver的跨域参数设置,本文详细讲一下geoserver的跨域访问配置. geoserver的跨域访问依赖java-p ...
- SpringBoot 优雅配置跨域多种方式及Spring Security跨域访问配置的坑
前言 最近在做项目的时候,基于前后端分离的权限管理系统,后台使用 Spring Security 作为权限控制管理, 然后在前端接口访问时候涉及到跨域,但我怎么配置跨域也没有生效,这里有一个坑,在使用 ...
- angualr跨域访问配置
浏览器对于javascript的同源策略的限制,例如a.cn下面的js不能调用b.cn中的js,对象或数据(因为a.cn和b.cn是不同域),所以跨域就出现了: 简单的解释就是相同域名,端口相同,协议 ...
- Tomcat跨域访问配置
下载cors-filter-1.7.jar,java-property-utils-1.9.jar这两个库文件,放到Tomcat的lib目录下. D:\Program Files\Tomcat-7.0 ...
- ajax跨域访问 java controller 和 cxf(webservice) 配置方式(CORS)
1. controller跨域访问,配置方式 重点在这里: <mvc:cors> <mvc:mapping path="/*" allowed-origins=& ...
- 解决ajax跨域访问sessionid不一致问题
根据浏览器的保护规则,跨域的时候我们创建的sessionId是不会被浏览器保存下来的,这样,当我们在进行跨域访问的时候,我们的sessionId就不会被保存下来,也就是说,每一次的请求,服务器就会以为 ...
- Jsonp跨域访问
很早之前看过好几篇跨域访问的文章,然后做项目的时候基本没有遇到跨域访问的问题.不过该来的还是会来,前些天终于让我遇到了.于是重温了一下原理这些,再进行实战.于是现在也敢通过实战后的一些理解来和大家分享 ...
随机推荐
- 查看tensorflow是否为MKL版本命令
python -c "import tensorflow; print(tensorflow.pywrap_tensorflow.IsMklEnabled())" source a ...
- 数据结构——顺序栈(sequence stack)
/* sequenceStack.c */ /* 栈 先进后出(First In Last Out,FILO)*/ #include <stdio.h> #include <stdl ...
- 第02组 Beta冲刺(4/4)
队名:十一个憨批 组长博客 作业博客 组长黄智 过去两天完成的任务:了解整个游戏的流程 GitHub签入记录 接下来的计划:继续完成游戏 还剩下哪些任务:完成游戏 燃尽图 遇到的困难:没有美术比较好的 ...
- 使用Shell上传/下载文件
来源:https://www.cnblogs.com/pcyy/p/7568820.html 1,安装lrzsz工具包 yum install lrzsz 2,安装完成后 输入rz选择文件进行上传
- Jenkins使用过程中遇到的问题
1./usr/local/jdk1.8.0_191/ is not a directory on the Jenkins master (but perhaps it exists on some a ...
- 大话设计模式Python实现-装饰模式
装饰模式(Decorator Pattern):动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活. 下面是一个给人穿衣服的过程,使用装饰模式: #!/usr/bin/en ...
- vulnhub之SP:Harrison靶机
下载地址:‘https://www.vulnhub.com/entry/sp-harrison,302/’ 环境:靶机放在virtualbox上运行,网卡模式 攻击机:kali Linux运行在VMw ...
- go-gin-api 规划目录和参数验证(二)
概述 首先同步下项目概况: 上篇文章分享了,使用 go modules 初始化项目,这篇文章咱们分享: 规划目录结构 模型绑定和验证 自定义验证器 制定 API 返回结构 废话不多说,咱们开始吧. 规 ...
- golang语言特性
1. 垃圾回收 a. 内存⾃动回收,再也不需要开发⼈员管理内存 b. 开发人员专注业务实现,降低了心智负担 c. 只需要new分配内存,不需要释放 2. 天然并发 a. 从语⾔层面⽀持并发,⾮常简 ...
- js 宏任务和微任务
.宏任务(macrotask )和微任务(microtask ) macrotask 和 microtask 表示异步任务的两种分类. 在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首 ...