上次我们用websocket做了一个后端实时传输数据的例子websocket 传输实时数据到前端,并用 Echart 动态展示数据,这次我打算换成SignalR来做数据传输试试。
SignalR 这个机制让后端可以主动调用前端的方法,在实际开发中解决了很多问题。比如说数据库进行了更新,但是前端并不知道,并不能实时反应出数据库的实时数据。这时候在后端更新数据库的逻辑中加入调用前端获取数据的方法,这时前端变受到后端的驱动进行数据更新,从而只要数据库有变化前端就会实时更新。
首先我们在服务器端的console项目中来建立一个hub,里边可以定义前端的方法供后端调用,也可定义后端的方法供前端调用:
public class DataHub : Hub
{
public DataHub()
{
Program.dataHub = this;
}
public void Push(string data)
{
Clients.All.Push(data);
}
public void SetCmd(string cmd)
{
Program.Cmd = cmd;
}
public override Task OnConnected()
{
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
return base.OnDisconnected(stopCalled);
}
}
Push方法为后端调用前端的方法,若后端执行push方法,则让所有与此hub相连接的的前端都执行自己的Push方法。SetCmd是后端的方法,它设定后端的Cmdproperty的值,所以一旦前端调用此方法可以改变后端Cmd的值。
之后我们要将hub部署到本地,做一些基本的配置:
using Microsoft.AspNet.SignalR;
using Microsoft.Owin.Cors;
using Owin;
namespace signalr
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR(new HubConfiguration() { EnableJSONP = true });
}
}
}
先解决跨域问题,再之后部署signalR。
static void Main(string[] args){
WebApp.Start<Startup>("http://localhost:8000");
}
那么这样一来signalr的hub就配置好了。我打算后端不停的去推送一些实时的随机数据,让前端以echart图表的方式展现出来。并当前端喊停时停止推送,具体代码如下:
using Microsoft.Owin.Hosting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading;
namespace signalr
{
public class Program
{
public static DataHub dataHub { get; set; }
public static string Cmd { get; set; }
private static string ConvertObjectToString(Data obj)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
MemoryStream memoryStream = new MemoryStream();
serializer.WriteObject(memoryStream, obj);
string json = Encoding.Default.GetString(memoryStream.ToArray());
return json;
}
static void Main(string[] args)
{
WebApp.Start<Startup>("http://localhost:8000");
while(true)
{
if (Cmd == "ACD")
{
while (Cmd == "ACD")
{
Thread.Sleep(300);
Data a = new Data()
{
x = new List<int>(),
y = new List<int>()
};
Random r = new Random();
for (int i = 1; i < 100; i++)
{
a.x.Add(i);
a.y.Add(r.Next(1, 100));
}
dataHub.Push(ConvertObjectToString(a));
}
}
else if (Cmd == "STOP")
{
Cmd = string.Empty;
}
}
}
}
}
至此后端代码就完成了,接下来就是前端,首先前端代码需要引用echart,jquery,signalr以及后端给前端的咱们自定义的hub代码,这样前后端才能都知道互相暴露出的方法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="./echarts.js"></script>
<script src="./jquery-1.6.4.min.js"></script>
<script src="./jquery.signalR-2.4.3.min.js"></script>
<script src="http://localhost:8000/signalr/hubs"></script>
<script src="./main.js" defer></script>
<title>signalR data</title>
</head>
<body>
<div id="main-chart" style="width: 600px;height:400px;"></div>
<button class="btn_close">close</button>
</body>
</html>
值得注意的时jquery的版本不能低于1.6哦,不然执行不了signalR。我将jquery.signalR-2.4.3.min.js上传了,大家可以来这里免费下载
前端的JS代码也是非常的简单,初始化echart,连接到hub,初始化Push方法,并调用后端setCmd方法改变Cmd来让后端开始push实时数据。点击按钮时将Cmd设置为“STOP” 后端便停止推送:
let myChart = echarts.init(document.getElementById('main-chart'));
let option = {
title: {
text: 'ECharts real time chart!!!'
},
tooltip: {},
legend: {
data: ['y']
},
xAxis: {
data: []
},
yAxis: {},
series: [
{
name: 'y',
type: 'bar',
data: []
}
]
};
let btn = document.getElementsByClassName('btn_close');
let hub = $.connection.dataHub;
//连接到dataHub上
$.connection.hub.url = "http://localhost:8000/signalr";
//设置前端的Push方法
hub.client.Push = function(data)
{
let jsonData = JSON.parse(data);
option.xAxis.data = jsonData.x;
option.series[0].data = jsonData.y;
myChart.setOption(option);
}
//一旦连接到dataHub后就调用后端setCmd方法,从而让后端开始推送数据
$.connection.hub.start().done(function () {
hub.server.setCmd("ACD");
});
//停止按钮:设置Cmd为STOP来停止推送
btn[0].addEventListener("click",function(){hub.server.setCmd("STOP");});