ASP.NET Průvodce rozhraním API center SignalR – server (SignalR 1.x)

Patrick Fletcher, Tom Dykstra

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 rozhraní API služby ASP.NET SignalR Hubs pro Službu SignalR verze 1.1, 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 služby SignalR, center a trvalých připojení nebo kurz, který ukazuje, jak sestavit kompletní aplikaci SignalR, najdete v tématu SignalR – Začínáme.

Přehled

Tento dokument obsahuje následující části:

Dokumentaci k programování klientů najdete v následujících zdrojích informací:

Odkazy na témata referenčních informací k rozhraní API jsou na verzi rozhraní API .NET 4.5. Pokud používáte .NET 4, projděte si témata týkající se rozhraní API verze .NET 4.

Postup registrace trasy Služby SignalR a konfigurace možností služby SignalR

Pokud chcete definovat trasu, kterou budou klienti používat pro připojení k vašemu centru, zavolejte metodu MapHubs při spuštění aplikace. MapHubs je rozšiřující metoda pro System.Web.Routing.RouteCollection třídu . Následující příklad ukazuje, jak definovat trasu SignalR Hubs v souboru Global.asax .

using System.Web.Routing;
public class Global : System.Web.HttpApplication
{
    protected void Application_Start(object sender, EventArgs e)
    {
        RouteTable.Routes.MapHubs();
    }
}

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 a MVC 4.

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

RouteTable.Routes.MapHubs("/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

MapHubs Přetížení metody umožňuje zadat vlastní adresu URL, vlastní překladač závislostí a následující možnosti:

  • Povolte mezidoménová volání 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 adrese http://contoso.com/signalr. Pokud stránka z http://contoso.com vytvoří připojení k http://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í MapHubs metody . Pokud chcete zadat vlastní adresu URL, nahraďte "/signalr" v příkladu adresou URL, kterou chcete použít.

var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableCrossDomain = true;
hubConfiguration.EnableDetailedErrors = true;
hubConfiguration.EnableJavaScriptProxies = false;
RouteTable.Routes.MapHubs("/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 void NewContosoChatMessage(string name, string message)
    {
        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 udělá kanál SignalR Hubs. Služba SignalR vytvoří novou instanci vaší třídy Centra 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 k dalšímu. Pokaždé, když server přijme volání metody z klienta, nová instance vaší třídy Hub zpracuje zprávu. Pokud chcete zachovat stav prostřednictvím více připojení a volání metod, použijte některou jinou metodu, například databázi nebo statickou proměnnou ve třídě Hub, nebo jinou třídu, která není odvozená z Hub. Pokud data zachováte v paměti a použijete metodu, jako je statická proměnná ve třídě Hub, při recyklaci domény aplikace dojde ke ztrátě dat.

Pokud chcete klientům posílat zprávy z vlastního kódu, který běží mimo třídu Hub, nemůžete to udělat vytvořením instance třídy Hub, 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 klientské metody a spravovat skupiny mimo třídu Hub dále v tomto tématu.

Camel-cas of Hub names in JavaScript clients

Ve výchozím nastavení klienti JavaScriptu odkazují na centra pomocí verze názvu třídy s velkých písmeny. SignalR tuto změnu automaticky provede, aby kód JavaScriptu mohl vyhovovat 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 klientům zadat jiný název, přidejte HubName atribut . Když použijete HubName atribut, u klientů JavaScriptu nedojde ke změně názvu na camel case.

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žadavku HTTP.

    Vzhledem k tomu, že všechna centra sdílejí stejné připojení, jediné informace o požadavku HTTP, které server získá, jsou informace, které jsou součástí původního požadavku HTTP, který naváže připojení SignalR. Pokud požadavek na 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 dotazu. 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 se definují v rámci center.

    V SignalR můžete definovat pojmenované skupiny, které budou vysílat podmnožinu 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ši StockTickerHub třídu.

Jak definovat metody ve třídě Hub, které můžou volat klienti

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 void NewContosoChatMessage(string name, string message)
    {
        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ě komplexních typů a polí, stejně jako v jakékoli metodě jazyka C#. Veškerá data, která obdržíte v parametrech nebo se vrátíte volajícímu, se mezi klientem a serverem sdělují pomocí formátu JSON a SignalR automaticky zpracovává vazbu složitých objektů a polí objektů.

Camel-casing názvů metod v javascriptových klientech

Ve výchozím nastavení odkazují klienti JavaScriptu na metody Centra pomocí verze názvu metody s camel-cased. SignalR tuto změnu automaticky provede, aby kód JavaScriptu mohl vyhovovat 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 klientům zadat jiný název, 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 musí provést práci, která by zahrnovala čekání, například vyhledávání v databázi nebo volání webové služby, nastavte metodu Hub 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 ve způsobu kódování volání metody v klientovi.

Asynchronní metoda Centra zabrání blokování připojení, když používá přenos WebSocket. Pokud se metoda Hub spouští synchronně a přenos je WebSocket, další volání metod v centru ze stejného klienta se zablokují, dokud se metoda Centra neskonví.

Následující příklad ukazuje stejnou metodu naprogramovanou tak, aby běžela synchronně nebo asynchronně, následovaná kódem klienta JavaScriptu, který funguje pro volání jedné z verzí.

Synchronní

public IEnumerable<Stock> GetAllStocks()
{
    // Returns data from memory.
    return _stockTicker.GetAllStocks();
}

Asynchronní – ASP.NET 4.5

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 Hubu se zkompiluje, ale služba SignalR vyvolá výjimku za běhu, když se klienti pokusí volat jedno z přetížení.

Jak volat klientské metody z třídy Hub

Pokud chcete volat metody klienta ze serveru, použijte Clients vlastnost v metodě ve vaší třídě Centra. Následující příklad ukazuje serverový kód, který volá addNewMessageToPage všechny připojené klienty, a klientský kód, který definuje metodu v javascriptovém klientovi.

Server

public class ContosoChatHub : Hub
{
    public void NewContosoChatMessage(string name, string message)
    {
        Clients.All.addNewMessageToPage(name, message);
    }
}

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 nelze získat návratovou hodnotu. int x = Clients.All.add(1,1) například 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 void SendMessage(string name, string message)
{
    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 Clients vrátí objekt HubConnectionContext , který poskytuje několik možností pro určení klientů, kteří 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í klient identifikovaný podle 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.Callerpříkazu .

  • Všichni připojení klienti s výjimkou určených klientů identifikovaných podle 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ů, kteří jsou identifikovaní 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);
    

Žádné ověření doby kompilace pro názvy metod

Zadaný název metody je interpretován jako dynamický objekt, což znamená, že pro něj není k dispozici technologie IntelliSense ani ověření v době kompilace. Výraz se vyhodnocuje za běhu. Při volání metody odešle signalR klientovi název metody a hodnoty parametrů, 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á služba SignalR přenáší do klienta na pozadí při volání metody klienta, najdete v tématu Úvod do služby SignalR.

Porovnávání názvů metod nerozlišují 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 na klientovi spustí AddContosoChatMessageToPage, addcontosochatmessagetopagenebo addContosoChatMessageToPage .

Asynchronní spouštění

Metoda, kterou voláte, se spouští asynchronně. Jakýkoli kód, který následuje po volání metody klienta, se spustí okamžitě bez čekání na to, až signalR dokončí přenos dat do klientů, pokud neurčíte, že by následné řádky kódu měly čekat na dokončení metody. Následující příklady kódu ukazují, jak spouštět dvě metody klienta postupně, jednu pomocí kódu, který funguje v .NET 4.5, a druhou pomocí kódu, který funguje v .NET 4.

Příklad .NET 4.5

async public Task NewContosoChatMessage(string name, string message)
{
    await Clients.Others.addContosoChatMessageToPage(data);
    Clients.Caller.notifyMessageSent();
}

Příklad .NET 4

public void NewContosoChatMessage(string name, string message)
{
    (Clients.Others.addContosoChatMessageToPage(data) as Task).ContinueWith(antecedent =>
        Clients.Caller.notifyMessageSent());
}

Pokud počkáte awaitContinueWith na dokončení klientské metody před spuštěním dalšího řádku 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 Služba SignalR udělala 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. Můžete například naprogramovat metodu MessageReceived v centru a v addContosoChatMessageToPage metodě na klientovi můžete volat poté MessageReceived , co provedete jakoukoli práci, kterou potřebujete udělat na klientovi. 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.Calleratd.) na IClientProxy a pak volejte Invoke(methodName, args...).

public void NewContosoChatMessage(string name, string message)
{
    string methodToCall = "addContosoChatMessageToPage";
    IClientProxy proxy = Clients.All;
    proxy.Invoke(methodToCall, name, message);
}

Správa členství ve skupinách z třídy Hub

Skupiny ve službě 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 centra, které jsou volána klientským kódem, 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 je skupina automaticky vytvořena při prvním zadání jejího názvu ve volání Groups.Adda je odstraněna, když odeberete poslední připojení z členství v této skupině.

Neexistuje žádné rozhraní API pro získání seznamu členství ve skupinách ani 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 jakýkoli stav, který SignalR udržuje, rozšířit do nového uzlu.

Asynchronní spouštění metod Add a Remove

Metody a Groups.Remove se Groups.Add provádějí asynchronně. Pokud chcete přidat klienta do skupiny a okamžitě odeslat zprávu klientovi pomocí skupiny, musíte se nejprve ujistit, že Groups.Add se metoda dokončí. Následující příklady kódu ukazují, jak to udělat– jeden pomocí kódu, který funguje v .NET 4.5, a druhý pomocí kódu, který funguje v .NET 4.

Příklad .NET 4.5

async public Task JoinGroup(string groupName)
{
    await Groups.Add(Context.ConnectionId, groupName);
    Clients.Group(groupname).addContosoChatMessageToPage(Context.ConnectionId + " added to group");
}

Příklad .NET 4

public void JoinGroup(string groupName)
{
    (Groups.Add(Context.ConnectionId, groupName) as Task).ContinueWith(antecedent =>
        Clients.Group(groupName).addContosoChatMessageToPage(Context.ConnectionId + " added to group"));
}

Trvalost členství ve skupinách

SignalR sleduje připojení, ne 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í, ale nenavazuje nové připojení, a proto se automaticky obnoví členství klienta ve skupině. To je možné i v případě, že dočasné přerušení je výsledkem restartování serveru nebo selhání, protože stav připojení každého klienta, včetně členství ve skupinách, se klientovi zobrazí zpět. Pokud server přestane fungovat a před vypršením časového limitu připojení ho nahradí nový server, může se klient automaticky znovu připojit k novému serveru a znovu zaregistrovat do skupin, kterých je členem.

Pokud připojení nejde obnovit automaticky po ztrátě připojení nebo po vypršení jeho časového limitu nebo když se klient odpojí (například když prohlížeč přejde na novou stránku), členství ve skupinách 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í doby života připojení ve třídě Hub dále v tomto tématu.

Skupiny pro jednoho uživatele

Aplikace, které používají Službu SignalR, obvykle musí sledovat přidružení mezi uživateli a připojeními, aby věděly, který uživatel odeslal zprávu a kteří uživatelé by ji měli dostávat. Skupiny se k tomu používají v jednom ze dvou běžně používaných vzorů.

  • Skupiny pro jednoho uživatele.

    Uživatelské jméno můžete zadat jako název skupiny a přidat do skupiny ID aktuálního připojení pokaždé, když se uživatel připojí nebo se znovu připojí. Chcete-li odeslat 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 každým uživatelským jménem 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í doby života připojení ve třídě Hub

Typické důvody pro zpracování událostí doby života připojení jsou 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 OnConnectedvirtuální metody , OnDisconnecteda 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()
    {
        // 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();
    }

    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í se navázat nové připojení, což znamená, že SignalR spustí metodu OnDisconnected následovanou metodou OnConnected . SignalR vždy vytvoří nové ID připojení při navázání nového připojení.

Metoda se OnReconnected volá, když dojde k dočasnému přerušení připojení, ze kterého se služba 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é sekvenci událostí pro daného klienta OnConnected, OnReconnected; OnDisconnectednebo OnConnected. OnDisconnected Pro dané připojení se nezobrazí sekvence 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 na lince objeví jiný server nebo když 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í doby života připojení v SignalR.

Stav volajícího se nevyplní

Metody obslužné rutiny události životnosti připojení jsou volávány ze serveru, což znamená, že žádný stav, který vložíte do objektu state na klientovi, se do vlastnosti na serveru nenaplní Caller . 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 třídy Hub. 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 PROTOKOLU HTTP.

    System.Collections.Specialized.NameValueCollection headers = Context.Request.Headers;
    

    Hlavičky HTTP můžete získat také z Context.Headers. Důvodem více odkazů na stejnou věc je to, že Context.Headers byla vytvořena jako první, Context.Request vlastnost byla přidána později a Context.Headers byla zachována pro zpětnou kompatibilitu.

  • Zadejte dotaz na řetězcová data.

    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ý navázal připojení SignalR. Parametry řetězce dotazu můžete v klientovi 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 ze 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 příručká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, které služba SignalR interně používá:

    string transportMethod = queryString["transport"];
    

    Hodnota transportMethod bude "webSockets", "serverSentEvents", "foreverFrame" nebo "longPolling". Všimněte si, že pokud tuto hodnotu zkontrolujete v OnConnected 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í poslední vyjednanou metodou přenosu pro připojení. V takovém případě metoda vyvolá výjimku a bude znovu volána 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.RequestCookiesadresy .

  • 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 objektu HttpContext pro připojení SignalR.

Předávání stavu mezi klienty a třídou Hub

Proxy klienta poskytuje objekt, state do kterého můžete ukládat data, která chcete přenést na server při každém volání metody. Na serveru máte přístup k datům ve Clients.Caller vlastnosti v metodách centra, které jsou volána klienty. Vlastnost Clients.Caller se nevyplní pro metody OnConnectedobslužné rutiny událostí doby trvání připojení , OnDisconnecteda OnReconnected.

Vytvoření nebo aktualizace dat v objektu stateClients.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 javascriptového klienta, který ukládá stav pro přenos na server s každým voláním 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ě Centra můžete k datům přistupovat ve Clients.Caller vlastnosti . Následující příklad ukazuje kód, který načte stav, na který se odkazuje v předchozím příkladu.

public void NewContosoChatMessage(string data)
{
    string userName = Clients.Caller.userName;
    string computerName = Clients.Caller.computerName;
    Clients.Others.addContosoChatMessageToPage(message, userName, computerName);
}

Poznámka

Tento mechanismus pro zachování stavu není určen pro velké objemy dat, protože vše, 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.

Zpracování chyb ve třídě Hub

Ke zpracování chyb, ke kterým dochází v metodách třídy Centra, použijte jednu nebo obě z následujících metod:

  • Zabalte kód metody do bloků try-catch a zapište 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 klientům podrobné informace 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 Global.asax, který vloží modul do kanálu Hubs.

    public class ErrorHandlingPipelineModule : HubPipelineModule
    {
        protected override void OnIncomingError(Exception ex, IHubIncomingInvokerContext context)
        {
            Debug.WriteLine("=> Exception " + ex.Message);
            if (ex.InnerException != null)
            {
                Debug.WriteLine("=> Inner Exception " + ex.InnerException.Message);
            }
            base.OnIncomingError(ex, context);
        }
    }
    
    protected void Application_Start(object sender, EventArgs e)
    {
        GlobalHost.HubPipeline.AddModule(new ErrorHandlingPipelineModule()); 
        RouteTable.Routes.MapHubs();
    }
    

Další informace o modulech kanálu centra najdete v části How to customize the Hubs pipeline dále v tomto tématu.

Jak povolit 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>

Když aplikaci spustíte v sadě Visual Studio, můžete zobrazit protokoly v okně Výstup .

Jak volat klientské metody a spravovat skupiny mimo třídu Hub

Pokud chcete volat klientské metody z jiné třídy, než je vaše třída centra Hub, získejte odkaz na objekt kontextu SignalR pro centrum a použijte ho k volání metod v klientovi nebo ke správě skupin.

Následující ukázková StockTicker třída získá objekt kontextu, uloží ho do instance třídy , uloží instanci třídy do statické vlastnosti a použije kontext z instance třídy singleton 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/signalr-1x/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 v dlouhodobém objektu potřebujete kontext použít vícekrát, získejte odkaz jednou a uložte ho, místo abyste ho pokaždé znovu získali. Získání kontextu jednou zajistí, že služba SignalR odesílá zprávy klientům ve stejném pořadí, ve kterém metody centra aktivují volání metod klienta. Kurz, který ukazuje, jak používat kontext SignalR pro centrum, najdete v tématu Všesměrové 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í, jako Clients.Othersjsou , nebo Clients.Caller, Clients.OthersInGroupnejsou k dispozici. Dostupné jsou tyto možnosti:

  • Všichni připojení klienti.

    context.Clients.All.addContosoChatMessageToPage(name, message);
    
  • Konkrétní klient identifikovaný podle ID připojení.

    context.Clients.Client(connectionID).addContosoChatMessageToPage(name, message);
    
  • Všichni připojení klienti s výjimkou určených klientů identifikovaných podle 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 podle ID připojení.

    Clients.Group(groupName, connectionId1, connectionId2).addContosoChatMessageToPage(name, message);
    

Pokud voláte třídu mimo centrum z metod ve třídě Centra, můžete předat aktuální ID připojení a použít ho s Clients.Client, Clients.AllExceptnebo Clients.Group k simulaci Clients.Caller, Clients.Othersnebo 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/getting-started/tutorial-high-frequency-realtime-with-signalr
// 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 ve třídě Centra.

  • Přidání klienta do skupiny

    context.Groups.Add(connectionID, groupName);
    
  • Odebrání klienta ze skupiny

    context.Groups.Remove(connectionID, groupName);
    

Přizpůsobení kanálu Hubs

SignalR umožňuje vložit do kanálu centra vlastní kód. 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 Global.asax zaregistruje modul ke spuštění v kanálu centra:

protected void Application_Start(object sender, EventArgs e) 
{ 
    GlobalHost.HubPipeline.AddModule(new LoggingPipelineModule()); 
    RouteTable.Routes.MapHubs();
}

Existuje mnoho různých metod, které můžete přepsat. Úplný seznam najdete v tématu Metody HubPipelineModule.