创建项目

创建一个空的 Web 项目,并在 Nuget 里面添加 SignalR,jQuery UI 包,添加以后项目里包含了 jQuery,jQuery.UI ,和 SignalR 的脚本。

服务端代码

创建 Stock 类

using System;

namespace SignalRDemo4
{
public class Stock
{
private decimal _price; public string Symbol { get; set; } public decimal Price
{
get
{
return _price;
}
set
{
if (_price == value)
{
return;
} _price = value; if (DayOpen == )
{
DayOpen = _price;
}
}
} public decimal DayOpen { get; private set; } public decimal Change
{
get
{
return Price - DayOpen;
}
} public double PercentChange
{
get
{
return (double)Math.Round(Change / Price, );
}
}
}
}

创建 tockTicker 和 StockTickerHub 类

添加类 StockTicker

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web; namespace SignalRDemo4
{
public class StockTicker
{
// Singleton instance
private readonly static Lazy<StockTicker> _instance = new Lazy<StockTicker>(() => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients)); private readonly ConcurrentDictionary<string, Stock> _stocks = new ConcurrentDictionary<string, Stock>(); private readonly object _updateStockPricesLock = new object(); //stock can go up or down by a percentage of this factor on each change
private readonly double _rangePercent = .; private readonly TimeSpan _updateInterval = TimeSpan.FromMilliseconds();
private readonly Random _updateOrNotRandom = new Random(); private readonly Timer _timer;
private volatile bool _updatingStockPrices = false; private StockTicker(IHubConnectionContext<dynamic> clients)
{
Clients = clients; _stocks.Clear();
var stocks = new List<Stock>
{
new Stock { Symbol = "MSFT", Price = 30.31m },
new Stock { Symbol = "APPL", Price = 578.18m },
new Stock { Symbol = "GOOG", Price = 570.30m }
};
stocks.ForEach(stock => _stocks.TryAdd(stock.Symbol, stock)); _timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval); } public static StockTicker Instance
{
get
{
return _instance.Value;
}
} private IHubConnectionContext<dynamic> Clients
{
get;
set;
} public IEnumerable<Stock> GetAllStocks()
{
return _stocks.Values;
} private void UpdateStockPrices(object state)
{
lock (_updateStockPricesLock)
{
if (!_updatingStockPrices)
{
_updatingStockPrices = true; foreach (var stock in _stocks.Values)
{
if (TryUpdateStockPrice(stock))
{
BroadcastStockPrice(stock);
}
} _updatingStockPrices = false;
}
}
} private bool TryUpdateStockPrice(Stock stock)
{
// Randomly choose whether to update this stock or not
var r = _updateOrNotRandom.NextDouble();
if (r > .)
{
return false;
} // Update the stock price by a random factor of the range percent
var random = new Random((int)Math.Floor(stock.Price));
var percentChange = random.NextDouble() * _rangePercent;
var pos = random.NextDouble() > .;
var change = Math.Round(stock.Price * (decimal)percentChange, );
change = pos ? change : -change; stock.Price += change;
return true;
} private void BroadcastStockPrice(Stock stock)
{
Clients.All.updateStockPrice(stock);
}
}
}

为了线程安全,把 Stock 的数据存储在了 ConcurrentDictionary 里面。

添加 SignalR Hub Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs; namespace SignalRDemo4
{
[HubName("stockTickerMini")]
public class StockTickerHub : Hub
{
private readonly StockTicker _stockTicker; public StockTickerHub() : this(StockTicker.Instance) { } public StockTickerHub(StockTicker stockTicker)
{
_stockTicker = stockTicker;
} public IEnumerable<Stock> GetAllStocks()
{
return _stockTicker.GetAllStocks();
}
}
}

添加 Owin 类,并在里面配置 SignalR

using System;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin; [assembly: OwinStartup(typeof(SignalRDemo4.Startup))] namespace SignalRDemo4
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
app.MapSignalR();
}
}
}

客户端代码

添加名为 StockTicker 的html页面,设置为启动页面,并替换为下面代码。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>ASP.NET SignalR Stock Ticker</title>
<style>
body {
font-family: 'Segoe UI', Arial, Helvetica, sans-serif;
font-size: 16px;
} #stockTable table {
border-collapse: collapse;
} #stockTable table th, #stockTable table td {
padding: 2px 6px;
} #stockTable table td {
text-align: right;
} #stockTable .loading td {
text-align: left;
}
</style>
</head>
<body>
<h1>ASP.NET SignalR Stock Ticker Sample</h1> <h2>Live Stock Table</h2>
<div id="stockTable">
<table border="1">
<thead>
<tr><th>Symbol</th><th>Price</th><th>Open</th><th>Change</th><th>%</th></tr>
</thead>
<tbody>
<tr class="loading"><td colspan="5">loading...</td></tr>
</tbody>
</table>
</div> <!--Script references. -->
<!--Reference the jQuery library. -->
<script src="Scripts/jquery-3.1.1.min.js"></script>
<!--Reference the SignalR library. -->
<script src="Scripts/jquery.signalR-2.2.2.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="/signalr/hubs"></script>
<!--Reference the StockTicker script. -->
<script src="Scripts/StockTicker.js"></script>
</body>
</html>

添加名为 StockTicker 的js文件,并添加下面代码

// A simple templating method for replacing placeholders enclosed in curly braces.
if (!String.prototype.supplant) {
String.prototype.supplant = function (o) {
return this.replace(/{([^{}]*)}/g,
function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
};
} $(function () { var ticker = $.connection.stockTickerMini, // the generated client-side hub proxy
up = '▲',
down = '▼',
$stockTable = $('#stockTable'),
$stockTableBody = $stockTable.find('tbody'),
rowTemplate = '<tr data-symbol="{Symbol}"><td>{Symbol}</td><td>{Price}</td><td>{DayOpen}</td><td>{Direction} {Change}</td><td>{PercentChange}</td></tr>'; function formatStock(stock) {
return $.extend(stock, {
Price: stock.Price.toFixed(2),
PercentChange: (stock.PercentChange * 100).toFixed(2) + '%',
Direction: stock.Change === 0 ? '' : stock.Change >= 0 ? up : down
});
} function init() {
ticker.server.getAllStocks().done(function (stocks) {
$stockTableBody.empty();
$.each(stocks, function () {
var stock = formatStock(this);
$stockTableBody.append(rowTemplate.supplant(stock));
});
});
} // Add a client-side hub method that the server will call
ticker.client.updateStockPrice = function (stock) {
var displayStock = formatStock(stock),
$row = $(rowTemplate.supplant(displayStock)); $stockTableBody.find('tr[data-symbol=' + stock.Symbol + ']')
.replaceWith($row);
} // Start the connection
$.connection.hub.start().done(init); });

然后按F5进行调试,打开多个浏览器,发现里面的数据会同步更新。

源代码链接:

链接: https://pan.baidu.com/s/1pKRIR2r 密码: em9k

参考链接:

https://docs.microsoft.com/zh-cn/aspnet/signalr/overview/getting-started/tutorial-server-broadcast-with-signalr

【SignalR学习系列】4. SignalR广播程序的更多相关文章

  1. 【SignalR学习系列】1. SignalR理论介绍

    什么是SignalR? ASP.NET SignalR 是一个让 ASP.NET开发者可以简单地给自己的程序添加即时通讯功能的开发库.即时通讯功能可以直接从服务器端给在线的客户端发送数据,而不用等待客 ...

  2. 【SignalR学习系列】3. SignalR实时高刷新率程序

    创建项目 创建一个空的 Web 项目,并在 Nuget 里面添加 SignalR,jQuery UI 包,添加以后项目里包含了 jQuery,jQuery.UI ,和 SignalR 的脚本. 创建基 ...

  3. 【SignalR学习系列】5. SignalR WPF程序

    首先创建 WPF Server 端,新建一个 WPF 项目 安装 Nuget 包 替换 MainWindows 的Xaml代码 <Window x:Class="WPFServer.M ...

  4. 【SignalR学习系列】2. 第一个SignalR程序

    新建项目 1.使用VisualStudio 2015 新建一个Web项目 2.选择空模板 3.添加一个新的SignalR Hub Class (v2)类文件,并修改类名为ChatHub 4.修改Cha ...

  5. 【SignalR学习系列】6. SignalR Hubs Api 详解(C# Server 端)

    如何注册 SignalR 中间件 为了让客户端能够连接到 Hub ,当程序启动的时候你需要调用 MapSignalR 方法. 下面代码显示了如何在 OWIN startup 类里面定义 SignalR ...

  6. 【SignalR学习系列】8. SignalR Hubs Api 详解(.Net C# 客户端)

    建立一个 SignalR 连接 var hubConnection = new HubConnection("http://www.contoso.com/"); IHubProx ...

  7. 【SignalR学习系列】7. SignalR Hubs Api 详解(JavaScript 客户端)

    SignalR 的 generated proxy 服务端 public class ContosoChatHub : Hub { public void NewContosoChatMessage( ...

  8. 我的Android 4 学习系列之创建应用程序和Activity:Manifest、Application、Activity

    目录 介绍Android应用程序组件,以及使用这些组件构建的各种Android应用程序 Android应用程序的生命周期 如何创建应用程序Manifest 如何使用外部资源提供对位置.语言和硬件配置的 ...

  9. JavaWeb学习系列——第一个JavaWeb程序

    创建JavaWeb项目 Eclipse中新建一个Dynamic Web Project 指定项目名称.依赖环境 勾选生成web.xml选项 更改项目编译输出目录,项目右键 ->propertie ...

随机推荐

  1. os模块学习小随笔

    os模块为python解释器与操作系统交互的接口 os.popen()   -------Open a pipe to or from command. The return value is an ...

  2. myeclipse导入项目时出现Exploded location overlaps an existing deployment错误解决方法

    版权声明:本文为博主原创文章,转载时请注明原文链接. 今天拿别人的项目,在自己的软件上配置,通过tomcat添加项目时出现了 Exploded location overlaps an existin ...

  3. python 标准库 -- subprocess

    subprocess 主要功能室执行外部的命令和程序 一个进程可 fork 一个子进程, 并让这个子进程 exec 另外一个程序. 在 python 中, 可以通过标准库中的 subprocess 包 ...

  4. VMware安装CentOS 提示:已将该虚拟机配置为使用 64 位客户机操作系统。但是,无法执行 64 位操作。解决方案

    安装虚拟机遇到错误: 在网上查了查资料,发现CPU支持VT技术的就能支持vmware中安装64位虚拟机. 以下是操作步骤: 1)到网上下载一个securable.exe,测试以下机器是否支持VT. l ...

  5. webpack2教程--从入门到放弃

    开车之前,先介绍一些npm的命令: :D 进入D盘 mkdir webapp 创建webapp文件夹 cd webapp 进入webapp文件夹 mkdir webapp && cd ...

  6. Android 设计模式实战之关于封装计费代码库的策略模式详谈

    写在之前 这周生活上出现了很多的不如意,从周一开始就觉得哪里出现了问题,然后就是各种烦躁的情绪,后来事情还真是如预感的那样发生了,很是心痛,但也无可奈何,希望大家都好好珍惜自己身边的人:友人,亲人,家 ...

  7. Linux: Bash基本命令

    切换目录 cd 查看当前目录 pwd 生成目录 mkdir 搜索文件 查看当前的文件 ls 删除文件但保留特定类型 rm !(**) 例如: rm !(.tex|*.eps)其中,.tex, .eps ...

  8. csv导入数据到mysql

    csv表中含有中文字符,具体实现代码示例: load data infile 'C:\\Users\\Administrator\\Desktop\\import\\CELLutf.csv' into ...

  9. Centos使用vsfotd配置fpt服务

    ---恢复内容开始--- vsftp简介 vsftpd 是一个 UNIX 类操作系统上运行的服务器的名字,它可以运行在诸如 Linux, BSD, Solaris, HP-UX 以及 IRIX 上面. ...

  10. Chapter 4. The MPEG-4 and H.264 Standards

    本章节介绍一些关于MPEG-4标准与H.264标准的基本知识 比较重要的是第95页关于两种标准的对比表格.其他部分没有什么特别重要的细节.