Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Upozornění
Tato dokumentace není určená pro nejnovější verzi služby SignalR. Podívejte se na ASP.NET Core SignalR.
Tento dokument obsahuje úvod do programování na straně serveru ASP.NET signalr hubs API pro SignalR verze 2, přičemž ukázky kódu demonstrují běžné možnosti.
Rozhraní API služby SignalR Hubs umožňuje vzdáleně volat proceduru (RPC) ze serveru do připojených klientů a z klientů na server. V kódu serveru definujete metody, které mohou být voláni klienty, a voláte metody, které běží na klientovi. V klientském kódu definujete metody, které lze volat ze serveru, a voláte metody, které běží na serveru. SignalR se postará o veškeré instalace klient-server za vás.
SignalR také nabízí rozhraní API nižší úrovně označované jako trvalá připojení. Úvod do SignalR, center a trvalých připojení najdete v tématu Úvod do SignalR 2.
Verze softwaru použité v tomto tématu
- Visual Studio 2013
- .NET 4.5
- SignalR verze 2
Verze témat
Informace o starších verzích služby SignalR najdete v tématu Starší verze služby SignalR.
Dotazy a komentáře
V komentářích v dolní části stránky nám napište, jak se vám tento kurz líbil a co bychom mohli zlepšit. Pokud máte dotazy, které nesouvisejí přímo s kurzem, můžete je publikovat na fóru ASP.NET SignalR nebo StackOverflow.com.
Přehled
Tento dokument obsahuje následující části:
Jak definovat metody ve třídě Hub, které můžou volat klienti
Jak volat klientské metody a spravovat skupiny mimo třídu Hub
Dokumentaci k programování klientů najdete v následujících zdrojích informací:
- Příručka k rozhraní API služby SignalR Hubs – javascriptový klient
- Příručka k rozhraní API služby SignalR Hubs – klient .NET
Součásti serveru pro SignalR 2 jsou dostupné jenom v .NET 4.5. Servery s .NET 4.0 musí používat SignalR v1.x.
Registrace middlewaru SignalR
Pokud chcete definovat trasu, kterou budou klienti používat pro připojení k vašemu centru, zavolejte metodu MapSignalR
při spuštění aplikace. MapSignalR
je rozšiřující metoda pro OwinExtensions
třídu . Následující příklad ukazuje, jak definovat trasu SignalR Hubs pomocí spouštěcí třídy OWIN.
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(MyApplication.Startup))]
namespace MyApplication
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Any connection or hub wire up and configuration should go here
app.MapSignalR();
}
}
}
Pokud přidáváte funkci SignalR do aplikace ASP.NET MVC, ujistěte se, že je trasa SignalR přidaná před ostatní trasy. Další informace najdete v tématu Kurz: Začínáme se službou SignalR 2 a MVC 5.
Adresa URL /signalr
Ve výchozím nastavení je adresa URL trasy, kterou budou klienti používat pro připojení k vašemu centru, "/signalr". (Nezaměňujte tuto adresu URL s adresou URL /signalr/hubs, která je určená pro automaticky vygenerovaný soubor JavaScriptu. Další informace o vygenerovaném proxy serveru najdete v tématu Průvodce rozhraním API služby SignalR Hubs – JavaScript Client – Vygenerovaný proxy server a jeho funkce pro vás.)
Mohou nastat mimořádné okolnosti, kvůli kterým tato základní adresa URL nebude použitelná pro Službu SignalR; Například v projektu máte složku s názvem signalr a nechcete název měnit. V takovém případě můžete změnit základní adresu URL, jak je znázorněno v následujících příkladech (nahraďte "/signalr" ve vzorovém kódu požadovanou adresou URL).
Kód serveru, který určuje adresu URL
app.MapSignalR("/signalr", new HubConfiguration());
Kód klienta JavaScriptu, který určuje adresu URL (s vygenerovaným proxy serverem)
$.connection.hub.url = "/signalr"
$.connection.hub.start().done(init);
Kód klienta JavaScriptu, který určuje adresu URL (bez vygenerovaného proxy serveru)
var connection = $.hubConnection("/signalr", { useDefaultPath: false });
Kód klienta .NET, který určuje adresu URL
var hubConnection = new HubConnection("http://contoso.com/signalr", useDefaultUrl: false);
Konfigurace možností služby SignalR
MapSignalR
Přetížení metody umožňuje zadat vlastní adresu URL, vlastní překladač závislostí a následující možnosti:
Povolte volání mezi doménami pomocí CORS nebo JSONP z klientů prohlížeče.
Pokud prohlížeč načítá stránku z
http://contoso.com
, připojení SignalR je obvykle ve stejné doméně na adresehttp://contoso.com/signalr
. Pokud stránka zhttp://contoso.com
vytvoří připojení khttp://fabrikam.com/signalr
, jedná se o připojení mezi doménou. Z bezpečnostních důvodů jsou připojení mezi doménou ve výchozím nastavení zakázaná. Další informace najdete v tématu Průvodce ASP.NET rozhraní API služby SignalR Hubs – JavaScript Client – Jak navázat připojení mezi doménami.Povolte podrobné chybové zprávy.
Pokud dojde k chybám, je výchozím chováním služby SignalR odesílání oznámení klientům bez podrobností o tom, co se stalo. Odesílání podrobných informací o chybách klientům se nedoporučuje v produkčním prostředí, protože uživatelé se zlými úmysly mohou tyto informace použít při útocích na vaši aplikaci. Při řešení potíží můžete pomocí této možnosti dočasně povolit informativnější zasílání zpráv o chybách.
Zakažte automaticky generované proxy soubory JavaScriptu.
Ve výchozím nastavení se vygeneruje soubor JavaScriptu s proxy pro vaše třídy Centra v reakci na adresu URL "/signalr/hubs". Pokud nechcete používat proxy javascriptové servery nebo pokud chcete tento soubor vygenerovat ručně a odkazovat na fyzický soubor v klientech, můžete pomocí této možnosti zakázat generování proxy serveru. Další informace najdete v tématu Průvodce rozhraním API služby SignalR Hubs – JavaScript Client – Vytvoření fyzického souboru pro proxy vygenerovaný službou SignalR.
Následující příklad ukazuje, jak zadat adresu URL připojení SignalR a tyto možnosti ve volání MapSignalR
metody . Pokud chcete zadat vlastní adresu URL, nahraďte "/signalr" v příkladu adresou URL, kterou chcete použít.
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
hubConfiguration.EnableJavaScriptProxies = false;
app.MapSignalR("/signalr", hubConfiguration);
Vytvoření a používání tříd centra
Chcete-li vytvořit centrum, vytvořte třídu, která je odvozena z Microsoft.Aspnet.Signalr.Hub. Následující příklad ukazuje jednoduchou třídu Centra pro chatovací aplikaci.
public class ContosoChatHub : Hub
{
public async Task NewContosoChatMessage(string name, string message)
{
await Clients.All.addNewMessageToPage(name, message);
}
}
V tomto příkladu může připojený klient volat metodu NewContosoChatMessage
, a když ano, přijatá data se vysílají všem připojeným klientům.
Životnost objektu centra
Nevytvoříte instanci třídy Hub ani nevoláte její metody z vlastního kódu na serveru; vše, co za vás dělá kanál SignalR Hubs. SignalR vytvoří novou instanci vaší třídy Hub pokaždé, když potřebuje zpracovat operaci centra, například když se klient připojí, odpojí nebo provede volání metody na server.
Vzhledem k tomu, že instance třídy Hub jsou přechodné, nemůžete je použít k udržování stavu od jednoho volání metody po další. Pokaždé, když server přijme volání metody z klienta, nová instance vaší třídy Hub zpracuje zprávu. Pokud chcete udržovat stav prostřednictvím více připojení a volání metod, použijte jinou metodu, jako je databáze nebo statická proměnná ve třídě Hub, nebo jinou třídu, která není odvozena z Hub
. Pokud data zachováte v paměti pomocí metody, jako je statická proměnná ve třídě Hub, při recyklaci domény aplikace dojde ke ztrátě dat.
Pokud chcete klientům odesílat zprávy z vlastního kódu, který běží mimo třídu Hub, nemůžete to udělat vytvořením instance hubové třídy, ale můžete to udělat tak, že získáte odkaz na objekt kontextu SignalR pro vaši třídu Hubu. Další informace najdete v části Jak volat metody klienta a spravovat skupiny mimo třídu Hub dále v tomto tématu.
Camel-casing názvů rozbočovačů v klientech JavaScriptu
Ve výchozím nastavení odkazují klienti JavaScriptu na centrum pomocí velbloudé verze názvu třídy. SignalR tuto změnu automaticky provede tak, aby kód JavaScriptu odpovídal konvencím JavaScriptu. Předchozí příklad by se v kódu JavaScriptu označoval jako contosoChatHub
.
Server
public class ContosoChatHub : Hub
Javascriptový klient s využitím vygenerovaného proxy serveru
var contosoChatHubProxy = $.connection.contosoChatHub;
Pokud chcete zadat jiný název, který mají klienti používat, přidejte HubName
atribut . Při použití atributu HubName
nedojde u klientů JavaScriptu ke změně názvu na velká písmena camel.
Server
[HubName("PascalCaseContosoChatHub")]
public class ContosoChatHub : Hub
Javascriptový klient s využitím vygenerovaného proxy serveru
var contosoChatHubProxy = $.connection.PascalCaseContosoChatHub;
Více center
V aplikaci můžete definovat více tříd centra. Když to uděláte, připojení se sdílí, ale skupiny jsou oddělené:
Všichni klienti použijí stejnou adresu URL k navázání připojení SignalR k vaší službě (/signalr nebo vlastní adresu URL, pokud jste ji zadali) a toto připojení se použije pro všechna centra definovaná službou.
Ve srovnání s definováním všech funkcí centra v jedné třídě není žádný rozdíl ve výkonu více center.
Všechna centra získají stejné informace o požadavcích HTTP.
Vzhledem k tomu, že všechna centra sdílejí stejné připojení, jediné informace o požadavku HTTP, které server získá, je to, co je součástí původního požadavku HTTP, který naváže připojení SignalR. Pokud žádost o připojení použijete k předání informací z klienta na server zadáním řetězce dotazu, nemůžete různým rozbočovačům poskytnout různé řetězce dotazů. Všechna centra obdrží stejné informace.
Vygenerovaný soubor proxy javascriptu bude obsahovat proxy servery pro všechna centra v jednom souboru.
Informace o proxy javascriptu najdete v tématu Průvodce rozhraním API služby SignalR Hubs – JavaScript Client – Vygenerovaný proxy server a jeho funkce pro vás.
Skupiny jsou definovány v rámci Hubs.
V SignalR můžete definovat pojmenované skupiny, které budou vysílat podmnožině připojených klientů. Skupiny se pro každé centrum spravují samostatně. Například skupina s názvem Administrators by obsahovala jednu sadu klientů pro vaši
ContosoChatHub
třídu a stejný název skupiny by odkazoval na jinou sadu klientů pro vašiStockTickerHub
třídu.
Strongly-Typed Hubs
Pokud chcete definovat rozhraní pro metody centra, na které může klient odkazovat (a povolit intellisense pro metody centra), odvozujte centrum z Hub<T>
(zavedeného v SignalR 2.1), a ne Hub
z :
public class StrongHub : Hub<IClient>
{
public async Task Send(string message)
{
await Clients.All.NewMessage(message);
}
}
public interface IClient
{
Task NewMessage(string message);
}
Jak definovat metody ve třídě Hub, které můžou klienti volat
Pokud chcete v centru zveřejnit metodu, kterou chcete volat z klienta, deklarujte veřejnou metodu, jak je znázorněno v následujících příkladech.
public class ContosoChatHub : Hub
{
public async Task NewContosoChatMessage(string name, string message)
{
await Clients.All.addNewMessageToPage(name, message);
}
}
public class StockTickerHub : Hub
{
public IEnumerable<Stock> GetAllStocks()
{
return _stockTicker.GetAllStocks();
}
}
Můžete zadat návratový typ a parametry, včetně složitých typů a polí, stejně jako v jakékoli metodě jazyka C#. Všechna data, která obdržíte v parametrech nebo se vrátíte volajícímu, se mezi klientem a serverem sdělují pomocí json a SignalR automaticky zpracovává vazby složitých objektů a polí objektů.
Camel-casing názvů metod v klientech JavaScriptu
Ve výchozím nastavení odkazují klienti JavaScriptu na metody Centra pomocí velbloudé verze názvu metody. SignalR tuto změnu automaticky provede tak, aby kód JavaScriptu odpovídal konvencím JavaScriptu.
Server
public void NewContosoChatMessage(string userName, string message)
Javascriptový klient s využitím vygenerovaného proxy serveru
contosoChatHubProxy.server.newContosoChatMessage(userName, message);
Pokud chcete zadat jiný název, který mají klienti používat, přidejte HubMethodName
atribut .
Server
[HubMethodName("PascalCaseNewContosoChatMessage")]
public void NewContosoChatMessage(string userName, string message)
Javascriptový klient s využitím vygenerovaného proxy serveru
contosoChatHubProxy.server.PascalCaseNewContosoChatMessage(userName, message);
Kdy provést asynchronně
Pokud bude metoda dlouhotrvající nebo bude muset provést práci, která by zahrnovala čekání, jako je vyhledávání databáze nebo volání webové služby, nastavte metodu Hub jako asynchronní vrácením objektu Task (místo návratu void
) nebo objektu Task<T> (místo návratového T
typu). Když vrátíte Task
objekt z metody, SignalR počká Task
na dokončení a pak odešle nezabalený výsledek zpět klientovi, takže není rozdíl v tom, jak kódujete volání metody v klientovi.
Asynchronní metoda Hub zabrání blokování připojení, když používá přenos WebSocket. Pokud se metoda Hub spustí synchronně a přenos je WebSocket, následné vyvolání metod v centru ze stejného klienta se zablokuje, dokud se metoda Hub neskončiní.
Následující příklad ukazuje stejnou metodu naprogramovanou tak, aby se spustila synchronně nebo asynchronně, následovaná kódem klienta JavaScriptu, který funguje pro volání obou verzí.
Synchronní
public IEnumerable<Stock> GetAllStocks()
{
// Returns data from memory.
return _stockTicker.GetAllStocks();
}
Asynchronní
public async Task<IEnumerable<Stock>> GetAllStocks()
{
// Returns data from a web service.
var uri = Util.getServiceUri("Stocks");
using (HttpClient httpClient = new HttpClient())
{
var response = await httpClient.GetAsync(uri);
return (await response.Content.ReadAsAsync<IEnumerable<Stock>>());
}
}
Javascriptový klient s využitím vygenerovaného proxy serveru
stockTickerHubProxy.server.getAllStocks().done(function (stocks) {
$.each(stocks, function () {
alert(this.Symbol + ' ' + this.Price);
});
});
Další informace o použití asynchronních metod v ASP.NET 4.5 najdete v tématu Použití asynchronních metod v ASP.NET MVC 4.
Definování přetížení
Pokud chcete definovat přetížení pro metodu, musí se počet parametrů v každém přetížení lišit. Pokud odlišíte přetížení pouze zadáním různých typů parametrů, vaše třída Hub se zkompiluje, ale služba SignalR vyvolá výjimku za běhu, když se klienti pokusí volat jedno z přetížení.
Generování sestav průběhu volání metod centra
SignalR 2.1 přidává podporu modelu generování sestav průběhu zavedeného v .NET 4.5. Pokud chcete implementovat vytváření sestav průběhu, definujte parametr pro metodu IProgress<T>
centra, ke kterému má klient přístup:
public class ProgressHub : Hub
{
public async Task<string> DoLongRunningThing(IProgress<int> progress)
{
for (int i = 0; i <= 100; i+=5)
{
await Task.Delay(200);
progress.Report(i);
}
return "Job complete!";
}
}
Při psaní dlouhotrvající serverové metody je důležité místo blokování vlákna centra použít asynchronní programovací vzor, jako je Async/Await.
Jak volat metody klienta z třídy Hub
Pokud chcete volat metody klienta ze serveru, použijte Clients
vlastnost v metodě ve vaší třídě Hub. Následující příklad ukazuje kód serveru, který volá addNewMessageToPage
všechny připojené klienty, a kód klienta, který definuje metodu v javascriptovém klientovi.
Server
public class ContosoChatHub : Hub
{
public async Task NewContosoChatMessage(string name, string message)
{
await Clients.All.addNewMessageToPage(name, message);
}
}
Vyvolání metody klienta je asynchronní operace a vrátí Task
. await
použijte:
- Chcete-li zajistit, aby zpráva byla odeslána bez chyby.
- Povolení zachytávání a zpracování chyb v bloku try-catch
Javascriptový klient s využitím vygenerovaného proxy serveru
contosoChatHubProxy.client.addNewMessageToPage = function (name, message) {
// Add the message to the page.
$('#discussion').append('<li><strong>' + htmlEncode(name)
+ '</strong>: ' + htmlEncode(message) + '<li>');
};
Z metody klienta nemůžete získat návratovou hodnotu. syntaxe, například int x = Clients.All.add(1,1)
nefunguje.
Pro parametry můžete zadat komplexní typy a pole. Následující příklad předá klientovi komplexní typ v parametru metody.
Kód serveru, který volá metodu klienta pomocí komplexního objektu
public async Task SendMessage(string name, string message)
{
await Clients.All.addContosoChatMessageToPage(new ContosoChatMessage() { UserName = name, Message = message });
}
Kód serveru, který definuje komplexní objekt
public class ContosoChatMessage
{
public string UserName { get; set; }
public string Message { get; set; }
}
Javascriptový klient s využitím vygenerovaného proxy serveru
var contosoChatHubProxy = $.connection.contosoChatHub;
contosoChatHubProxy.client.addMessageToPage = function (message) {
console.log(message.UserName + ' ' + message.Message);
});
Výběr klientů, kteří budou přijímat rpc
Vlastnost Klienti vrátí HubConnectionContext objekt, který poskytuje několik možností pro určení, kteří klienti budou přijímat RPC:
Všichni připojení klienti.
Clients.All.addContosoChatMessageToPage(name, message);
Pouze volající klient.
Clients.Caller.addContosoChatMessageToPage(name, message);
Všichni klienti kromě volajícího klienta.
Clients.Others.addContosoChatMessageToPage(name, message);
Konkrétního klienta identifikovaného ID připojení.
Clients.Client(Context.ConnectionId).addContosoChatMessageToPage(name, message);
Tento příklad volá
addContosoChatMessageToPage
volajícího klienta a má stejný účinek jako použitíClients.Caller
.Všichni připojení klienti s výjimkou zadaných klientů, kteří jsou identifikováni ID připojení.
Clients.AllExcept(connectionId1, connectionId2).addContosoChatMessageToPage(name, message);
Všichni připojení klienti v zadané skupině.
Clients.Group(groupName).addContosoChatMessageToPage(name, message);
Všichni připojení klienti v zadané skupině s výjimkou zadaných klientů identifikovaných ID připojení.
Clients.Group(groupName, connectionId1, connectionId2).addContosoChatMessageToPage(name, message);
Všichni připojení klienti v zadané skupině s výjimkou volajícího klienta.
Clients.OthersInGroup(groupName).addContosoChatMessageToPage(name, message);
Konkrétní uživatel, identifikovaný podle userId.
Clients.User(userid).addContosoChatMessageToPage(name, message);
Ve výchozím nastavení je
IPrincipal.Identity.Name
to , ale to lze změnit registrací implementace IUserIdProvider u globálního hostitele.Všichni klienti a skupiny v seznamu ID připojení.
Clients.Clients(ConnectionIds).broadcastMessage(name, message);
Seznam skupin.
Clients.Groups(GroupIds).broadcastMessage(name, message);
Uživatel podle jména.
Clients.Client(username).broadcastMessage(name, message);
Seznam uživatelských jmen (zavedených v SignalR 2.1)
Clients.Users(new string[] { "myUser", "myUser2" }).broadcastMessage(name, message);
Žádné ověření názvů metod v době kompilace
Zadaný název metody je interpretován jako dynamický objekt, což znamená, že pro něj neexistuje technologie IntelliSense ani ověření v době kompilace. Výraz se vyhodnocuje za běhu. Když se volání metody spustí, SignalR odešle název metody a hodnoty parametru klientovi a pokud má klient metodu, která odpovídá názvu, zavolá se tato metoda a předají se jí hodnoty parametrů. Pokud se v klientovi nenajde žádná odpovídající metoda, nevyvolá se žádná chyba. Informace o formátu dat, která SignalR přenáší klientovi na pozadí při volání metody klienta, najdete v tématu Úvod do SignalR.
Párování názvů metod nerozlišující malá a velká písmena
Porovnávání názvů metod nerozlišuje velká a malá písmena. Například Clients.All.addContosoChatMessageToPage
na serveru se spustí AddContosoChatMessageToPage
, addcontosochatmessagetopage
nebo addContosoChatMessageToPage
na klientovi.
Asynchronní spouštění
Metoda, kterou voláte, se spouští asynchronně. Jakýkoli kód, který přijde po volání metody klienta, se spustí okamžitě bez čekání na dokončení přenosu dat do klientů signalR, pokud neurčíte, že následující řádky kódu by měly čekat na dokončení metody. Následující příklad kódu ukazuje, jak postupně spustit dvě metody klienta.
Použití funkce Await (.NET 4.5)
public async Task NewContosoChatMessage(string name, string message)
{
await Clients.Others.addContosoChatMessageToPage(data);
await Clients.Caller.notifyMessageSent();
}
Pokud používáte await
k čekání, dokud se metoda klienta nedokončí, než se spustí další řádek kódu, neznamená to, že klienti skutečně obdrží zprávu před spuštěním dalšího řádku kódu. "Dokončení" volání metody klienta pouze znamená, že SignalR udělal vše potřebné k odeslání zprávy. Pokud potřebujete ověřit, že klienti zprávu obdrželi, musíte tento mechanismus naprogramovat sami. Například můžete kódovat metodu MessageReceived
v centru a v metodě na addContosoChatMessageToPage
klientovi můžete volat MessageReceived
po provedení jakékoli práce, kterou potřebujete na klientovi udělat. V MessageReceived
centru můžete provádět jakoukoli práci, která závisí na skutečném přijetí klienta a zpracování volání původní metody.
Použití řetězcové proměnné jako názvu metody
Pokud chcete vyvolat metodu klienta pomocí řetězcové proměnné jako názvu metody, přetypujte Clients.All
(nebo Clients.Others
, Clients.Caller
atd.) a IClientProxy
pak volejte Invoke(methodName, args...).
public async Task NewContosoChatMessage(string name, string message)
{
string methodToCall = "addContosoChatMessageToPage";
IClientProxy proxy = Clients.All;
await proxy.Invoke(methodToCall, name, message);
}
Správa členství ve skupinách z třídy Hub
Skupiny v SignalR poskytují metodu pro vysílání zpráv určeným podmnožinám připojených klientů. Skupina může mít libovolný počet klientů a klient může být členem libovolného počtu skupin.
Pokud chcete spravovat členství ve skupinách, použijte metody Add a Remove , které Groups
poskytuje vlastnost Hub třídy. Následující příklad ukazuje Groups.Add
metody a Groups.Remove
používané v metodách hubu, které jsou volána kódem klienta, následovaný kódem klienta JavaScriptu, který je volá.
Server
public class ContosoChatHub : Hub
{
public Task JoinGroup(string groupName)
{
return Groups.Add(Context.ConnectionId, groupName);
}
public Task LeaveGroup(string groupName)
{
return Groups.Remove(Context.ConnectionId, groupName);
}
}
Javascriptový klient s využitím vygenerovaného proxy serveru
contosoChatHubProxy.server.joinGroup(groupName);
contosoChatHubProxy.server.leaveGroup(groupName);
Skupiny nemusíte explicitně vytvářet. V důsledku toho se skupina automaticky vytvoří při prvním zadání jejího názvu ve volání Groups.Add
a odstraní se, když odeberete poslední připojení z členství v ní.
Neexistuje žádné rozhraní API pro získání seznamu členství ve skupině nebo seznamu skupin. SignalR odesílá zprávy klientům a skupinám na základě modelu pub/sub a server neudržuje seznamy skupin ani členství ve skupinách. To pomáhá maximalizovat škálovatelnost, protože pokaždé, když přidáte uzel do webové farmy, musí se do nového uzlu rozšířit jakýkoli stav, který SignalR udržuje.
Asynchronní spouštění metod Add a Remove
Metody Groups.Add
a Groups.Remove
se provádějí asynchronně. Pokud chcete přidat klienta do skupiny a okamžitě odeslat zprávu klientovi pomocí skupiny, musíte se ujistit, že Groups.Add
se metoda dokončí jako první. Následující příklad kódu ukazuje, jak to udělat.
Přidání klienta do skupiny a následné zasílání zpráv klientovi
public async Task JoinGroup(string groupName)
{
await Groups.Add(Context.ConnectionId, groupName);
await Clients.Group(groupname).addContosoChatMessageToPage(Context.ConnectionId + " added to group");
}
Trvalost členství ve skupině
SignalR sleduje připojení, nikoli uživatele, takže pokud chcete, aby byl uživatel ve stejné skupině pokaždé, když uživatel naváže připojení, musíte volat Groups.Add
pokaždé, když uživatel naváže nové připojení.
Po dočasné ztrátě připojení může někdy SignalR připojení obnovit automaticky. V takovém případě služba SignalR obnovuje stejné připojení, nenavazuje nové připojení, a proto se automaticky obnoví členství klienta ve skupině. To je možné i v případě, že je dočasné přerušení výsledkem restartování nebo selhání serveru, protože stav připojení každého klienta, včetně členství ve skupinách, se klientovi přepne. Pokud server přestane fungovat a před vypršením časového limitu připojení ho nahradí novým serverem, klient se může automaticky znovu připojit k novému serveru a znovu se zaregistrovat ve skupinách, kterých je členem.
Pokud připojení nejde obnovit automaticky po ztrátě připojení nebo když vyprší jeho časový limit nebo když se klient odpojí (například když prohlížeč přejde na novou stránku), členství ve skupině se ztratí. Až se uživatel příště připojí, bude to nové připojení. Pokud chcete zachovat členství ve skupinách, když stejný uživatel naváže nové připojení, musí vaše aplikace sledovat přidružení mezi uživateli a skupinami a obnovit členství ve skupinách pokaždé, když uživatel naváže nové připojení.
Další informace o připojeních a opětovném připojení najdete v části Zpracování událostí životnosti připojení ve třídě Hub dále v tomto tématu.
Skupiny pro jednoho uživatele
Aplikace, které používají SignalR, obvykle musí sledovat přidružení mezi uživateli a připojeními, aby věděli, který uživatel odeslal zprávu a kteří uživatelé by měli zprávu dostávat. Skupiny se k tomu používají v jednom ze dvou běžně používaných vzorů.
Skupiny pro jednoho uživatele.
Jako název skupiny můžete zadat uživatelské jméno a přidat id aktuálního připojení ke skupině pokaždé, když se uživatel připojí nebo se znovu připojí. Chcete odesílat zprávy uživateli, který odešlete skupině. Nevýhodou této metody je, že skupina neposkytuje způsob, jak zjistit, jestli je uživatel online nebo offline.
Sledování přidružení mezi uživatelskými jmény a ID připojení
Můžete uložit přidružení mezi jednotlivými uživatelskými jmény a jedním nebo více ID připojení ve slovníku nebo databázi a aktualizovat uložená data pokaždé, když se uživatel připojí nebo odpojí. Pokud chcete uživateli posílat zprávy, zadejte ID připojení. Nevýhodou této metody je, že zabírá více paměti.
Zpracování událostí životnosti připojení ve třídě Hub
Typickými důvody pro zpracování událostí doby života připojení je sledování, jestli je uživatel připojený nebo ne, a sledování přidružení mezi uživatelskými jmény a ID připojení. Pokud chcete spustit vlastní kód, když se klienti připojují nebo odpojí, přepište OnConnected
virtuální metody , OnDisconnected
a OnReconnected
třídy Hub, jak je znázorněno v následujícím příkladu.
public class ContosoChatHub : Hub
{
public override Task OnConnected()
{
// Add your own code here.
// For example: in a chat application, record the association between
// the current connection ID and user name, and mark the user as online.
// After the code in this method completes, the client is informed that
// the connection is established; for example, in a JavaScript client,
// the start().done callback is executed.
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
// Add your own code here.
// For example: in a chat application, mark the user as offline,
// delete the association between the current connection id and user name.
return base.OnDisconnected(stopCalled);
}
public override Task OnReconnected()
{
// Add your own code here.
// For example: in a chat application, you might have marked the
// user as offline after a period of inactivity; in that case
// mark the user as online again.
return base.OnReconnected();
}
}
Když se volá OnConnected, OnDisconnected a OnReconnected
Pokaždé, když prohlížeč přejde na novou stránku, musí být navázáno nové připojení, což znamená, že SignalR spustí metodu OnDisconnected
následovanou metodou OnConnected
. SignalR vždy vytvoří nové ID připojení, když je navázáno nové připojení.
Metoda OnReconnected
se volá, pokud došlo k dočasnému přerušení připojení, ze kterého se signalR může automaticky obnovit, například při dočasném odpojení a opětovném připojení kabelu před vypršením časového limitu připojení. Metoda se OnDisconnected
volá, když je klient odpojený a SignalR se nemůže automaticky znovu připojit, například když prohlížeč přejde na novou stránku. Proto je možná posloupnost událostí pro daného klienta OnConnected
, OnReconnected
, OnDisconnected
; nebo OnConnected
, . OnDisconnected
Pro dané připojení se nezobrazí posloupnost OnConnected
, OnDisconnected
. OnReconnected
Metoda OnDisconnected
se v některých scénářích nevolá, například když dojde k výpadku serveru nebo recyklaci domény aplikace. Když se spustí jiný server nebo doména aplikace dokončí recyklaci, někteří klienti se můžou znovu připojit a aktivovat OnReconnected
událost.
Další informace najdete v tématu Vysvětlení a zpracování událostí životnosti připojení v SignalR.
Stav volajícího se nenaplní
Metody obslužné rutiny události životnosti připojení se volají ze serveru, což znamená, že žádný stav, který vložíte do objektu state
na klientovi, nebude naplněn ve Caller
vlastnosti na serveru. Informace o objektu state
a Caller
vlastnosti najdete v části Jak předávat stav mezi klienty a třídou Hub dále v tomto tématu.
Jak získat informace o klientovi z vlastnosti Context
Pokud chcete získat informace o klientovi Context
, použijte vlastnost hub třídy. Vlastnost Context
vrátí objekt HubCallerContext , který poskytuje přístup k následujícím informacím:
ID připojení volajícího klienta.
string connectionID = Context.ConnectionId;
ID připojení je identifikátor GUID přiřazený službou SignalR (hodnotu nemůžete zadat ve vlastním kódu). Pro každé připojení existuje jedno ID připojení a stejné ID připojení používají všechna centra, pokud máte v aplikaci více center.
Data hlaviček HTTP.
System.Collections.Specialized.NameValueCollection headers = Context.Request.Headers;
Hlavičky HTTP můžete získat také z .
Context.Headers
Důvodem pro více odkazů na stejnou věc je, žeContext.Headers
byla vytvořena jako první,Context.Request
vlastnost byla přidána později aContext.Headers
byla zachována pro zpětnou kompatibilitu.Dotazování na data řetězce.
System.Collections.Specialized.NameValueCollection queryString = Context.Request.QueryString; string parameterValue = queryString["parametername"]
Data řetězce dotazu můžete získat také z
Context.QueryString
.Řetězec dotazu, který získáte v této vlastnosti, je ten, který byl použit s požadavkem HTTP, který navazoval připojení SignalR. Parametry řetězce dotazu v klientovi můžete přidat konfigurací připojení, což je pohodlný způsob předávání dat o klientovi z klienta na server. Následující příklad ukazuje jeden způsob, jak přidat řetězec dotazu do javascriptového klienta při použití vygenerovaného proxy serveru.
$.connection.hub.qs = { "version" : "1.0" };
Další informace o nastavení parametrů řetězce dotazu najdete v průvodcích rozhraní API pro klienty JavaScriptu a .NET .
Metodu přenosu používanou pro připojení najdete v datech řetězce dotazu spolu s některými dalšími hodnotami používanými interně službou SignalR:
string transportMethod = queryString["transport"];
Hodnota
transportMethod
bude "webSockets", "serverSentEvents", "foreverFrame" nebo "longPolling". Všimněte si, že pokud tuto hodnotu zkontrolujete vOnConnected
metodě obslužné rutiny události, v některých scénářích můžete na začátku získat hodnotu přenosu, která není konečnou vyjednanou metodou přenosu pro připojení. V takovém případě metoda vyvolá výjimku a bude volána znovu později při vytvoření konečné metody přenosu.Soubory cookie.
System.Collections.Generic.IDictionary<string, Cookie> cookies = Context.Request.Cookies;
Soubory cookie můžete získat také z
Context.RequestCookies
adresy .Informace o uživateli.
System.Security.Principal.IPrincipal user = Context.User;
Objekt HttpContext pro požadavek :
System.Web.HttpContextBase httpContext = Context.Request.GetHttpContext();
Tuto metodu použijte místo získání
HttpContext.Current
objektuHttpContext
pro připojení SignalR.
Předávání stavu mezi klienty a třídou Hub
Klientský proxy server poskytuje state
objekt, ve kterém můžete ukládat data, která chcete přenést na server při každém volání metody. Na serveru můžete k datům přistupovat ve Clients.Caller
vlastnosti v metodách centra, které jsou volána klienty. Vlastnost Clients.Caller
není vyplněna pro metody OnConnected
obslužné rutiny události doby trvání připojení , OnDisconnected
a OnReconnected
.
Vytváření nebo aktualizace dat v objektu state
Clients.Caller
a vlastnost funguje v obou směrech. Hodnoty na serveru můžete aktualizovat a předávají se zpět klientovi.
Následující příklad ukazuje kód klienta JavaScriptu, který ukládá stav pro přenos na server při každém volání metody.
contosoChatHubProxy.state.userName = "Fadi Fakhouri";
contosoChatHubProxy.state.computerName = "fadivm1";
Následující příklad ukazuje ekvivalentní kód v klientovi .NET.
contosoChatHubProxy["userName"] = "Fadi Fakhouri";
chatHubProxy["computerName"] = "fadivm1";
Ve třídě Hub máte přístup k datům ve Clients.Caller
vlastnosti . Následující příklad ukazuje kód, který načte stav uvedený v předchozím příkladu.
public async Task NewContosoChatMessage(string data)
{
string userName = Clients.Caller.userName;
string computerName = Clients.Caller.computerName;
await Clients.Others.addContosoChatMessageToPage(message, userName, computerName);
}
Poznámka
Tento mechanismus pro trvalý stav není určen pro velké objemy dat, protože všechno, co vložíte do state
vlastnosti nebo Clients.Caller
, se při každém vyvolání metody zaokrouhlí. Je užitečný pro menší položky, jako jsou uživatelská jména nebo čítače.
V VB.NET nebo v centru se silnými typy není možné získat přístup k objektu stavu volajícího prostřednictvím Clients.Caller
; místo toho použijte Clients.CallerState
(zavedeno v SignalR 2.1):
Použití CallerState v jazyce C#
public async Task NewContosoChatMessage(string data)
{
string userName = Clients.CallerState.userName;
string computerName = Clients.CallerState.computerName;
await Clients.Others.addContosoChatMessageToPage(data, userName, computerName);
}
Použití CallerState v jazyce Visual Basic
Public Async Function NewContosoChatMessage(message As String) As Task
Dim userName As String = Clients.CallerState.userName
Dim computerName As String = Clients.CallerState.computerName
Await Clients.Others.addContosoChatMessageToPage(message, userName, computerName)
End Sub
Zpracování chyb ve třídě Hub
Pokud chcete zpracovat chyby, ke kterým dochází v metodách třídy Hub, nejprve se ujistěte, že "pozorujete" všechny výjimky z asynchronních operací (například vyvolání klientských metod) pomocí .await
Pak použijte jednu nebo více následujících metod:
Zabalte kód metody do bloků try-catch a protokolujte objekt výjimky. Pro účely ladění můžete odeslat výjimku klientovi, ale z bezpečnostních důvodů se nedoporučuje odesílat podrobné informace klientům v produkčním prostředí.
Vytvořte modul kanálu Hubs, který zpracovává metodu OnIncomingError . Následující příklad ukazuje modul kanálu, který protokoluje chyby následované kódem v souboru Startup.cs, který vloží modul do kanálu Hubs.
public class ErrorHandlingPipelineModule : HubPipelineModule { protected override void OnIncomingError(ExceptionContext exceptionContext, IHubIncomingInvokerContext invokerContext) { Debug.WriteLine("=> Exception " + exceptionContext.Error.Message); if (exceptionContext.Error.InnerException != null) { Debug.WriteLine("=> Inner Exception " + exceptionContext.Error.InnerException.Message); } base.OnIncomingError(exceptionContext, invokerContext); } }
public void Configuration(IAppBuilder app) { // Any connection or hub wire up and configuration should go here GlobalHost.HubPipeline.AddModule(new ErrorHandlingPipelineModule()); app.MapSignalR(); }
Použijte třídu (zavedenou
HubException
v SignalR 2). Tato chyba může být vyvoláná z jakéhokoli volání centra. KonstruktorHubError
přijímá řetězcovou zprávu a objekt pro ukládání dalších chybových dat. SignalR automaticky serializuje výjimku a odešle ji klientovi, kde se použije k odmítnutí nebo selhání vyvolání metody centra.Následující ukázky kódu ukazují, jak vyvolat
HubException
během vyvolání centra a jak zpracovat výjimku na klientech JavaScriptu a .NET.Kód serveru demonstrující třídu HubException
public class MyHub : Hub { public async Task Send(string message) { if(message.Contains("<script>")) { throw new HubException("This message will flow to the client", new { user = Context.User.Identity.Name, message = message }); } await Clients.All.send(message); } }
Kód klienta JavaScriptu demonstrující odpověď na vyvolání hubexception v centru
myHub.server.send("<script>") .fail(function (e) { if (e.source === 'HubException') { console.log(e.message + ' : ' + e.data.user); } });
Klientský kód .NET demonstrující odpověď na vyvolání hubexception v centru
try { await myHub.Invoke("Send", "<script>"); } catch(HubException ex) { Console.WriteLine(ex.Message); }
Další informace o modulech kanálu centra najdete v části Přizpůsobení kanálu služby Hubs dále v tomto tématu.
Povolení trasování
Pokud chcete povolit trasování na straně serveru, přidejte do souboru Web.config element system.diagnostics, jak je znázorněno v tomto příkladu:
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit https://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="SignalRSamples" connectionString="Data Source=(local);Initial Catalog=SignalRSamples;Integrated Security=SSPI;Asynchronous Processing=True;" />
<add name="SignalRSamplesWithMARS" connectionString="Data Source=(local);Initial Catalog=SignalRSamples;Integrated Security=SSPI;Asynchronous Processing=True;MultipleActiveResultSets=true;" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
<system.diagnostics>
<sources>
<source name="SignalR.SqlMessageBus">
<listeners>
<add name="SignalR-Bus" />
</listeners>
</source>
<source name="SignalR.ServiceBusMessageBus">
<listeners>
<add name="SignalR-Bus" />
</listeners>
</source>
<source name="SignalR.ScaleoutMessageBus">
<listeners>
<add name="SignalR-Bus" />
</listeners>
</source>
<source name="SignalR.Transports.WebSocketTransport">
<listeners>
<add name="SignalR-Transports" />
</listeners>
</source>
<source name="SignalR.Transports.ServerSentEventsTransport">
<listeners>
<add name="SignalR-Transports" />
</listeners>
</source>
<source name="SignalR.Transports.ForeverFrameTransport">
<listeners>
<add name="SignalR-Transports" />
</listeners>
</source>
<source name="SignalR.Transports.LongPollingTransport">
<listeners>
<add name="SignalR-Transports" />
</listeners>
</source>
<source name="SignalR.Transports.TransportHeartBeat">
<listeners>
<add name="SignalR-Transports" />
</listeners>
</source>
</sources>
<switches>
<add name="SignalRSwitch" value="Verbose" />
</switches>
<sharedListeners>
<add name="SignalR-Transports"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="transports.log.txt" />
<add name="SignalR-Bus"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="bus.log.txt" />
</sharedListeners>
<trace autoflush="true" />
</system.diagnostics>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v11.0" />
</parameters>
</defaultConnectionFactory>
</entityFramework>
</configuration>
Při spuštění aplikace v sadě Visual Studio můžete protokoly zobrazit v okně Výstup .
Jak volat metody klienta a spravovat skupiny mimo třídu Hub
Pokud chcete volat metody klienta z jiné třídy, než je vaše třída Hub, získejte odkaz na objekt kontextu SignalR pro centrum a použijte ho k volání metod na klientovi nebo ke správě skupin.
Následující ukázková StockTicker
třída získá kontextový objekt, uloží ho do instance třídy, uloží instanci třídy do statické vlastnosti a použije kontext z instance jedné třídy k volání updateStockPrice
metody na klientech, kteří jsou připojeni k centru s názvem StockTickerHub
.
// For the complete example, go to
// http://www.asp.net/signalr/overview/getting-started/tutorial-server-broadcast-with-aspnet-signalr
// This sample only shows code related to getting and using the SignalR context.
public class StockTicker
{
// Singleton instance
private readonly static Lazy<StockTicker> _instance = new Lazy<StockTicker>(
() => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>()));
private IHubContext _context;
private StockTicker(IHubContext context)
{
_context = context;
}
// This method is invoked by a Timer object.
private void UpdateStockPrices(object state)
{
foreach (var stock in _stocks.Values)
{
if (TryUpdateStockPrice(stock))
{
_context.Clients.All.updateStockPrice(stock);
}
}
}
Pokud potřebujete kontext použít vícekrát v objektu s dlouhou životností, získejte odkaz jednou a uložte ho místo toho, abyste ho pokaždé znovu získali. Získání kontextu jednou zajistí, že SignalR odesílá zprávy klientům ve stejném pořadí, ve kterém vaše metody centra aktivují volání metod klienta. Kurz, který ukazuje, jak používat kontext SignalR pro centrum, najdete v tématu Vysílání serveru s ASP.NET SignalR.
Volání klientských metod
Můžete určit, kteří klienti budou přijímat rpc, ale máte méně možností než při volání z třídy Hub. Důvodem je to, že kontext není přidružen ke konkrétnímu volání z klienta, takže žádné metody, které vyžadují znalost id aktuálního připojení, například Clients.Others
, nebo Clients.Caller
, Clients.OthersInGroup
nejsou k dispozici. Dostupné jsou tyto možnosti:
Všichni připojení klienti.
context.Clients.All.addContosoChatMessageToPage(name, message);
Konkrétního klienta identifikovaného ID připojení.
context.Clients.Client(connectionID).addContosoChatMessageToPage(name, message);
Všichni připojení klienti s výjimkou zadaných klientů, kteří jsou identifikováni ID připojení.
context.Clients.AllExcept(connectionId1, connectionId2).addContosoChatMessageToPage(name, message);
Všichni připojení klienti v zadané skupině.
context.Clients.Group(groupName).addContosoChatMessageToPage(name, message);
Všichni připojení klienti v zadané skupině s výjimkou zadaných klientů identifikovaných id připojení.
Clients.Group(groupName, connectionId1, connectionId2).addContosoChatMessageToPage(name, message);
Pokud voláte do třídy mimo centrum z metod v hubové třídě, můžete předat aktuální ID připojení a použít ho s Clients.Client
, Clients.AllExcept
nebo Clients.Group
k simulaci Clients.Caller
, Clients.Others
nebo Clients.OthersInGroup
. V následujícím příkladu MoveShapeHub
třída předá ID připojení do Broadcaster
třídy, Broadcaster
aby třída mohl simulovat Clients.Others
.
// For the complete example, see
// http://www.asp.net/signalr/overview/signalr-20/getting-started-with-signalr-20/tutorial-server-broadcast-with-signalr-20
// This sample only shows code that passes connection ID to the non-Hub class,
// in order to simulate Clients.Others.
public class MoveShapeHub : Hub
{
// Code not shown puts a singleton instance of Broadcaster in this variable.
private Broadcaster _broadcaster;
public void UpdateModel(ShapeModel clientModel)
{
clientModel.LastUpdatedBy = Context.ConnectionId;
// Update the shape model within our broadcaster
_broadcaster.UpdateShape(clientModel);
}
}
public class Broadcaster
{
public Broadcaster()
{
_hubContext = GlobalHost.ConnectionManager.GetHubContext<MoveShapeHub>();
}
public void UpdateShape(ShapeModel clientModel)
{
_model = clientModel;
_modelUpdated = true;
}
// Called by a Timer object.
public void BroadcastShape(object state)
{
if (_modelUpdated)
{
_hubContext.Clients.AllExcept(_model.LastUpdatedBy).updateShape(_model);
_modelUpdated = false;
}
}
}
Správa členství ve skupinách
Pro správu skupin máte stejné možnosti jako v hubové třídě.
Přidání klienta do skupiny
context.Groups.Add(connectionID, groupName);
Odebrání klienta ze skupiny
context.Groups.Remove(connectionID, groupName);
Jak přizpůsobit kanál Hubs
SignalR umožňuje vložit vlastní kód do kanálu centra. Následující příklad ukazuje vlastní modul kanálu centra, který protokoluje každé příchozí volání metody přijaté z klienta a volání odchozí metody vyvolané na klientovi:
public class LoggingPipelineModule : HubPipelineModule
{
protected override bool OnBeforeIncoming(IHubIncomingInvokerContext context)
{
Debug.WriteLine("=> Invoking " + context.MethodDescriptor.Name + " on hub " + context.MethodDescriptor.Hub.Name);
return base.OnBeforeIncoming(context);
}
protected override bool OnBeforeOutgoing(IHubOutgoingInvokerContext context)
{
Debug.WriteLine("<= Invoking " + context.Invocation.Method + " on client hub " + context.Invocation.Hub);
return base.OnBeforeOutgoing(context);
}
}
Následující kód v souboru Startup.cs zaregistruje modul, který se má spustit v kanálu centra:
public void Configuration(IAppBuilder app)
{
GlobalHost.HubPipeline.AddModule(new LoggingPipelineModule());
app.MapSignalR();
}
Existuje mnoho různých metod, které můžete přepsat. Úplný seznam najdete v tématu HubPipelineModule – metody.