ASP.NET和SignalR簡單實現股票行情實時展示和價格變動推送
ASP.NET C# SignalR 簡單實現股票行情實時展示和價格變動推送
本文將從SignalR的簡介、專案新建和實現入手,簡單演示SignalR功能的一部分。
效果見第11步,demo見附件。
1、開發環境
- Visual Studio 2013
- .Net Framework 4.5
- SignalR-2.0.0
2、SignalR簡介
ASP.NET SignalR 是為 ASP.NET 開發人員提供的一個庫,可以簡化開發人員將實時 Web 功能新增到應用程式的過程。實時 Web 功能是指這樣一種功能:當所連線的客戶端變得可用時伺服器程式碼可以立即向其推送內容,而不是讓伺服器等待客戶端請求新的資料。
ASP .NET SignalR 是一個ASP .NET 下的類庫,可以在ASP .NET 的Web專案中實現實時通訊。什麼是實時通訊的Web呢?就是讓客戶端(Web頁面)和伺服器端可以互相通知訊息及呼叫方法,當然這是實時操作的。
WebSockets是HTML5提供的新的API,可以在Web網頁與伺服器端間建立Socket連線,當WebSockets可用時(即瀏覽器支援Html5)SignalR使用WebSockets,當不支援時SignalR將使用其它技術來保證達到相同效果。
SignalR當然也提供了非常簡單易用的高階API,使伺服器端可以單個或批量呼叫客戶端上的JavaScript函式,並且非常 方便地進行連線管理,例如客戶端連線到伺服器端,或斷開連線,客戶端分組,以及客戶端授權,使用SignalR都非常 容易實現。
SignalR 將與客戶端進行實時通訊帶給了ASP .NET 。當然這樣既好用,而且也有足夠的擴充套件性。以前使用者需要重新整理頁面或使用Ajax輪詢才能實現的實時顯示資料,現在只要使用SignalR,就可以簡單實現了。
3、建立專案
4、建立stock.cs類,用於股票資訊實體類
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace SignalR.StockTicker { 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 == 0) { 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, 4); } } } }stock.cs實體類中的兩個屬性,用於儲存股票名稱程式碼,股票價格,其他剩餘屬性用於決定如何和何時來設定價格欄位,會根據dayopen之間的差異計算各個屬性值的變化。
5、使用SignaR集線器的API來處理伺服器到客戶端的互動。一個stocktickerhub類派生類將處理signalr接收到的client連線和呼叫方法。專案中還需要維護股票資料,並執行一個計時器物件,以週期性地觸發價格更新,這個計時器獨立於客戶端連線。而且也不能把這些函式放在一個集線器類中,因為集線器例項是暫時的。一個集線器類例項是在集線器上的每個操作建立的,比如客戶端到伺服器的連線和呼叫。這樣的機制,使股票價格資料、更新,和server推送到client的價格更新已經執行在一個單獨的類,就是stockticker。
6、右鍵專案新增SignalR Hub Class (v2)模板類 StockTickerHub.cs,
using System.Collections.Generic; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Hubs; namespace SignalR.StockTicker { [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(); } } }7、建立一個新的StockTicker.cs類,用於判斷如何,何時進行股票價格的變動處理
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Hubs; namespace SignalR.StockTicker { public class StockTicker { // 單一例項物件 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(); // 股票可以按比例上升或下降的百分比 private readonly double _rangePercent = .002; private readonly TimeSpan _updateInterval = TimeSpan.FromMilliseconds(250); private readonly Random _updateOrNotRandom = new Random(); private readonly Timer _timer; private volatile bool _updatingStockPrices = false; private StockTicker(IHubConnectionContext clients) { Clients = clients; _stocks.Clear(); var stocks = new List<Stock> { new Stock { Symbol = "微軟", Price = 30.31m }, new Stock { Symbol = "蘋果", Price = 578.18m }, new Stock { Symbol = "谷歌", 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 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) { // 判斷是否進行報價更新 var r = _updateOrNotRandom.NextDouble(); if (r > .1) { return false; } // 注:這裡應該是進行資料庫實時資料讀取 // 暫時使用random隨機數值來演示股票行情報價的變動 var random = new Random((int)Math.Floor(stock.Price)); var percentChange = random.NextDouble() * _rangePercent; var pos = random.NextDouble() > .51; var change = Math.Round(stock.Price * (decimal)percentChange, 2); change = pos ? change : -change; stock.Price += change; return true; } private void BroadcastStockPrice(Stock stock) { Clients.All.updateStockPrice(stock); } } }8、右鍵專案新增啟動檔案Startup.cs,用於處理入口處理
using System; using System.Threading.Tasks; using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(SignalR.StockTicker.Startup))] namespace SignalR.StockTicker { public class Startup { public void Configuration(IAppBuilder app) { //任何一個client連線或集線器連線和配置都會先進這裡 app.MapSignalR(); } } }9、上面8步已經基本將server端處理好,下面處理client頁面端,建立一個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 股票行情實時顯示demo</h1> <div id="stockTable"> <table border="1"> <thead> <tr><th>股票名稱</th><th>開盤價格</th><th>當前價格</th><th>漲跌值</th><th>漲跌幅(%)</th></tr> </thead> <tbody> <tr class="loading"><td colspan="5">載入中...</td></tr> </tbody> </table> </div> <script src="Scripts/jquery-1.10.2.min.js"></script> <script src="Scripts/jquery.signalR-2.0.0.js"></script> <script src="/signalr/hubs"></script> <script src="Scripts/StockTicker.js"></script> </body> </html>
注意:上面的html程式碼中我用的我本地script指令碼,自行處理。
10、建立通訊指令碼StockTicker.js
// 簡單替換方法 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, //StockTickerHub類,[HubName("stockTickerMini")] 屬性值 up = '▲', down = '▼', $stockTable = $('#stockTable'), $stockTableBody = $stockTable.find('tbody'), rowTemplate = '<tr data-symbol="{Symbol}"><td>{Symbol}</td><td>{DayOpen}</td><td>{Price}</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)); }); }); } // 客戶端集線器方法,股票價格變動的時候伺服器將呼叫 ticker.client.updateStockPrice = function (stock) { var displayStock = formatStock(stock), $row = $(rowTemplate.supplant(displayStock)); $stockTableBody.find('tr[data-symbol=' + stock.Symbol + ']') .replaceWith($row); } // 開始client和server連線 $.connection.hub.start().done(init); });
- var ticker = $.connection.stockTickerMini; 這是指定signalr連線代理,引用StockTickerHub.cs類中的 [HubName("stockTickerMini")]
- $.connection.hub.start().done(init); 啟動signalr,開始執行並返回推送的訊息對象,這裡的call和response都是函式非同步呼叫的。
- function init() 此方法用於初始化顯示的表格,這裡全都是用的 camel 命名規則,如 getAllStocks()
- ticker.client.updateStockPrice 用於執行股票價格變動的更新操作
由請喊我大龍哥最後編輯於:3年前
內容均為作者獨立觀點,不代表八零IT人立場,如涉及侵權,請及時告知。
相關文章
- ASP.NET Core的實時庫: SignalR簡介及使用ASP.NETSignalR
- vue +signalR+log4net 實時日誌推送VueSignalR
- Redux 原理和簡單實現Redux
- 【SignalR全套系列】之在.Net Core 中實現SignalR實時通訊SignalR
- kafka和websocket實時資料推送KafkaWeb
- 簡單介紹ASP.NET Core實現檔案上傳和下載ASP.NET
- ASP.NET Core+Vue3 實現SignalR通訊ASP.NETVueSignalR
- 智慧家居簡單實現---使用ESP8266簡單實現和APP通訊APP
- ASP.NET Core的實時庫: SignalR -- 預備知識ASP.NETSignalR
- (十)如果實現滑動展示選單效果
- 使用Netty和動態代理實現一個簡單的RPCNettyRPC
- JS簡單實現防抖和節流JS
- 如何實現定時推送?
- 【ASP.NET Core】使用SignalR推送伺服器日誌ASP.NETSignalR伺服器
- 用setTimeout和clearTimeout簡單實現setInterval與clearInterval
- Steam 推出全新實時和周度榜單,展示最熱銷和最熱玩遊戲遊戲
- Web SSH 的原理與在 ASP.NET Core SignalR 中的實現WebASP.NETSignalR
- 利用WebSocket和EventSource實現服務端推送Web服務端
- 基於 HTML5 實現的簡單雲動畫和景物描述HTML動畫
- Stockfolio for Mac 股票行情實時檢視工具Mac
- Stockfolio for Mac(股票行情實時檢視工具)Mac
- React 教程第十一篇 —— Redux 簡介和簡單實現ReactRedux
- 使用 python 實現簡單的共享鎖和排他鎖Python
- 使用canvas實現簡單動畫Canvas動畫
- PHP與反ajax推送,實現的訊息實時推送功能PHP
- Signalr自託管最簡實踐SignalR
- 一個簡單API,一鍵實現多通道訊息推送API
- vue+koa2即時聊天,實時推送比特幣價格,爬取電影網站Vue比特幣網站
- SignalR簡版web聊天室(實現過程分析篇)SignalRWeb
- 使用 Docker 和 Nginx 實現簡單目錄索引服務DockerNginx索引
- TCP和UDP實現簡單一對一通訊TCPUDP
- 簡單的list介面和edit介面使用java swing實現Java
- DIY Matter Bridge 和智慧鎖簡單聯動的實踐
- vue實現登入和個人資訊元件展示Vue元件
- 用ListView簡單實現滑動列表View
- 實現去中心化,安全精準和實時喂價的行業願景中心化行業
- 延時 (遲) 操作的 PHP 簡單實現PHP
- Grafana新手教程-實現儀表盤建立和告警推送Grafana