创建项目

创建一个空的 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. CSS 简单了解(二)

    我们第一天说了简单的HTML,第二天说了简单的CSS.那么今天.咱们就来说一说他们的结合如何使用吧! 首先说引用方式,和使用方法吧! 1.内部样式表.(放入<head>中) <hea ...

  2. 从deque到std::stack,std::queue,再到iOS 中NSArray(CFArray)

    从deque到std::stack,std::queue,再到iOS 中NSArray(CFArray) deque deque双端队列,分段连续空间数据结构,由中控的map(与其说map,不如说是数 ...

  3. 动态分配数组(new)和用随机数赋值(rand)

    #include <iostream>#include <ctime>#include <cstdlib>using namespace std; int main ...

  4. java源码学习(二)Integer

    Integer类包含了一个原始基本类型int.Integer属性中就一个属性,它的类型就是int. 此外,这个类还提供了几个把int转成String和把String转成int的方法,同样也提供了其它跟 ...

  5. Redis中的数据对象

    redis对象 redis中有五种常用对象 我们所说的对象的类型大多是值的类型,键的类型大多是字符串对象,值得类型大概有以下几种,但是无论哪种都是基于redisObject实现的 redisObjec ...

  6. C# 短信发送 邮件发送

    兴趣是最好的老师. --爱因斯坦 一.实现短信发送 1.使用短信mao的方式进行短信发送,前提要购买硬件设备,这里就不考虑展示了: 2.使用中国网建提供的短信平台,但是用几次后要收费: 我们这里主要介 ...

  7. select onchagnge 弹出自己的文本值

    select onchagnge 弹出自己的文本值onchange='alert($("option:selected",this).text())'

  8. 持续集成篇 --Hudson持续集成服务器的安装配置与使用

    样例项目参考视频教程:http://www.roncoo.com/course/view/85d6008fe77c4199b0cdd2885eaeee53 IP:192.168.4.221  8G内存 ...

  9. Swift自增和自增运算

    自增和自增运算 和 C 语言一样,Swift 也提供了方便对变量本身加1或减1的自增(++)和自减(--)的运算符.其操作对象可以是整形和浮点型. ‌ var i = ++i // 现在 i = 1 ...

  10. GC机制总结

    一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般 ...