直接上代码

/// <summary>
/// WebSocket Handler
/// </summary>
public class QWebSocketHandler
{
private WebSocket _websocket;
/// <summary>
/// 用户名
/// </summary>
public string User { get; set; }
/// <summary>
/// webSocket 连接关闭
/// </summary>
public event EventHandler Closed;
/// <summary>
/// webSocket 连接接受信息
/// </summary>
public event EventHandler<string> Received;
/// <summary>
/// webSocket 连接成功
/// </summary>
public event EventHandler<string> Opened;
/// <summary>
/// webSocket 请求连接
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async Task ProcessRequest(AspNetWebSocketContext context)
{
_websocket = context.WebSocket; var login = context.User.Identity.Name;
User = login;
Opened?.Invoke(this, login);
while(true)
{
var buffer = new ArraySegment<byte>(new byte[1024]);
var receivemsg = await _websocket.ReceiveAsync(buffer, System.Threading.CancellationToken.None); if(receivemsg.MessageType == WebSocketMessageType.Close)
{
await _websocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "connect colsed", CancellationToken.None);
Closed?.Invoke(this, EventArgs.Empty);
break; }
if(_websocket.State == WebSocketState.Open)
{
string remsg = Encoding.UTF8.GetString(buffer.Array, 0, receivemsg.Count);
Received?.Invoke(this, remsg);
}
}
}
/// <summary>
/// 向当前连接发送消息
/// </summary>
/// <param name="msg">消息内容</param>
/// <returns></returns>
public async Task<bool> SendMSG(string msg)
{
if (_websocket == null || _websocket.State != WebSocketState.Open)
{
throw new Exception("the web socket is not connected");
}
var sebyte = Encoding.UTF8.GetBytes(msg);
var sebuffer = new ArraySegment<byte>(sebyte); await _websocket.SendAsync(sebuffer, WebSocketMessageType.Text, true, CancellationToken.None);
return true;
}
/// <summary>
/// 关闭当前webSocket连接
/// </summary>
public void Close()
{
if (_websocket == null || _websocket.State == WebSocketState.Closed || _websocket.State == WebSocketState.Aborted)
{
return;
} _websocket.Abort();
}
}
/// <summary>
/// 用户离线消息池
/// </summary>
public class MessagePool
{
/// <summary>
/// 用户
/// </summary>
public string User { get; set; }
/// <summary>
/// 消息集合
/// </summary>
public ConcurrentQueue<OffMessage> MessageS { get; set; } }
/// <summary>
/// 用户离线消息
/// </summary>
public class OffMessage:MessageTemplate
{
/// <summary>
/// 消息失效时间
/// </summary>
public DateTime ValidTime { get; set; } } /// <summary>
/// 消息实体
/// </summary>
public class MessageTemplate
{
/// <summary>
/// 接受消息的用户Login
/// </summary>
public string ToUser { get; set; }
/// <summary>
/// 发送消息的用户Login
/// </summary>
public string FromUser { get; set; }
/// <summary>
/// 消息内容
/// </summary>
public MessageContent MsgContent { get; set; }
} /// <summary>
/// 消息内容体实体模型
/// </summary>
public class MessageContent
{
/// <summary>
/// 标题
/// </summary>
public string Title { get; set; }
/// <summary>
/// 内容
/// </summary>
public string Content { get; set; }
/// <summary>
/// 日期
/// </summary>
public DateTime Time { get; set; }
}

handler

/// <summary>
/// webSocket服务
/// </summary>
public class QWebSocketService
{
private static ConcurrentDictionary<string, QWebSocketHandler> _websockets = new ConcurrentDictionary<string, QWebSocketHandler>();
/// <summary>
/// 用户离线消息池
/// 用户上线直接发送消息给用户
/// 离线消息仅保留3天,72小时
/// </summary>
private static ConcurrentQueue<MessagePool> UserMessageS = new ConcurrentQueue<MessagePool>();
/// <summary>
/// 连接websocket
/// </summary>
/// <param name="Login"></param>
/// <param name="Token"></param>
/// <returns></returns>
public static HttpResponseMessage Connect(System.Web.HttpContext context, string Login)
{ //如果用户存在于连接池则更新 webSocket连接信息,否则新建连接池 var handler = new QWebSocketHandler();
handler.Received -= Socket_Received;
handler.Received += Socket_Received; handler.Closed -= Socket_Closed;
handler.Closed += Socket_Closed; handler.Opened -= Socket_Opened;
handler.Opened += Socket_Opened; if (_websockets.Keys.Contains(Login))
{
var inhandler = _websockets[Login];
inhandler.Close();
_websockets[Login] = handler;
}
else
{
_websockets.TryAdd(Login, handler);
}
context.User = new System.Security.Principal.GenericPrincipal(new System.Security.Principal.GenericIdentity(Login), null); context.AcceptWebSocketRequest(handler); return new HttpResponseMessage(System.Net.HttpStatusCode.SwitchingProtocols); } /// <summary>
/// 清理过期消息
/// </summary>
private static void ClearUserMessage()
{
var validuser = new ConcurrentQueue<MessagePool>(); foreach (var msg in UserMessageS)
{
var valid = new ConcurrentQueue<OffMessage>(); foreach (var msgcontent in msg.MessageS)
{
if ((DateTime.Now - msgcontent.ValidTime).TotalHours < 72)
{
valid.Enqueue(msgcontent);
} }
msg.MessageS = valid;
if (!valid.IsEmpty)
{
validuser.Enqueue(msg);
}
}
UserMessageS = validuser; }
/// <summary>
/// Insert send to offline user's message in messagepool
/// </summary>
/// <param name="msg"></param>
private static void AddUserMessage(MessageTemplate msg)
{
if (UserMessageS.Any(q => q.User == msg.ToUser))
{
//存在离线用户离线消息
var innermsg = UserMessageS.FirstOrDefault(q => q.User == msg.ToUser);
OffMessage offmessage = new OffMessage()
{
ToUser = msg.ToUser,
FromUser = msg.FromUser,
MsgContent = msg.MsgContent,
ValidTime = DateTime.Now
};
innermsg.MessageS.Enqueue(offmessage);
}
else
{
//不存在离线用户消息
OffMessage offMessage = new OffMessage()
{
MsgContent = msg.MsgContent,
FromUser = msg.FromUser,
ToUser = msg.ToUser,
ValidTime = DateTime.Now
};
ConcurrentQueue<OffMessage> msgs = new ConcurrentQueue<OffMessage>();
msgs.Enqueue(offMessage);
MessagePool usermessage = new MessagePool()
{
User = msg.ToUser,
MessageS = msgs
}; UserMessageS.Enqueue(usermessage); } } private static async Task SendOffMessage(QWebSocketHandler socket, string login)
{
//有离线消息则发送
await Task.Delay(2000); //异步等待2秒发送离线消息 var msgs = UserMessageS.FirstOrDefault(q => q.User == login);
if (msgs != null)
{
var sended = new ConcurrentQueue<OffMessage>();
foreach (var omsg in msgs.MessageS)
{
var send = await socket.SendMSG(omsg.MsgContent.ToString()); if (!send)
{
send.Equals(omsg);
}
}
msgs.MessageS = sended; } ClearUserMessage();//清理过期离线消息
}
/// <summary>
/// 向指定用户发送消息
/// </summary>
/// <param name="Login"></param>
/// <param name="msg"></param>
/// <returns></returns>
public static async Task<bool> SendMSG(MessageTemplate msg)
{
if (_websockets.Any(q => q.Key == msg.ToUser))
{
var socket = _websockets[msg.ToUser];
if (socket == null)
{
//用户不在线,消息加入离线
AddUserMessage(msg);
return false;
}
var str = JsonConvert.SerializeObject(msg.MsgContent);
return await socket.SendMSG(str);
}
else
{
//用户不在线,消息加入离线
AddUserMessage(msg);
return false;
} } private static void Socket_Opened(object sender, string login)
{
//连接后,发送离线消息
SendOffMessage((QWebSocketHandler)sender, login);
}
/// <summary>
/// webSocket 接收消息
/// </summary>
/// <param name="sender"></param>
/// <param name="msg"></param>
private static void Socket_Received(object sender, string msg)
{ }
/// <summary>
/// webSocket 客户端关闭
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void Socket_Closed(object sender, EventArgs e)
{
var socket = (QWebSocketHandler)sender;
var csocket = _websockets.FirstOrDefault(q => q.Value == socket); _websockets.TryRemove(csocket.Key, out socket); }
} public static class HttpContextExtension
{
public static void AcceptWebSocketRequest(this HttpContext context, QWebSocketHandler handler)
{
context.AcceptWebSocketRequest(handler.ProcessRequest);
}
}

Service

/// <summary>
/// webSocket 消息管理,
/// 请使用WebSocket协议请求:
/// ws://server/api/msger/{login}/{token}
/// {login}为当前用户名;{token}为当前用户登陆的有效token
/// </summary>
[RoutePrefix("api/msger")]
public class MessageController : LoanAPI
{
private DBContext db = new DBContext();
/// <summary>
/// 请求webSocket连接
/// </summary>
/// <param name="login"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet]
[Route("connect/{login}/{token}")]
[AllowAnonymous]
public HttpResponseMessage Connect(string login, string token)
{
var user = db.SYS_User.FirstOrDefault(q => q.Login == login && q.Token == token);
if (user == null)
{
return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Login is Not Valid");
}
else
{
if(HttpContext.Current.IsWebSocketRequest)
{
return QWebSocketService.Connect(HttpContext.Current, login);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.MethodNotAllowed, "Is Not WebSocekt Request");
} }
}
/// <summary>
/// 向用户发送消息,正常的http请求
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
[HttpPost]
[Route("send")]
public async System.Threading.Tasks.Task<ActionResult<bool>> SendMSGAsync([FromBody] MessageTemplate msg)
{ var sended = await QWebSocketService.SendMSG(msg); return new ActionResult<bool>(sended);
} }

Controller

js Common

(function ($) {

    $.config = {
url: '', //链接地址
token: '',// 通讯key
}; $.init = function (config) {
this.config = config;
return this;
}; /**
* 连接webcocket
*/
$.connect = function () {
var protocol = (window.location.protocol === 'http:') ? 'ws:' : 'wss:';
this.host = protocol + this.config.url;
this.protocols = this.config.token; window.WebSocket = window.WebSocket || window.MozWebSocket;
if (!window.WebSocket) { // 检测浏览器支持
this.error('Error: WebSocket is not supported .');
return;
}
this.socket = new WebSocket(this.host, [this.protocols]); // 创建连接并注册响应函数
this.socket.onopen = function () {
$.onopen();
};
this.socket.onmessage = function (message) {
$.onmessage(message);
};
this.socket.onclose = function () {
$.onclose();
$.socket = null; // 清理
};
this.socket.onerror = function (errorMsg) {
$.onerror(errorMsg);
}
return this;
} /**
* 自定义异常函数
* @param {Object} errorMsg
*/
$.error = function (errorMsg) {
this.onerror(errorMsg);
} /**
* 消息发送
*/
$.send = function (message) {
if (this.socket) {
this.socket.send(message);
return true;
}
this.error('please connect to the server first !!!');
return false;
} $.close = function () {
if (this.socket !== undefined && this.socket !== null) {
this.socket.close();
} else {
this.error("this socket is not available");
}
} /**
* 消息回調
* @param {Object} message
*/
$.onmessage = function (message) {
console.log(message)
} /**
* 链接回调函数
*/
$.onopen = function () {
console.log('连接成功')
} /**
* 关闭回调
*/
$.onclose = function () {
console.log('连接关闭');
} /**
* 异常回调
*/
$.onerror = function (error) {
console.log(error);
} })(ws = {});

Asp.Net WebApi使用Websocket的更多相关文章

  1. C# WebApi+Task+WebSocket实战项目演练(四)

    一.课程介绍 本次分享课程属于<C#高级编程实战技能开发宝典课程系列>中的第四部分,阿笨后续会计划将实际项目中的一些比较实用的关于C#高级编程的技巧分享出来给大家进行学习,不断的收集.整理 ...

  2. C#实战技能之WebApi+Task+WebSocket

    一.背景介绍 环境的局限性: 用户在使用XX客户端的时候,必须每台电脑都安装打印组件,同时由于XX客户端使用的是 websocket进行通讯,这就必须限制用户的电脑浏览器必须是IE10.0+以上版本, ...

  3. 连表查询都用Left Join吧 以Windows服务方式运行.NET Core程序 HTTP和HTTPS的区别 ASP.NET SignalR介绍 asp.net—WebApi跨域 asp.net—自定义轻量级ORM C#之23中设计模式

    连表查询都用Left Join吧   最近看同事的代码,SQL连表查询的时候很多时候用的是Inner Join,而我觉得对我们的业务而言,99.9%都应该使用Left Join(还有0.1%我不知道在 ...

  4. 重温ASP.NET WebAPI(一)初阶

    重温ASP.NET WebAPI(一)初阶   前言 本文为个人对WebApi的回顾无参考价值.主要简单介绍WEB api和webapi项目的基本结构,并创建简单地webaapi项目实现CRUD操作. ...

  5. Asp.Net WebApi核心对象解析(下篇)

    在接着写Asp.Net WebApi核心对象解析(下篇)之前,还是一如既往的扯扯淡,元旦刚过,整个人还是处于晕的状态,一大早就来处理系统BUG,简直是坑爹(好在没让我元旦赶过来该BUG),队友挖的坑, ...

  6. ASP.NET WebApi OWIN 实现 OAuth 2.0

    OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. OAuth 允许用户提供一个令牌, ...

  7. Asp.Net WebApi核心对象解析(上篇)

    生活需要自己慢慢去体验和思考,对于知识也是如此.匆匆忙忙的生活,让人不知道自己一天到晚都在干些什么,似乎每天都在忙,但又好似不知道自己到底在忙些什么.不过也无所谓,只要我们知道最后想要什么就行.不管怎 ...

  8. ASP.NET WebApi 文档Swagger深度优化

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明博客园蜗牛原文地址,cnblogs.com/tdws   写在前面 请原谅我这个标题党,写到了第100篇随笔,说是深度优化,其实也并没有什么深度 ...

  9. ASP.NET WebApi 文档Swagger中度优化

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文地址:www.cnblogs.com/tdws   写在前面 在后台接口开发中,接口文档是必不可少的.在复杂的业务当中和多人对接的情况下,简 ...

随机推荐

  1. django绕过admin登录设置

    在admin.py文件添加以下函数本文是转载:#绕过admin登录def allow_anonymous_user(): from django.contrib.auth.models import ...

  2. Matlab 条件循环函数

    条件判断 if 表达式 语句 elseif 表达式 语句 -. else 语句 end 这个与c语言不同的就是 1:要多一个end 2:还有没有括号 3:else if连在一起 for 循环 for ...

  3. 关于transition动画效果中,滚动条会闪一下就消失的问题

    具体问题说明: 我在通过transition来改变width的长度,在transition变化过程中,底下的滚动条会闪烁一下. 问题原理:因为是里面容器没办法完全被装下,并且容器的宽度被限制住了. 解 ...

  4. Alpha冲刺-第八次冲刺笔记

    Alpha冲刺-冲刺笔记 这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzzcxy/2018SE2 这个作业要求在哪里 https://edu.cnblogs. ...

  5. App自动化《元素定位方式、元素操作、混合应用、分层设计、代码方式执行Pytest 命令》

    坚持原创输出,点击蓝字关注我吧 作者:清菡 博客:oschina.云+社区.知乎等各大平台都有. 目录 一.App 元素定位方式 二.元素操作 三.测试混合应用 四.以代码的方式执行 Pytest 命 ...

  6. 第8.24节 使用__subclasses__查看类的直接子类

    在<第8.9节 Python类中内置的__bases__属性>中介绍了__bases__这个类的特殊变量可以查看类的直接父类,而__subclasses__() 方法的使用则与__base ...

  7. PyQt学习随笔:ListView控件的视图和数据模型分离案例

    Qt 中view类控件的目的是实现数据和模型分离,控件展示数据,数据保存在数据存储中,数据存储中的数据改变了,则控件中展示的数据跟随改变.当设计时只指定了一个控件和一个数据存储关联时,这种分离虽然也能 ...

  8. PyQt(Python+Qt)学习随笔:Qt Designer中部件与国际化有关的设置translatable、 disambiguation和comment含义

    在Qt Designer的部件的多个属性中,如toolTip.whatsThis.accessibleName.accessibleDescription.text等都有国际化属性设置,国际化属性有三 ...

  9. PyQt(Python+Qt)学习随笔:QAbstractItemView的dragEnabled属性的困惑

    老猿Python博文目录 老猿Python博客地址 dragEnabled属性用于控制视图是否支持拖拽,可以通过dragEnabled().setDragEnabled(bool enable)进行属 ...

  10. CSS基础-边框

    border border-top设置上边界 border-bottom / border-left / border-right 同理 可以为每一条边设置 : border-top-width宽度 ...