Asp.Net FrameWork 4.7.2 WebAPI 使用WebSocket协议

参考文章:Asp.net webApi 通过WebSocket推送消息给客户端,搭建一个即是服务端又是客户端的服务_c# webapi websocket-CSDN博客

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。

WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

废话不多说了,直接手把手教你如何通信。

下面是一个简单的用户连接和断开操作实例代码,有别的业务需求可以根据自己情况修改一下代码

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.WebSockets;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.WebSockets;
using WYC.DAL.DAL;

namespace WYC.WebAPI.Controllers
{
    /// <summary>
    /// 聊天控制器
    /// </summary>
    [RoutePrefix("Chat")]
    [AllowAnonymous] //不授权
    public class ChatController : ApiController
    {
        /// <summary>
        /// 记录客户端(根据用户ID一一对应)
        /// </summary>
        private static Dictionary<string, WebSocket> _listSockets = new Dictionary<string, WebSocket>();

        /// <summary>
        /// 业务逻辑层
        /// </summary>
        private readonly ChatDAL _dal = new ChatDAL();

        /// <summary>
        /// 连接
        /// </summary>
        /// <param name="userId">用户Id</param>
        /// <returns></returns>
        [Route("GetConnect"), HttpGet]
        public async Task<HttpResponseMessage> GetConnect(string userId)
        {
            await _dal.UpdateUserOnlineState(userId, 1); //修改用户在线状态
            //指定执行不带参数的方法(注意:ProcessRequest(AspNetWebSocketContext context)这样属于不带参数,当前这个方法因为多了一个userId参数所以属于带参数方法)
            //HttpContext.Current.AcceptWebSocketRequest(ProcessRequest); 
            //指定执行额外带参数的方法(注意:ProcessRequest(AspNetWebSocketContext context)这样属于不带参数,当前这个方法因为多了一个userId参数所以属于带参数方法)
            Func<AspNetWebSocketContext, Task> paramnter = async (context) =>
               {
                   await ProcessRequest(context, userId);
               };
            HttpContext.Current.AcceptWebSocketRequest(paramnter);
            return Request.CreateResponse(HttpStatusCode.SwitchingProtocols);
        }

        /// <summary>
        /// 客户端连接成功后执行方法(接收信息和发送信息)
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task ProcessRequest(AspNetWebSocketContext context, string userId)
        {
            var socket = context.WebSocket;
            _sockets.Add(socket); //存放客户端连接的WebSocket
            _listSockets.Add(userId, socket); //存放客户端连接的WebSocket
            while (true) //进入一个无限循环,一直监听当前连接成功的客户端操作行为
            {
                var buffer = new ArraySegment<byte>(new byte[1024]);
                //对web socket进行异步接收数据(相当于是等待客户端发送消息)
                var receivedResult = await socket.ReceiveAsync(buffer, System.Threading.CancellationToken.None);
                if (receivedResult.MessageType == WebSocketMessageType.Close) //客户端断开连接
                {
                    await socket.CloseAsync(WebSocketCloseStatus.Empty, string.Empty, System.Threading.CancellationToken.None);//如果client发起close请求,对client进行ack
                    _listSockets.Remove(userId); //删除
                    break; //结束循环
                }
                if (socket.State == WebSocketState.Open) //客户端连接状态
                {
                    //获取客户端发送消息内容
                    string recvMsg = Encoding.UTF8.GetString(buffer.Array, 0, receivedResult.Count);
                }

            }
        }
    }
}

注意这里有一个小小的重点:

一、HttpContext.Current.AcceptWebSocketRequest(ProcessRequest); 
二、 Func<AspNetWebSocketContext, Task> paramnter = async (context) =>
               {
                   await ProcessRequest(context, userId);
               };
            HttpContext.Current.AcceptWebSocketRequest(paramnter);

以上两个代码区别就是一个指定带参数的方法,一个指定不带参数的方法,上面的一是指定不带参数的方法:相当于指定执行ProcessRequest(AspNetWebSocketContext context)这样的方法,上面的二是指定带参数的方法:相当于指定执行ProcessRequest(AspNetWebSocketContext context, string userId)这样多了一个参数的方法。正常咱们在处理业务和数据库对接的话都会设计到带参数所以这里是个重点。

以下代码是个人成功案例,可以根据自己业务需求进行调整代码

一、控制器

注意:这里不需要下载任何什么SDK包,就是引用一下系统自带的包如下:

using System.Net.WebSockets;

using System.Web.WebSockets;

1、首先创建一个ChatController继承自ApiController,如下代码:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.WebSockets;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.WebSockets;
using WYC.DAL.DAL;

namespace WYC.WebAPI.Controllers
{
    /// <summary>
    /// 聊天控制器
    /// </summary>
    [RoutePrefix("Chat")]
    [AllowAnonymous] //不授权
    public class ChatController : ApiController
    {
        /// <summary>
        /// 记录客户端(根据用户ID一一对应)
        /// </summary>
        private static Dictionary<string, WebSocket> _listSockets = new Dictionary<string, WebSocket>();

        /// <summary>
        /// 业务逻辑层
        /// </summary>
        private readonly ChatDAL _dal = new ChatDAL();

        /// <summary>
        /// 连接
        /// </summary>
        /// <param name="userId">用户Id</param>
        /// <returns></returns>
        [Route("GetConnect"), HttpGet]
        public async Task<HttpResponseMessage> GetConnect(string userId)
        {
            await _dal.UpdateUserOnlineState(userId, 1); //修改用户在线状态
            //指定执行不带参数的方法(注意:ProcessRequest(AspNetWebSocketContext context)这样属于不带参数,当前这个方法因为多了一个userId参数所以属于带参数方法)
            //HttpContext.Current.AcceptWebSocketRequest(ProcessRequest); 
            //指定执行额外带参数的方法(注意:ProcessRequest(AspNetWebSocketContext context)这样属于不带参数,当前这个方法因为多了一个userId参数所以属于带参数方法)
            Func<AspNetWebSocketContext, Task> paramnter = async (context) =>
               {
                   await ProcessRequest(context, userId);
               };
            HttpContext.Current.AcceptWebSocketRequest(paramnter);
            return Request.CreateResponse(HttpStatusCode.SwitchingProtocols);
        }

        /// <summary>
        /// 客户端连接成功后执行方法(接收信息和发送信息)
        /// </summary>
        /// <param name="context">WebSocket上下文类</param>
        /// <param name="userId">当前连接用户Id</param>
        /// <returns></returns>
        public async Task ProcessRequest(AspNetWebSocketContext context, string userId)
        {
            var socket = context.WebSocket;
            _listSockets.Add(userId, socket); //存放客户端连接的WebSocket
            while (true) //进入一个无限循环,一直监听当前连接成功的客户端操作行为
            {
                var buffer = new ArraySegment<byte>(new byte[1024]);
                //对web socket进行异步接收数据(相当于是等待客户端发送消息)
                var receivedResult = await socket.ReceiveAsync(buffer, System.Threading.CancellationToken.None);
                if (receivedResult.MessageType == WebSocketMessageType.Close) //客户端断开连接
                {
                    await socket.CloseAsync(WebSocketCloseStatus.Empty, string.Empty, System.Threading.CancellationToken.None);//如果client发起close请求,对client进行ack
                    _listSockets.Remove(userId); //删除
                    await _dal.UpdateUserOnlineState(userId, 0); //修改用户离线状态
                    break; //结束循环
                }
                if (socket.State == WebSocketState.Open) //客户端连接状态
                {
                    //获取客户端发送消息内容
                    string recvMsg = Encoding.UTF8.GetString(buffer.Array, 0, receivedResult.Count);
                    //根据 前端|特殊字符 切割 获取接收信息用户Id
                    string receiptUserId = recvMsg.Substring(0, recvMsg.IndexOf("|"));
                    recvMsg = recvMsg.Substring(recvMsg.IndexOf("|") + 1); //获取完整聊天信息
                    await SendMessageToClientAsync(userId, receiptUserId, recvMsg); //一对一聊天
                }

            }
        }


        /// <summary>
        /// 发送消息给指定用户(一对一聊天)
        /// </summary>
        /// <param name="sendUserId">发送用户Id</param>
        /// <param name="receiptUserId">接受用户Id</param>
        /// <param name="message">发送消息</param>
        /// <returns></returns>
        public async Task SendMessageToClientAsync(string sendUserId, string receiptUserId, string message)
        {
            //判断当前接受用户是否在词典里 并且 获取WebSocket
            if (_listSockets.TryGetValue(receiptUserId, out WebSocket client)) //存在 则实时推送消息给用户
            {
                if (client.State == WebSocketState.Open) //打开状态
                {
                    byte[] buffer = Encoding.UTF8.GetBytes(message);
                    ArraySegment<byte> segment = new ArraySegment<byte>(buffer);
                    //发送对应的client用户消息
                    await client.SendAsync(segment, WebSocketMessageType.Text, true, System.Threading.CancellationToken.None);
                }
            }
            //将聊天信息存放数据库
            await _dal.AddUserChatMessage(sendUserId, receiptUserId, message); //添加一对一聊天记录
        }

        /// <summary>
        /// 群发消息给用户(群发消息)
        /// </summary>
        /// <param name="message">消息</param>
        /// <returns></returns>
        public async Task SendMessageToAllAsync(string message)
        {
            //这里因为WebSocket发送数据需要时字节格式 所以将字符串转换成字节,实际前端接收到的消息是字符串
            byte[] buffer = Encoding.UTF8.GetBytes(message);
            ArraySegment<byte> segment = new ArraySegment<byte>(buffer);
            //遍历所有在线用户并发送数据
            foreach (var client in _listSockets.Values)
            {
                if (client.State == WebSocketState.Open) //打开状态
                {
                    //发送对应的client用户消息
                    await client.SendAsync(segment, WebSocketMessageType.Text, true, System.Threading.CancellationToken.None);
                }
            }
        }
    }
}

二、前端代码

需要引用jquery.js包如下代码:

<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-1.11.3.min.js"></script>
var socket;

//Socket连接
function Connection() {
    try {
        //192.168.1.7:1112把这个IP和端口替换成自己WebAPI项目IP和端口 其实这里跟Http协议一样的请求道理,无非就是把http://替换成了ws://
        var host = "ws://192.168.1.7:1112/Chat/GetConnect?userId=" + userId;
        socket = new WebSocket(host);
        /*连接*/
        socket.onopen = function (msg) {
            console.log("连接成功");
        };
        ReceptionMsg(); //接收消息
    } catch (e) {
        alert(e);
    }

}

//Socket发送消息
function SocketSendMsg(msg) {
    if (socket.readyState == WebSocket.OPEN) {
        //ltHyUserId:接收消息的用户Id   msg:消息  这里使用特殊字符|隔开,后端需要加工处理
        socket.send(ltHyUserId + "|" + msg);
    } else {
        alert('连接已关闭');
    }
}

//Socket关闭连接
function SocketClose() {
    socket.close(); //关闭
}


//Socket接收服务端消息
function ReceptionMsg() {
    /*接收消息*/
    socket.onmessage = function (evt) {
        console.log(evt.data); //接收到服务端发送过来的消息
    }
}

注意:

需要将IIS安装WebSocket协议,不管是服务器还是本机都需要,如下步骤:

1、打开控制面板

2、点击程序

3、点击启用和关闭Windows功能

4、勾选WebSocket协议

然后确认重启电脑就OK了。

<think>好的,用户想在.NET WebAPI使用WebSocket,需要示例和教程。首先,我需要回忆相关的知识,结合提供的引用内容,特别是引用[1]、[2]、[3]、[4]中的信息。 首先,用户可能已经知道WebSocket的基本概念,但需要具体的实现步骤。根据引用[1]和[4],ASP.NET Framework 4.7.2可以通过WebSocket推送消息,而引用[3]提到在.NET8中使用ASP.NET Core和SignalR。但用户的问题是关于.NET WebAPI的,可能需要区分不同版本,比如传统的ASP.NETASP.NET Core的不同实现方式。 根据引用[2],WebSocket握手是通过HTTP请求升级的,需要在服务端处理Upgrade头。而引用[3]中的示例使用ASP.NET Core的中间件和MapWebSocketMiddleware,这可能适用于较新的版本。但用户的问题可能更倾向于传统ASP.NET WebAPI,比如使用OWIN中间件或者HttpListenerContext。 需要确认用户的具体环境是ASP.NET Framework还是ASP.NET Core,但根据提供的引用,引用[1]和[4]是传统的ASP.NET,而引用[3]是Core。因此,可能需要分别给出两种情况的示例。 不过,用户的问题没有明确版本,可能需要给出两种方案。或者,优先回答ASP.NET Core的,因为现在更常用。例如,在ASP.NET Core中使用中间件处理WebSocket,或者结合SignalR简化操作。 根据引用[3],在ASP.NET Core中,可以通过app.UseWebSockets()启用中间件,然后使用MapWebSocketMiddleware处理连接。同时,SignalR可以更方便地管理消息传递。因此,可能需要分步骤说明如何在Core中实现,并提到传统框架的方法。 同时,引用[5]提到获取客户端信息,可能需要注意在WebSocket处理中如何获取客户端信息,比如IP地址等。 因此,回答的结构应该是先介绍WebSocket的基本概念,然后分版本(ASP.NET Framework和Core)给出实现步骤,并提供代码示例。同时,注意事项如跨域处理、心跳机制等也需要提及,以确保回答的全面性。 需要检查提供的引用是否有具体的代码示例。例如,引用[1]提到搭建既是服务端又是客户端的服务,可能需要展示如何接受连接和发送消息。引用[3]中的步骤包括添加中间件和编写处理类,这可能在Core中更常见。 总结回答步骤: 1. 创建ASP.NET Core WebAPI项目 2. 配置中间件启用WebSocket 3. 编写处理连接的中间件或控制器 4. 客户端JavaScript示例 5. 注意事项 同时,需要确保代码的正确性,比如在中间件中正确处理WebSocket请求,异步方法的使用,以及异常处理。可能还需要对比传统ASP.NET中的实现,比如使用HttpContext.AcceptWebSocketRequest方法。 最后,相关问题可以涉及性能优化、安全认证、跨域处理等,结合用户提供的引用中的内容。</think>### 在 .NET WebAPI使用 WebSocket 的示例及教程 #### 1. WebSocket 基础概念 WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,允许服务端与客户端双向实时通信[^4]。在 .NET WebAPI 中,可通过以下两种方式实现: --- #### 2. ASP.NET Core 实现(推荐) ##### 步骤 1:创建项目并添加依赖 新建 ASP.NET Core WebAPI 项目,确保 `Microsoft.AspNetCore.WebSockets` 包已安装: ```bash dotnet add package Microsoft.AspNetCore.WebSockets ``` ##### 步骤 2:配置 WebSocket 中间件 在 `Program.cs` 中启用 WebSocket 支持: ```csharp var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); // 启用 WebSocket 中间件 app.UseWebSockets(); app.Map("/ws", async context => { if (context.WebSockets.IsWebSocketRequest) { using var ws = await context.WebSockets.AcceptWebSocketAsync(); await HandleWebSocketConnection(ws); } else { context.Response.StatusCode = 400; } }); app.Run(); async Task HandleWebSocketConnection(WebSocket ws) { var buffer = new byte[1024]; while (ws.State == WebSocketState.Open) { var result = await ws.ReceiveAsync(buffer, CancellationToken.None); if (result.MessageType == WebSocketMessageType.Text) { var message = Encoding.UTF8.GetString(buffer, 0, result.Count); // 处理消息并回复 await ws.SendAsync(Encoding.UTF8.GetBytes($"Received: {message}"), WebSocketMessageType.Text, true, CancellationToken.None); } } } ``` ##### 步骤 3:客户端 JavaScript 示例 ```javascript const socket = new WebSocket('ws://localhost:5000/ws'); socket.onmessage = (event) => console.log('Received:', event.data); socket.send('Hello WebSocket!'); ``` --- #### 3. 传统 ASP.NET Framework 实现 ##### 步骤 1:创建 WebAPI 控制器 通过 `HttpListenerContext` 处理 WebSocket 请求: ```csharp public class WebSocketController : ApiController { [HttpGet] public async Task<HttpResponseMessage> Connect() { if (HttpContext.Current.IsWebSocketRequest) { var context = HttpContext.Current.AcceptWebSocketRequest(null); await ProcessWebSocketRequest(context.WebSocket); return new HttpResponseMessage(HttpStatusCode.SwitchingProtocols); } return new HttpResponseMessage(HttpStatusCode.BadRequest); } private async Task ProcessWebSocketRequest(WebSocket ws) { ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024]); while (ws.State == WebSocketState.Open) { var result = await ws.ReceiveAsync(buffer, CancellationToken.None); if (result.MessageType == WebSocketMessageType.Text) { var message = Encoding.UTF8.GetString(buffer.Array, 0, result.Count); await ws.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes($"Echo: {message}")), WebSocketMessageType.Text, true, CancellationToken.None); } } } } ``` ##### 步骤 2:配置路由(WebApiConfig.cs) ```csharp config.Routes.MapHttpRoute( name: "WebSocket", routeTemplate: "api/ws", defaults: new { controller = "WebSocket" } ); ``` --- #### 4. 注意事项 1. **跨域处理**:需在服务端配置 CORS,允许 WebSocket 请求来源[^2]。 2. **心跳机制**:通过定时发送 Ping/Pong 保持连接活性。 3. **异常处理**:捕获 `WebSocketException` 并关闭连接。 4. **性能优化**:使用异步方法避免阻塞线程[^1]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值