Kurz: Serverové vysílání se službou SignalR 2
Upozornění
Tato dokumentace není určená pro nejnovější verzi služby SignalR. Podívejte se na ASP.NET Core SignalR.
V tomto kurzu se dozvíte, jak vytvořit webovou aplikaci, která používá ASP.NET SignalR 2 k zajištění funkce všesměrového vysílání serveru. Serverové vysílání znamená, že server zahájí komunikaci odesílanou klientům.
Aplikace, kterou v tomto kurzu vytvoříte, simuluje burzovní ticker, což je typický scénář pro funkci serverového vysílání. Server pravidelně náhodně aktualizuje ceny akcií a vysílá aktualizace všem připojeným klientům. V prohlížeči se čísla a symboly ve sloupcích Change a % dynamicky mění v reakci na oznámení ze serveru. Pokud otevřete další prohlížeče se stejnou adresou URL, všechny zobrazují stejná data a stejné změny dat současně.
V tomto kurzu jste:
- Vytvoření projektu
- Nastavení kódu serveru
- Prozkoumání kódu serveru
- Nastavení klientského kódu
- Prozkoumání kódu klienta
- Testování aplikace
- Povolit protokolování
Důležité
Pokud nechcete procházet kroky sestavení aplikace, můžete balíček SignalR.Sample nainstalovat do nového projektu Empty ASP.NET Web Application. Pokud nainstalujete balíček NuGet bez provedení kroků v tomto kurzu, musíte postupovat podle pokynů v souborureadme.txt . Ke spuštění balíčku je potřeba přidat spouštěcí třídu OWIN, která volá metodu ConfigureSignalR
v nainstalovaném balíčku. Pokud nepřidáte spouštěcí třídu OWIN, zobrazí se chyba. Projděte si část Instalace ukázky Nástroje StockTicker tohoto článku.
Požadavky
- Sada Visual Studio 2017 se sadou funkcí Vývoj pro ASP.NET a web.
Vytvoření projektu
Tato část ukazuje, jak pomocí sady Visual Studio 2017 vytvořit prázdnou webovou aplikaci ASP.NET.
V sadě Visual Studio vytvořte webovou aplikaci ASP.NET.
V okně New ASP.NET Web Application - SignalR.StockTicker (Nová webová aplikace ASP.NET – SignalR.StockTicker ) ponechte vybranou možnost Empty (Prázdné) a vyberte OK.
Nastavení kódu serveru
V této části nastavíte kód, který běží na serveru.
Vytvoření třídy Stock
Začnete vytvořením třídy modelu Stock , kterou použijete k ukládání a přenosu informací o akciích.
V Průzkumník řešení klikněte pravým tlačítkem na projekt a vyberte Přidat>třídu.
Pojmenujte třídu Stock a přidejte ji do projektu.
Nahraďte kód v souboru Stock.cs tímto kódem:
using System; 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); } } } }
Dvě vlastnosti, které nastavíte při vytváření akcií, jsou
Symbol
(například MSFT pro Microsoft) aPrice
. Další vlastnosti závisí na tom, jak a kdy nastavítePrice
. Při prvním nastaveníPrice
se hodnota rozšíří naDayOpen
. Když pak nastavítePrice
, aplikace vypočítáChange
hodnoty vlastností aPercentChange
na základě rozdílu meziPrice
aDayOpen
.
Vytvoření tříd StockTickerHub a StockTicker
K interakci mezi servery a klienty použijete rozhraní API služby SignalR Hub. Třída StockTickerHub
odvozená z třídy SignalR Hub
bude zpracovávat příjem připojení a volání metod z klientů. Potřebujete také udržovat skladová data a spustit Timer
objekt. Objekt Timer
bude pravidelně spouštět aktualizace cen nezávisle na klientských připojeních. Tyto funkce nemůžete umístit do Hub
třídy, protože centra jsou přechodná. Aplikace vytvoří Hub
instanci třídy pro každý úkol v centru, například připojení a volání z klienta na server. Takže mechanismus, který uchovává data akcií, aktualizuje ceny a vysílá aktualizace cen, musí běžet v samostatné třídě. Třídu pojmenujete StockTicker
.
Chcete, aby na serveru běžela pouze jedna instance StockTicker
třídy, takže budete muset nastavit odkaz z každé StockTickerHub
instance na jednu StockTicker
instanci. Třída StockTicker
musí vysílat klientům, protože obsahuje data akcií a aktivuje aktualizace, ale StockTicker
není Hub
třídou. Třída StockTicker
musí získat odkaz na objekt kontextu připojení centra SignalR. Pak může použít objekt kontextu připojení SignalR k vysílání do klientů.
Vytvoření Souboru StockTickerHub.cs
V Průzkumník řešení klikněte pravým tlačítkem na projekt a vyberte Přidat>novou položku.
V části Přidat novou položku – SignalR.StockTicker vyberte Installed>Visual C#>Web>SignalR a pak vyberte SignalR Hub Class (v2).
Pojmenujte třídu StockTickerHub a přidejte ji do projektu.
Tento krok vytvoří soubor třídy StockTickerHub.cs . Současně do projektu přidá sadu souborů skriptů a odkazů na sestavení, které podporují SignalR.
Nahraďte kód v souboru StockTickerHub.cs tímto kódem:
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(); } } }
Soubor uložte.
Aplikace používá třídu Hub k definování metod, které můžou klienti volat na serveru. Definujete jednu metodu: GetAllStocks()
. Když se klient poprvé připojí k serveru, zavolá tuto metodu, aby získal seznam všech akcií s jejich aktuálními cenami. Metoda může běžet synchronně a vracet IEnumerable<Stock>
se, protože vrací data z paměti.
Pokud by metoda musela získat data provedením něčeho, co by zahrnovalo čekání, jako je vyhledávání v databázi nebo volání webové služby, zadali Task<IEnumerable<Stock>>
byste jako návratovou hodnotu pro povolení asynchronního zpracování. Další informace najdete v tématu Příručka ASP.NET rozhraní API služby SignalR Hubs – Server – Kdy provést asynchronně.
Atribut HubName
určuje, jak bude aplikace odkazovat na centrum v kódu JavaScriptu na klientovi. Výchozí název v klientovi, pokud tento atribut nepoužijete, je verze camelCase názvu třídy, která by v tomto případě byla stockTickerHub
.
Jak uvidíte později při vytváření StockTicker
třídy, aplikace vytvoří jednu instanci této třídy ve své statické Instance
vlastnosti. Tato jediná instance je StockTicker
v paměti bez ohledu na to, kolik klientů se připojí nebo odpojí. Tato instance je to, co GetAllStocks()
metoda používá k vrácení aktuálních informací o akciích.
Vytvoření Souboru StockTicker.cs
V Průzkumník řešení klikněte pravým tlačítkem na projekt a vyberte Přidat>třídu.
Pojmenujte třídu StockTicker a přidejte ji do projektu.
Nahraďte kód v souboru StockTicker.cs tímto kódem:
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 { // 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 = .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<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 > .1) { 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() > .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); } } }
Vzhledem k tomu, že všechna vlákna budou spuštěna stejnou instanci kódu StockTicker, třída StockTicker musí být bezpečná pro přístup z více vláken.
Prozkoumání kódu serveru
Když prozkoumáte kód serveru, pomůže vám to pochopit, jak aplikace funguje.
Uložení instance typu singleton do statického pole
Kód inicializuje statické _instance
pole, které podporuje Instance
vlastnost s instancí třídy . Vzhledem k tomu, že je konstruktor soukromý, je to jediná instance třídy, kterou může aplikace vytvořit. Aplikace pro _instance
pole používá lazy inicializaci. Není to kvůli výkonu. Je potřeba zajistit, aby vytváření instancí bylo bezpečné pro přístup z více vláken.
private readonly static Lazy<StockTicker> _instance = new Lazy<StockTicker>(() => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients));
public static StockTicker Instance
{
get
{
return _instance.Value;
}
}
Pokaždé, když se klient připojí k serveru, nová instance StockTickerHub třídy spuštěné v samostatném vlákně získá instance StockTicker singleton ze StockTicker.Instance
statické vlastnosti, jak jste viděli dříve ve StockTickerHub
třídě .
Ukládání burzovních dat v ConcurrentDictionary
Konstruktor inicializuje kolekci _stocks
s některými ukázkovými burzovními daty a GetAllStocks
vrátí akcie. Jak jste viděli dříve, tuto kolekci akcií vrací StockTickerHub.GetAllStocks
metoda , což je metoda serveru ve Hub
třídě, kterou můžou volat klienti.
private readonly ConcurrentDictionary<string, Stock> _stocks = new ConcurrentDictionary<string, Stock>();
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 IEnumerable<Stock> GetAllStocks()
{
return _stocks.Values;
}
Kolekce akcie je definována jako typ ConcurrentDictionary pro bezpečnost vláken. Jako alternativu můžete použít objekt Dictionary a při provádění změn slovník explicitně uzamknout.
U této ukázkové aplikace je v pořádku ukládat data aplikace do paměti a ztratit je, když aplikace instanci odstraní StockTicker
. Ve skutečné aplikaci byste pracovali s back-endovým úložištěm dat, jako je databáze.
Pravidelně se aktualizují ceny akcií
Konstruktor spustí Timer
objekt, který pravidelně volá metody, které náhodně aktualizují ceny akcií.
_timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval);
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 > .1)
{
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() > .51;
var change = Math.Round(stock.Price * (decimal)percentChange, 2);
change = pos ? change : -change;
stock.Price += change;
return true;
}
Timer
volá UpdateStockPrices
, který předává hodnotu null v parametru state. Před aktualizací cen aplikace zamkne objekt._updateStockPricesLock
Kód zkontroluje, jestli už neaktualizuje ceny jiné vlákno, a pak zavolá TryUpdateStockPrice
na každou akcii v seznamu. Metoda TryUpdateStockPrice
rozhoduje o tom, jestli se má cena akcií změnit a o kolik ji změnit. Pokud se cena akcií změní, aplikace zavolá BroadcastStockPrice
, aby změnu ceny akcií vysílala všem připojeným klientům.
Příznak _updatingStockPrices
označený jako nestálý , aby se zajistilo, že je bezpečný z více vláken.
private volatile bool _updatingStockPrices = false;
Ve skutečné aplikaci by metoda volala webovou službu, TryUpdateStockPrice
aby vyhledala cenu. V tomto kódu aplikace používá generátor náhodných čísel k náhodnému provádění změn.
Získání kontextu SignalR, aby třída StockTicker mohl vysílat klientům
Vzhledem k tomu, že změny cen pocházejí z objektu StockTicker
, je to objekt, který potřebuje volat metodu updateStockPrice
na všech připojených klientech. Hub
Ve třídě máte rozhraní API pro volání klientských metod, ale StockTicker
neodvozuje se z Hub
třídy a nemá odkaz na žádný Hub
objekt. Pokud chcete vysílat do připojených klientů, StockTicker
musí třída získat instanci kontextu SignalR pro StockTickerHub
třídu a použít ji k volání metod na klientech.
Kód získá odkaz na kontext SignalR, když vytvoří instanci singleton třídy, předá tento odkaz konstruktoru a konstruktor ho vloží do Clients
vlastnosti.
Existují dva důvody, proč chcete získat kontext jenom jednou: získání kontextu je nákladný úkol a jeho získání jednou zajistí, že aplikace zachová zamýšlené pořadí zpráv odesílaných klientům.
private readonly static Lazy<StockTicker> _instance =
new Lazy<StockTicker>(() => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients));
private StockTicker(IHubConnectionContext<dynamic> clients)
{
Clients = clients;
// Remainder of constructor ...
}
private IHubConnectionContext<dynamic> Clients
{
get;
set;
}
private void BroadcastStockPrice(Stock stock)
{
Clients.All.updateStockPrice(stock);
}
Clients
Získání vlastnosti kontextu a jeho vložení do StockTickerClient
vlastnosti umožňuje psát kód pro volání metod klienta, které vypadají stejně jako ve Hub
třídě. Pokud chcete například vysílat všechny klienty, můžete napsat Clients.All.updateStockPrice(stock)
.
Metoda updateStockPrice
, kterou voláte BroadcastStockPrice
, ještě neexistuje. Přidáte ho později při psaní kódu, který běží na klientovi. Tady můžete odkazovat, updateStockPrice
protože Clients.All
je dynamický, což znamená, že aplikace vyhodnotí výraz za běhu. Když se toto volání metody spustí, SignalR odešle název metody a hodnotu parametru klientovi a pokud má klient metodu s názvem updateStockPrice
, aplikace zavolá tuto metodu a předá jí hodnotu parametru.
Clients.All
znamená odeslat všem klientům. SignalR nabízí další možnosti, jak určit, kterým klientům nebo skupinám klientů se má odesílat. Další informace najdete v tématu HubConnectionContext.
Registrace trasy SignalR
Server potřebuje vědět, kterou adresu URL má zachytit a směrovat na SignalR. Chcete-li to provést, přidejte spouštěcí třídu OWIN:
V Průzkumník řešení klikněte pravým tlačítkem na projekt a vyberte Přidat>novou položku.
V části Přidat novou položku – SignalR.StockTicker vyberte Installed Visual C#Web ( Nainstalovaný>visual C#>Web ) a pak vyberte OWIN Startup Class (Třída spouštění OWIN).
Pojmenujte třídu Startup a vyberte OK.
Nahraďte výchozí kód v souboru Startup.cs tímto kódem:
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) { // Any connection or hub wire up and configuration should go here app.MapSignalR(); } } }
Dokončili jste nastavení kódu serveru. V další části nastavíte klienta.
Nastavení klientského kódu
V této části nastavíte kód, který běží na klientovi.
Vytvoření stránky HTML a souboru JavaScriptu
Stránka HTML zobrazí data a soubor JavaScriptu data uspořádá.
Vytvořit StockTicker.html
Nejprve přidáte klienta HTML.
V Průzkumník řešení klikněte pravým tlačítkem na projekt a vyberte Přidat>stránku HTML.
Pojmenujte soubor StockTicker a vyberte OK.
Nahraďte výchozí kód v souboru StockTicker.html tímto kódem:
<!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-1.10.2.min.js" ></script> <!--Reference the SignalR library. --> <script src="/Scripts/jquery.signalR-2.1.0.js"></script> <!--Reference the autogenerated SignalR hub script. --> <script src="/signalr/hubs"></script> <!--Reference the StockTicker script. --> <script src="StockTicker.js"></script> </body> </html>
Kód HTML vytvoří tabulku s pěti sloupci, řádkem záhlaví a datovým řádkem s jednou buňkou, která zahrnuje všech pět sloupců. Na řádku dat se zobrazuje "načítání..." v okamžiku, kdy se aplikace spustí. JavaScriptový kód odebere tento řádek a přidá na jeho místo řádky s burzovními daty načtenými ze serveru.
Značky skriptu určují:
Soubor skriptu jQuery.
Soubor základního skriptu SignalR.
Soubor skriptu proxy serverů SignalR.
Soubor skriptu StockTicker, který vytvoříte později.
Aplikace dynamicky generuje soubor skriptu proxy serverů SignalR. Určuje adresu URL /signalr/hubs a definuje metody proxy pro metody ve třídě Hub, v tomto případě pro
StockTickerHub.GetAllStocks
. Pokud chcete, můžete tento javascriptový soubor vygenerovat ručně pomocí nástrojů SignalR. Nezapomeňte při volání metody zakázat dynamické vytvářeníMapHubs
souborů.V Průzkumník řešení rozbalte Položku Skripty.
Knihovny skriptů pro jQuery a SignalR jsou viditelné v projektu.
Důležité
Správce balíčků nainstaluje novější verzi skriptů SignalR.
Aktualizujte odkazy na skripty v bloku kódu tak, aby odpovídaly verzím souborů skriptů v projektu.
V Průzkumník řešení klikněte pravým tlačítkem na StockTicker.htmla pak vyberte Nastavit jako úvodní stránku.
Vytvořit StockTicker.js
Teď vytvořte soubor JavaScriptu.
V Průzkumník řešení klikněte pravým tlačítkem na projekt a vyberte Přidat>soubor JavaScriptu.
Pojmenujte soubor StockTicker a vyberte OK.
Do souboru StockTicker.js přidejte tento kód:
// 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); });
Prozkoumání kódu klienta
Pokud prozkoumáte kód klienta, pomůže vám to zjistit, jak kód klienta komunikuje s kódem serveru, aby aplikace fungovala.
Zahájení připojení
$.connection
odkazuje na proxy služby SignalR. Kód získá odkaz na proxy pro StockTickerHub
třídu a umístí ho do ticker
proměnné. Název proxy serveru je název, který byl nastaven atributem HubName
:
var ticker = $.connection.stockTickerMini
[HubName("stockTickerMini")]
public class StockTickerHub : Hub
Po definování všech proměnných a funkcí inicializuje poslední řádek kódu v souboru připojení SignalR voláním funkce SignalR start
. Funkce start
provede asynchronně a vrátí objekt jQuery Deferred. Můžete volat hotovou funkci a určit funkci, která se má volat, když aplikace dokončí asynchronní akci.
$.connection.hub.start().done(init);
Získání všech akcií
Funkce init
volá getAllStocks
funkci na serveru a použije informace, které server vrátí, k aktualizaci burzovní tabulky. Všimněte si, že ve výchozím nastavení musíte na klientovi použít camelCasing, i když je název metody na serveru s písmeny pascal. Pravidlo camelCasing se vztahuje pouze na metody, ne na objekty. Například odkazujete na stock.Symbol
a stock.Price
, ne stock.symbol
nebo stock.price
.
function init() {
ticker.server.getAllStocks().done(function (stocks) {
$stockTableBody.empty();
$.each(stocks, function () {
var stock = formatStock(this);
$stockTableBody.append(rowTemplate.supplant(stock));
});
});
}
public IEnumerable<Stock> GetAllStocks()
{
return _stockTicker.GetAllStocks();
}
init
V metodě aplikace vytvoří html pro řádek tabulky pro každý skladový objekt přijatý ze serveru voláním formatStock
vlastností formátu objektu stock
a pak voláním supplant
nahradit zástupné symboly v rowTemplate
proměnné hodnotami vlastností objektustock
. Výsledný kód HTML se pak připojí k burzovní tabulce.
Poznámka
Zavoláte init
ho předáním jako callback
funkci, která se spustí po dokončení asynchronní start
funkce. Pokud jste po volání start
volali init
jako samostatný příkaz Jazyka JavaScript , funkce by selhala, protože by se spustila okamžitě, aniž by čekala na dokončení navazování připojení funkcí Start. V takovém případě se funkce pokusí volat getAllStocks
funkci předtím, init
než aplikace naváže připojení k serveru.
Získání aktualizovaných cen akcií
Když server změní cenu akcie, zavolá updateStockPrice
připojené klienty. Aplikace přidá funkci do vlastnosti stockTicker
klienta proxy serveru, aby byla dostupná pro volání ze serveru.
ticker.client.updateStockPrice = function (stock) {
var displayStock = formatStock(stock),
$row = $(rowTemplate.supplant(displayStock));
$stockTableBody.find('tr[data-symbol=' + stock.Symbol + ']')
.replaceWith($row);
}
Funkce updateStockPrice
formátuje akciový objekt přijatý ze serveru do řádku tabulky stejným způsobem jako ve init
funkci. Místo připojení řádku k tabulce najde aktuální řádek akcie v tabulce a nahradí ho novým řádkem.
Testování aplikace
Aplikaci můžete otestovat, abyste měli jistotu, že funguje. Ve všech oknech prohlížeče se zobrazí živá burzovní tabulka s kolísajícími cenami akcií.
Na panelu nástrojů zapněte Ladění skriptů a pak výběrem tlačítka Přehrát spusťte aplikaci v režimu ladění.
Otevře se okno prohlížeče s živou burzovní tabulkou. Burzovní tabulka zpočátku zobrazuje "načítání..." po krátké době aplikace zobrazí počáteční data o akciích a ceny akcií se začnou měnit.
Zkopírujte adresu URL z prohlížeče, otevřete dva další prohlížeče a vložte adresy URL do adresního řádku.
Počáteční zobrazení akcií je stejné jako v prvním prohlížeči a změny probíhají současně.
Zavřete všechny prohlížeče, otevřete nový prohlížeč a přejděte na stejnou adresu URL.
Objekt singleton StockTicker pokračoval v běhu na serveru. Tabulka živých akcií ukazuje, že se akcie stále mění. Nevidíte počáteční tabulku s nulovými údaji o změnách.
Zavřete prohlížeč.
Povolit protokolování
SignalR má integrovanou funkci protokolování, kterou můžete na klientovi povolit, aby vám pomohla při řešení potíží. V této části povolíte protokolování a zobrazíte příklady, které ukazují, jak protokoly říkají, kterou z následujících metod přenosu používá SignalR:
WebSockety podporované službou IIS 8 a aktuálními prohlížeči.
Události odeslané serverem, podporované jinými prohlížeči než Internet Explorer.
Rámeček Forever podporovaný aplikací Internet Explorer.
Dlouhé dotazování Ajax, podporované všemi prohlížeči.
Pro jakékoli připojení zvolí SignalR nejlepší metodu přenosu, kterou podporuje server i klient.
Otevřete StockTicker.js.
Přidejte tento zvýrazněný řádek kódu, který povolí protokolování bezprostředně před kódem, který inicializuje připojení na konci souboru:
// Start the connection $.connection.hub.logging = true; $.connection.hub.start().done(init);
Stisknutím klávesy F5 spusťte projekt.
Otevřete okno vývojářských nástrojů v prohlížeči a výběrem konzoly zobrazte protokoly. Možná budete muset stránku aktualizovat, abyste viděli protokoly služby SignalR, která vyjednává metodu přenosu pro nové připojení.
Pokud používáte Internet Explorer 10 na Windows 8 (IIS 8), metoda přenosu je WebSockets.
Pokud používáte Internet Explorer 10 ve Windows 7 (IIS 7.5), metoda přenosu je iframe.
Pokud používáte Firefox 19 na Windows 8 (IIS 8), metoda přenosu je WebSockets.
Tip
Ve Firefoxu nainstalujte doplněk Firebug a získejte okno konzoly.
Pokud používáte Firefox 19 ve Windows 7 (IIS 7.5), metoda přenosu je události odeslané serverem .
Instalace ukázky StockTicker
Microsoft.AspNet.SignalR.Sample nainstaluje aplikaci StockTicker. Balíček NuGet obsahuje více funkcí než zjednodušená verze, kterou jste vytvořili od začátku. V této části kurzu nainstalujete balíček NuGet a zkontrolujete nové funkce a kód, který je implementuje.
Důležité
Pokud nainstalujete balíček bez provedení předchozích kroků tohoto kurzu, musíte do projektu přidat spouštěcí třídu OWIN. Tento readme.txt soubor pro balíček NuGet vysvětluje tento krok.
Instalace balíčku NuGet SignalR.Sample
V Průzkumník řešení klikněte pravým tlačítkem na projekt a vyberte Spravovat balíčky NuGet.
Ve správci balíčků NuGet: SignalR.StockTicker vyberte Procházet.
V části Zdroj balíčku vyberte nuget.org.
Do vyhledávacího pole zadejte SignalR.Sample a vyberte Microsoft.AspNet.SignalR.Sample>Install.
V Průzkumník řešení rozbalte složku SignalR.Sample.
Instalace balíčku SignalR.Sample vytvořila složku a její obsah.
Ve složce SignalR.Sample klikněte pravým tlačítkem na StockTicker.htmla pak vyberte Nastavit jako úvodní stránku.
Poznámka
Instalace balíčku NuGet SignalR.Sample může změnit verzi jQuery, kterou máte ve složce Scripts . Nový souborStockTicker.html , který balíček nainstaluje do složky SignalR.Sample , bude synchronizovaný s verzí jQuery, kterou balíček nainstaluje, ale pokud chcete původní StockTicker.html soubor spustit znovu, možná budete muset nejprve aktualizovat odkaz jQuery ve značce script.
Spuštění aplikace
Tabulka, kterou jste viděli v první aplikaci, měla užitečné funkce. Úplná aplikace burzovních akcií zobrazuje nové funkce: vodorovně posouvací okno, které zobrazuje data akcií a akcie, které mění barvu, když rostou a klesají.
Stisknutím klávesy F5 aplikaci spusťte.
Při prvním spuštění aplikace se "trh" zavře a zobrazí se statická tabulka a okno s tickerem, které se neposouvá.
Vyberte Otevřít trh.
Pole Live Stock Ticker se začne vodorovně posouvat a server začne pravidelně náhodně vysílat změny cen akcií.
Pokaždé, když se změní cena akcií, aplikace aktualizuje tabulku live stock i live stock ticker.
Pokud je změna ceny akcie kladná, aplikace zobrazí akcii se zeleným pozadím.
Pokud je změna záporná, aplikace zobrazí akcie s červeným pozadím.
Vyberte Zavřít trh.
Tabulka se aktualizuje.
Ticker přestane posouvat.
Vyberte Resetovat.
Všechna data akcií se resetuje.
Aplikace obnoví počáteční stav před zahájením změn cen.
Zkopírujte adresu URL z prohlížeče, otevřete dva další prohlížeče a vložte adresy URL do adresního řádku.
V každém prohlížeči uvidíte stejná dynamicky aktualizovaná data současně.
Když vyberete některý z ovládacích prvků, všechny prohlížeče budou reagovat stejným způsobem ve stejnou dobu.
Zobrazení live stock tickeru
Zobrazení live stock tickeru je neuspořádaný seznam v elementu <div>
formátovaného do jednoho řádku podle stylů CSS. Aplikace inicializuje a aktualizuje ticker stejným způsobem jako tabulka: nahrazením zástupných symbolů v <li>
řetězci šablony a dynamickým přidáním <li>
prvků do elementu <ul>
. Aplikace zahrnuje posouvání pomocí funkce jQuery animate
, která mění levý okraj neuspořádaného seznamu v rámci <div>
.
StockTicker.html SignalR.Sample
Kód HTML burzovního kódu:
<h2>Live Stock Ticker</h2>
<div id="stockTicker">
<div class="inner">
<ul>
<li class="loading">loading...</li>
</ul>
</div>
</div>
SignalR.Sample StockTicker.css
Kód CSS burzovního tickeru:
#stockTicker {
overflow: hidden;
width: 450px;
height: 24px;
border: 1px solid #999;
}
#stockTicker .inner {
width: 9999px;
}
#stockTicker ul {
display: inline-block;
list-style-type: none;
margin: 0;
padding: 0;
}
#stockTicker li {
display: inline-block;
margin-right: 8px;
}
/*<li data-symbol="{Symbol}"><span class="symbol">{Symbol}</span><span class="price">{Price}</span><span class="change">{PercentChange}</span></li>*/
#stockTicker .symbol {
font-weight: bold;
}
#stockTicker .change {
font-style: italic;
}
SignalR.StockTicker.js SignalR.Sample
Kód jQuery, který ho posouvá:
function scrollTicker() {
var w = $stockTickerUl.width();
$stockTickerUl.css({ marginLeft: w });
$stockTickerUl.animate({ marginLeft: -w }, 15000, 'linear', scrollTicker);
}
Další metody na serveru, které může klient volat
Pro zvýšení flexibility aplikace existují další metody, které může aplikace volat.
SignalR.Sample StockTickerHub.cs
Třída StockTickerHub
definuje čtyři další metody, které může klient volat:
public string GetMarketState()
{
return _stockTicker.MarketState.ToString();
}
public void OpenMarket()
{
_stockTicker.OpenMarket();
}
public void CloseMarket()
{
_stockTicker.CloseMarket();
}
public void Reset()
{
_stockTicker.Reset();
}
Aplikace volá OpenMarket
, CloseMarket
a Reset
v reakci na tlačítka v horní části stránky. Demonstrují vzor jednoho klienta, který aktivuje změnu stavu okamžitě šířenou do všech klientů. Každá z těchto metod volá metodu StockTicker
ve třídě, která způsobuje změnu stavu trhu, a pak vysílá nový stav.
SignalR.Sample StockTicker.cs
StockTicker
Ve třídě aplikace udržuje stav trhu s MarketState
vlastností, která vrací hodnotu výčtuMarketState
:
public MarketState MarketState
{
get { return _marketState; }
private set { _marketState = value; }
}
public enum MarketState
{
Closed,
Open
}
Každá z metod, které mění stav trhu, to dělá uvnitř blok zámku, protože StockTicker
třída musí být bezpečná pro přístup z více vláken:
public void OpenMarket()
{
lock (_marketStateLock)
{
if (MarketState != MarketState.Open)
{
_timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval);
MarketState = MarketState.Open;
BroadcastMarketStateChange(MarketState.Open);
}
}
}
public void CloseMarket()
{
lock (_marketStateLock)
{
if (MarketState == MarketState.Open)
{
if (_timer != null)
{
_timer.Dispose();
}
MarketState = MarketState.Closed;
BroadcastMarketStateChange(MarketState.Closed);
}
}
}
public void Reset()
{
lock (_marketStateLock)
{
if (MarketState != MarketState.Closed)
{
throw new InvalidOperationException("Market must be closed before it can be reset.");
}
LoadDefaultStocks();
BroadcastMarketReset();
}
}
Abyste měli jistotu_marketState
, že je tento kód bezpečný pro přístup z více vláken, pole, které vrací MarketState
vlastnost určenou :volatile
private volatile MarketState _marketState;
Metody BroadcastMarketStateChange
a BroadcastMarketReset
se podobají metodě BroadcastStockPrice, kterou jste už viděli, s tím rozdílem, že volají různé metody definované v klientovi:
private void BroadcastMarketStateChange(MarketState marketState)
{
switch (marketState)
{
case MarketState.Open:
Clients.All.marketOpened();
break;
case MarketState.Closed:
Clients.All.marketClosed();
break;
default:
break;
}
}
private void BroadcastMarketReset()
{
Clients.All.marketReset();
}
Další funkce v klientovi, které může server volat
Funkce updateStockPrice
teď zpracovává tabulku i zobrazení tickeru a používá jQuery.Color
k blikající červené a zelené barvě.
Nové funkce v SignalR.StockTicker.js tlačítka povolit a zakázat na základě stavu trhu. Zastaví nebo spustí vodorovné posouvání live stock tickeru . Vzhledem k tomu, že se do ticker.client
aplikace přidává mnoho funkcí, aplikace k jejich přidání používá funkci rozšíření jQuery .
$.extend(ticker.client, {
updateStockPrice: function (stock) {
var displayStock = formatStock(stock),
$row = $(rowTemplate.supplant(displayStock)),
$li = $(liTemplate.supplant(displayStock)),
bg = stock.LastChange === 0
? '255,216,0' // yellow
: stock.LastChange > 0
? '154,240,117' // green
: '255,148,148'; // red
$stockTableBody.find('tr[data-symbol=' + stock.Symbol + ']')
.replaceWith($row);
$stockTickerUl.find('li[data-symbol=' + stock.Symbol + ']')
.replaceWith($li);
$row.flash(bg, 1000);
$li.flash(bg, 1000);
},
marketOpened: function () {
$("#open").prop("disabled", true);
$("#close").prop("disabled", false);
$("#reset").prop("disabled", true);
scrollTicker();
},
marketClosed: function () {
$("#open").prop("disabled", false);
$("#close").prop("disabled", true);
$("#reset").prop("disabled", false);
stopTicker();
},
marketReset: function () {
return init();
}
});
Další nastavení klienta po navázání připojení
Jakmile klient naváže připojení, bude muset provést další práci:
Zjistěte, jestli je trh otevřený nebo uzavřený kvůli volání příslušné
marketOpened
funkce nebomarketClosed
funkce.Připojte volání metody serveru k tlačítkům.
$.connection.hub.start()
.pipe(init)
.pipe(function () {
return ticker.server.getMarketState();
})
.done(function (state) {
if (state === 'Open') {
ticker.client.marketOpened();
} else {
ticker.client.marketClosed();
}
// Wire up the buttons
$("#open").click(function () {
ticker.server.openMarket();
});
$("#close").click(function () {
ticker.server.closeMarket();
});
$("#reset").click(function () {
ticker.server.reset();
});
});
Metody serveru nejsou připojeny k tlačítkům, dokud aplikace nenaváže připojení. Je to proto, aby kód nemohl volat serverové metody, dokud nebudou k dispozici.
Další materiály
V tomto kurzu jste se naučili naprogramovat aplikaci SignalR, která vysílá zprávy ze serveru všem připojeným klientům. Teď můžete zprávy vysílat pravidelně a v reakci na oznámení od libovolného klienta. Koncept singletonové instance s více vlákny můžete použít k udržování stavu serveru ve scénářích online her s více hráči. Příklad: Podívejte se na hru ShootR založenou na SignalR.
Kurzy, které ukazují scénáře komunikace mezi dvěma účastníky, najdete v tématech Začínáme se službou SignalR a Aktualizace v reálném čase pomocí SignalR.
Další informace o službě SignalR najdete v následujících zdrojích informací:
Další kroky
V tomto kurzu jste:
- Vytvořil se projekt.
- Nastavení kódu serveru
- Prozkoumání kódu serveru
- Nastavení klientského kódu
- Prověřil kód klienta.
- Otestování aplikace
- Povolené protokolování
V dalším článku se dozvíte, jak vytvořit webovou aplikaci v reálném čase, která používá ASP.NET SignalR 2.