之前在写MES系统看板部分的web api的时候,都是通过Ajax在规定时间内轮询调用web api,这样简单省事,但是当看板多了(并发量上来)以后,比较消耗服务器的性能,所以最近研究了websocket,希望使用websocket只在数据发生变化时向客户端推送数据。
1、控制器
public class UserController : ApiController
{
[HttpGet]
[Route("info")]
public HttpResponseMessage GetConnect()
{
//在服务器端接受WebSocket请求
HttpContext.Current.AcceptWebSocketRequest(WebsocketHelper.ProcessRequest);
//Response.
return Request.CreateResponse(HttpStatusCode.SwitchingProtocols);
}
}
2、Websocket类
public static class WebsocketHelper
{
/// <summary>
/// 记录客户端连接
/// </summary>
private static Dictionary<string, WebSocket> webSockets=new Dictionary<string, WebSocket>();
/// <summary>
/// 接受信息
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async static Task ProcessRequest(AspNetWebSocketContext context)
{
try
{
//获取路由
string route = context.RawUrl;
if (route.Contains("?"))
{
route = route.Split('?')[0];
}
string key = context.UserHostAddress + route;
//传入的context中有当前的websocket对象
var socket = context.WebSocket;
//此处将web socket对象加入一个静态字典中.
if (!webSockets.ContainsKey(key))
{
//将IP地址和路由设置为hashTable的key值,若hashTable中存在该IP地址则不再添加
webSockets.Add(key, socket);
}
//进入一个无限循环,当websocket close时循环结束
while (true)
{
//关闭连接
var buffer = new ArraySegment<byte>(new byte[1024]);
//对web socket进行异步接收数据
var receivedResult = await socket.ReceiveAsync(buffer, CancellationToken.None);
if (receivedResult.MessageType == WebSocketMessageType.Close)
{
//如果client发起close请求,对client进行ack
await socket.CloseAsync(WebSocketCloseStatus.Empty, string.Empty, CancellationToken.None);
webSockets.Remove(key);
break;
}
}
}
catch (Exception ex)
{
}
}
/// <summary>
/// 将数据发送给所有已连接的客户端
/// </summary>
/// <param name="data"></param>
/// <param name="route">接口路由</param>
public static void SendAll(string data, string route)
{
var recvBytes = Encoding.UTF8.GetBytes(data);
var sendBuffer = new ArraySegment<byte>(recvBytes);
if (webSockets.Any())
{
var webs = webSockets.Where(w => w.Key.Contains(route)).ToList();
if (webs != null)
{
foreach (var item in webs)
{
item.Value.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
}
}
}
}
3、定时获取数据并判断数据是否变化
public class DataTimer
{
/// <summary>
/// 定时获取数据库数据并赋值给Data类
/// </summary>
public void ChangeData()
{
//用定时器设置多长时间,客户端首次连接就会有相应的延迟时间
DBData dBDataTimer = new DBData();
Timer timer = new Timer();
timer.Interval = 3000;
timer.AutoReset = true;
timer.Enabled = true;
timer.Elapsed += delegate
{
string data = GetData();
if (data != dBDataTimer.Data)
{
WebsocketHelper.SendAll(data, "info");
dBDataTimer.Data = data;
}
};
timer.Start();
}
/// <summary>
/// 获取数据库数据
/// </summary>
/// <returns></returns>
public string GetData()
{
List<Inform> inform_list = new List<Inform>();
DataTable inform_dt = SqlHelper.ExecuteTable("select * from inform where state='true'");
for (int i = 0; i < inform_dt.Rows.Count; i++)
{
Inform data = new Inform();
data.Id = inform_dt.Rows[i].Field<Int32>("id");
data.Name = inform_dt.Rows[i].Field<string>("name");
data.State = inform_dt.Rows[i].Field<bool>("state");
inform_list.Add(data);
}
string ret = JsonConvert.SerializeObject(new { type = "info", data = inform_list });
return ret;
}
private class Inform
{
public int Id { get; set; }
public string Name { get; set; }
public bool State { get; set; }
}
}
public class DBData
{
public string Data { get; set; }
}
4、在Global.asax中调用定时获取数据的方法
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
new DataTimer().ChangeData();
}
}
以上就是websocket在asp.net web api中的用法,本人入行不久,不足之处敬请谅解,谢谢!!!