Sdílet prostřednictvím


ASP.NET Průvodce rozhraním API služby SignalR Hubs – server (C#)

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

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:

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

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 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í 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ši StockTickerHub 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 Hubz :

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.Nameto , 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, addcontosochatmessagetopagenebo 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.Calleratd.) 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.Adda 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 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(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, ž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.

  • 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 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í 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.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

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 OnConnectedobslužné rutiny události doby trvání připojení , OnDisconnecteda OnReconnected.

Vytvář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 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. Konstruktor HubError 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.OthersInGroupnejsou 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.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/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.