Usare hub in SignalR per ASP.NET Core

Di Rachel Appel e Kevin Griffin

L'API SignalR Hubs consente ai client connessi di chiamare i metodi nel server. Il server definisce i metodi chiamati dal client e il client definisce i metodi chiamati dal server. SignalR si occupa di tutto ciò che è necessario per rendere possibile la comunicazione da client a server e da server a client in tempo reale.

Configurare SignalR hub

Per registrare i servizi richiesti dagli SignalR hub, chiamare AddSignalR in Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddSignalR();

Per configurare SignalR gli endpoint, chiamare MapHubanche in Program.cs:

app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");

app.Run();

Nota

ASP.NET assembly lato server Core SignalR sono ora installati con .NET Core SDK. Per altre informazioni, vedere SignalR assembly nel framework condiviso.

Creare e usare hub

Creare un hub dichiarando una classe che eredita da Hub. Aggiungere public metodi alla classe per renderli chiamabili dai client:

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
        => await Clients.All.SendAsync("ReceiveMessage", user, message);
}

Nota

Gli hub sono temporanei:

  • Non archiviare lo stato in una proprietà della classe hub. Ogni chiamata al metodo hub viene eseguita in una nuova istanza dell'hub.
  • Non creare un'istanza di un hub direttamente tramite l'inserimento delle dipendenze. Per inviare messaggi a un client da un'altra posizione nell'applicazione, usare un oggetto IHubContext.
  • Usare await quando si chiamano metodi asincroni che dipendono dall'hub che rimangono attivi. Ad esempio, un metodo come Clients.All.SendAsync(...) può non riuscire se viene chiamato senza await e il metodo hub viene completato prima SendAsync del completamento.

Oggetto Context

La Hub classe include una Context proprietà che contiene le proprietà seguenti con informazioni sulla connessione:

Proprietà Descrizione
ConnectionId Ottiene l'ID univoco per la connessione, assegnato da SignalR. Esiste un ID di connessione per ogni connessione.
UserIdentifier Ottiene l'identificatore utente. Per impostazione predefinita, SignalR usa l'oggetto ClaimTypes.NameIdentifier dell'oggetto ClaimsPrincipal associato alla connessione come identificatore utente.
User Ottiene l'oggetto ClaimsPrincipal associato all'utente corrente.
Items Ottiene una raccolta chiave/valore che può essere utilizzata per condividere i dati nell'ambito di questa connessione. I dati possono essere archiviati in questa raccolta e verranno mantenuti per la connessione tra diverse chiamate al metodo hub.
Features Ottiene la raccolta di funzionalità disponibili nella connessione. Per il momento, questa raccolta non è necessaria nella maggior parte degli scenari, quindi non è ancora documentata in dettaglio.
ConnectionAborted Ottiene un oggetto CancellationToken che notifica quando la connessione viene interrotta.

Hub.Context contiene anche i metodi seguenti:

metodo Descrizione
GetHttpContext Restituisce per HttpContext la connessione o null se la connessione non è associata a una richiesta HTTP. Per le connessioni HTTP, usare questo metodo per ottenere informazioni quali intestazioni HTTP e stringhe di query.
Abort Interrompe la connessione.

Oggetto Clients

La Hub classe include una Clients proprietà che contiene le proprietà seguenti per la comunicazione tra server e client:

Proprietà Descrizione
All Chiama un metodo su tutti i client connessi
Caller Chiama un metodo sul client che ha richiamato il metodo hub
Others Chiama un metodo su tutti i client connessi, ad eccezione del client che ha richiamato il metodo

Hub.Clients contiene anche i metodi seguenti:

metodo Descrizione
AllExcept Chiama un metodo su tutti i client connessi, ad eccezione delle connessioni specificate
Client Chiama un metodo in un client connesso specifico
Clients Chiama un metodo su client connessi specifici
Group Chiama un metodo su tutte le connessioni nel gruppo specificato
GroupExcept Chiama un metodo su tutte le connessioni nel gruppo specificato, ad eccezione delle connessioni specificate
Groups Chiama un metodo su più gruppi di connessioni
OthersInGroup Chiama un metodo su un gruppo di connessioni, escluso il client che ha richiamato il metodo hub
User Chiama un metodo su tutte le connessioni associate a un utente specifico
Users Chiama un metodo su tutte le connessioni associate agli utenti specificati

Ogni proprietà o metodo nelle tabelle precedenti restituisce un oggetto con un SendAsync metodo . Il SendAsync metodo riceve il nome del metodo client da chiamare ed eventuali parametri.

L'oggetto restituito dai Client metodi e Caller contiene anche un InvokeAsync metodo, che può essere utilizzato per attendere un risultato dal client.

Inviare messaggi ai client

Per effettuare chiamate a client specifici, utilizzare le proprietà dell'oggetto Clients . Nell'esempio seguente sono disponibili tre metodi hub:

  • SendMessage invia un messaggio a tutti i client connessi usando Clients.All.
  • SendMessageToCaller invia un messaggio al chiamante usando Clients.Caller.
  • SendMessageToGroup invia un messaggio a tutti i client del SignalR Users gruppo.
public async Task SendMessage(string user, string message)
    => await Clients.All.SendAsync("ReceiveMessage", user, message);

public async Task SendMessageToCaller(string user, string message)
    => await Clients.Caller.SendAsync("ReceiveMessage", user, message);

public async Task SendMessageToGroup(string user, string message)
    => await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);

Hub fortemente tipizzato

Uno svantaggio dell'uso SendAsync è che si basa su una stringa per specificare il metodo client da chiamare. In questo modo il codice viene aperto per gli errori di runtime se il nome del metodo è stato digitato in modo non corretto o mancante dal client.

Un'alternativa all'uso SendAsync consiste nel digitare fortemente la Hub classe con Hub<T>. Nell'esempio seguente il ChatHub metodo client è stato estratto in un'interfaccia denominata IChatClient:

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

Questa interfaccia può essere usata per effettuare il refactoring dell'esempio precedente ChatHub per essere fortemente tipizzato:

public class StronglyTypedChatHub : Hub<IChatClient>
{
    public async Task SendMessage(string user, string message)
        => await Clients.All.ReceiveMessage(user, message);

    public async Task SendMessageToCaller(string user, string message)
        => await Clients.Caller.ReceiveMessage(user, message);

    public async Task SendMessageToGroup(string user, string message)
        => await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}

L'uso Hub<IChatClient> di abilita il controllo in fase di compilazione dei metodi client. In questo modo si evitano problemi causati dall'uso di stringhe, poiché Hub<T> può fornire l'accesso solo ai metodi definiti nell'interfaccia . L'uso di un oggetto fortemente tipizzato Hub<T> disabilita la possibilità di usare SendAsync.

Nota

Il Async suffisso non viene rimosso dai nomi dei metodi. A meno che un metodo client non sia definito con .on('MyMethodAsync'), non usare MyMethodAsync come nome.

Risultati del client

Oltre a effettuare chiamate ai client, il server può richiedere un risultato da un client. Ciò richiede che il server usi ISingleClientProxy.InvokeAsync e che il client restituisca un risultato dal relativo .On gestore.

Esistono due modi per usare l'API nel server, la prima consiste nel chiamare Client(...) o Caller nella Clients proprietà in un metodo hub:

public class ChatHub : Hub
{
    public async Task<string> WaitForMessage(string connectionId)
    {
        var message = await Clients.Client(connectionId).InvokeAsync<string>(
            "GetMessage");
        return message;
    }
}

Il secondo modo consiste nel chiamare Client(...) su un'istanza di IHubContext<T>:

async Task SomeMethod(IHubContext<MyHub> context)
{
    string result = await context.Clients.Client(connectionID).InvokeAsync<string>(
        "GetMessage");
}

Gli hub fortemente tipizzati possono anche restituire valori dai metodi di interfaccia:

public interface IClient
{
    Task<string> GetMessage();
}

public class ChatHub : Hub<IClient>
{
    public async Task<string> WaitForMessage(string connectionId)
    {
        string message = await Clients.Client(connectionId).GetMessage();
        return message;
    }
}

I client restituiscono i risultati nei relativi .On(...) gestori, come illustrato di seguito:

Client .NET

hubConnection.On("GetMessage", async () =>
{
    Console.WriteLine("Enter message:");
    var message = await Console.In.ReadLineAsync();
    return message;
});

Client Typescript

hubConnection.on("GetMessage", async () => {
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("message");
        }, 100);
    });
    return promise;
});

Client Java

hubConnection.onWithResult("GetMessage", () -> {
    return Single.just("message");
});

Modificare il nome di un metodo hub

Per impostazione predefinita, il nome di un metodo hub server è il nome del metodo .NET. Per modificare questo comportamento predefinito per un metodo specifico, usare l'attributo HubMethodName . Il client deve usare questo nome anziché il nome del metodo .NET quando si richiama il metodo :

[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
    => await Clients.User(user).SendAsync("ReceiveMessage", user, message);

Inserire i servizi in un hub

I costruttori dell'hub possono accettare i servizi di inserimento delle dipendenze come parametri, che possono essere archiviati nelle proprietà della classe da usare in un metodo hub.

Quando si inserisce più servizi per metodi hub diversi o come modo alternativo di scrivere codice, i metodi hub possono anche accettare servizi dall'inserimento delle dipendenze. Per impostazione predefinita, i parametri del metodo hub vengono esaminati e risolti dall'inserimento delle dipendenze, se possibile.

services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();

// ...

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message, IDatabaseService dbService)
    {
        var userName = dbService.GetUserName(user);
        return Clients.All.SendAsync("ReceiveMessage", userName, message);
    }
}

Se la risoluzione implicita dei parametri dai servizi non è desiderata, disabilitarla con DisableImplicitFromServicesParameters. Per specificare in modo esplicito i parametri risolti dall'inserimento delle dipendenze nei metodi hub, usare l'opzione DisableImplicitFromServicesParameters e usare l'attributo o un attributo personalizzato che implementa IFromServiceMetadata nei parametri del metodo hub che devono essere risolti dall'inserimento [FromServices] delle dipendenze.

services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
services.AddSignalR(options =>
{
    options.DisableImplicitFromServicesParameters = true;
});

// ...

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message,
        [FromServices] IDatabaseService dbService)
    {
        var userName = dbService.GetUserName(user);
        return Clients.All.SendAsync("ReceiveMessage", userName, message);
    }
}

Nota

Questa funzionalità usa , che è facoltativamente implementato dalle implementazioni di IServiceProviderIsServiceinserimento delle dipendenze. Se il contenitore di inserimento delle dipendenze dell'app non supporta questa funzionalità, l'inserimento dei servizi nei metodi hub non è supportato.

Supporto dei servizi con chiave nell'inserimento delle dipendenze

I servizi con chiave fanno riferimento a un meccanismo per la registrazione e il recupero di servizi di inserimento delle dipendenze tramite chiavi. Un servizio è associato a una chiave chiamando AddKeyedSingleton (o AddKeyedScoped ) AddKeyedTransientper registrarlo. Accedere a un servizio registrato specificando la chiave con l'attributo [FromKeyedServices] . Il codice seguente illustra come usare i servizi con chiave:

using Microsoft.AspNetCore.SignalR;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");

builder.Services.AddRazorPages();
builder.Services.AddSignalR();

var app = builder.Build();

app.MapRazorPages();
app.MapHub<MyHub>("/myHub");

app.Run();

public interface ICache
{
    object Get(string key);
}
public class BigCache : ICache
{
    public object Get(string key) => $"Resolving {key} from big cache.";
}

public class SmallCache : ICache
{
    public object Get(string key) => $"Resolving {key} from small cache.";
}

public class MyHub : Hub
{
    public void SmallCacheMethod([FromKeyedServices("small")] ICache cache)
    {
        Console.WriteLine(cache.Get("signalr"));
    }

    public void BigCacheMethod([FromKeyedServices("big")] ICache cache)
    {
        Console.WriteLine(cache.Get("signalr"));
    }
}

Gestire gli eventi per una connessione

L'API SignalR Hubs fornisce i OnConnectedAsync metodi virtuali e OnDisconnectedAsync per gestire e tenere traccia delle connessioni. Eseguire l'override del OnConnectedAsync metodo virtuale per eseguire azioni quando un client si connette all'hub, ad esempio aggiungendolo a un gruppo:

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

Eseguire l'override del OnDisconnectedAsync metodo virtuale per eseguire azioni quando un client si disconnette. Se il client si disconnette intenzionalmente, ad esempio chiamando connection.stop(), il exception parametro viene impostato su null. Tuttavia, se il client si disconnette a causa di un errore, ad esempio un errore di rete, il exception parametro contiene un'eccezione che descrive l'errore:

public override async Task OnDisconnectedAsync(Exception? exception)
{
    await base.OnDisconnectedAsync(exception);
}

RemoveFromGroupAsync non deve essere chiamato in OnDisconnectedAsync, viene gestito automaticamente per l'utente.

Gestione degli errori

Le eccezioni generate nei metodi hub vengono inviate al client che ha richiamato il metodo . Nel client JavaScript il invoke metodo restituisce un codice JavaScript Promise. I client possono collegare un catch gestore alla promessa restituita o usarla trycatch/con async/await per gestire le eccezioni:

try {
  await connection.invoke("SendMessage", user, message);
} catch (err) {
  console.error(err);
}

Connessione non vengono chiuse quando un hub genera un'eccezione. Per impostazione predefinita, restituisce SignalR un messaggio di errore generico al client, come illustrato nell'esempio seguente:

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.

Le eccezioni impreviste contengono spesso informazioni riservate, ad esempio il nome di un server di database in un'eccezione attivata quando la connessione al database non riesce. SignalR non espone questi messaggi di errore dettagliati per impostazione predefinita come misura di sicurezza. Per altre informazioni sul motivo per cui i dettagli delle eccezioni vengono eliminati, vedere Considerazioni sulla sicurezza in ASP.NET Core SignalR.

Se è necessario propagare una condizione eccezionale al client, usare la HubException classe . Se viene generata un'eccezione HubException in un metodo hub, SignalRinvia l'intero messaggio di eccezione al client, non modificato:

public Task ThrowException()
    => throw new HubException("This error will be sent to the client!");

Nota

SignalR invia solo la Message proprietà dell'eccezione al client. L'analisi dello stack e altre proprietà sull'eccezione non sono disponibili per il client.

Risorse aggiuntive

Di Rachel Appel e Kevin Griffin

L'API SignalR Hubs consente ai client connessi di chiamare i metodi nel server. Il server definisce i metodi chiamati dal client e il client definisce i metodi chiamati dal server. SignalR si occupa di tutto ciò che è necessario per rendere possibile la comunicazione da client a server e da server a client in tempo reale.

Configurare SignalR hub

Per registrare i servizi richiesti dagli SignalR hub, chiamare AddSignalR in Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddSignalR();

Per configurare SignalR gli endpoint, chiamare MapHubanche in Program.cs:

app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");

app.Run();

Nota

ASP.NET assembly lato server Core SignalR sono ora installati con .NET Core SDK. Per altre informazioni, vedere SignalR assembly nel framework condiviso.

Creare e usare hub

Creare un hub dichiarando una classe che eredita da Hub. Aggiungere public metodi alla classe per renderli chiamabili dai client:

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
        => await Clients.All.SendAsync("ReceiveMessage", user, message);
}

Nota

Gli hub sono temporanei:

  • Non archiviare lo stato in una proprietà della classe hub. Ogni chiamata al metodo hub viene eseguita in una nuova istanza dell'hub.
  • Non creare un'istanza di un hub direttamente tramite l'inserimento delle dipendenze. Per inviare messaggi a un client da un'altra posizione nell'applicazione, usare un oggetto IHubContext.
  • Usare await quando si chiamano metodi asincroni che dipendono dall'hub che rimangono attivi. Ad esempio, un metodo come Clients.All.SendAsync(...) può non riuscire se viene chiamato senza await e il metodo hub viene completato prima SendAsync del completamento.

Oggetto Context

La Hub classe include una Context proprietà che contiene le proprietà seguenti con informazioni sulla connessione:

Proprietà Descrizione
ConnectionId Ottiene l'ID univoco per la connessione, assegnato da SignalR. Esiste un ID di connessione per ogni connessione.
UserIdentifier Ottiene l'identificatore utente. Per impostazione predefinita, SignalR usa l'oggetto ClaimTypes.NameIdentifier dell'oggetto ClaimsPrincipal associato alla connessione come identificatore utente.
User Ottiene l'oggetto ClaimsPrincipal associato all'utente corrente.
Items Ottiene una raccolta chiave/valore che può essere utilizzata per condividere i dati nell'ambito di questa connessione. I dati possono essere archiviati in questa raccolta e verranno mantenuti per la connessione tra diverse chiamate al metodo hub.
Features Ottiene la raccolta di funzionalità disponibili nella connessione. Per il momento, questa raccolta non è necessaria nella maggior parte degli scenari, quindi non è ancora documentata in dettaglio.
ConnectionAborted Ottiene un oggetto CancellationToken che notifica quando la connessione viene interrotta.

Hub.Context contiene anche i metodi seguenti:

metodo Descrizione
GetHttpContext Restituisce per HttpContext la connessione o null se la connessione non è associata a una richiesta HTTP. Per le connessioni HTTP, usare questo metodo per ottenere informazioni quali intestazioni HTTP e stringhe di query.
Abort Interrompe la connessione.

Oggetto Clients

La Hub classe include una Clients proprietà che contiene le proprietà seguenti per la comunicazione tra server e client:

Proprietà Descrizione
All Chiama un metodo su tutti i client connessi
Caller Chiama un metodo sul client che ha richiamato il metodo hub
Others Chiama un metodo su tutti i client connessi, ad eccezione del client che ha richiamato il metodo

Hub.Clients contiene anche i metodi seguenti:

metodo Descrizione
AllExcept Chiama un metodo su tutti i client connessi, ad eccezione delle connessioni specificate
Client Chiama un metodo in un client connesso specifico
Clients Chiama un metodo su client connessi specifici
Group Chiama un metodo su tutte le connessioni nel gruppo specificato
GroupExcept Chiama un metodo su tutte le connessioni nel gruppo specificato, ad eccezione delle connessioni specificate
Groups Chiama un metodo su più gruppi di connessioni
OthersInGroup Chiama un metodo su un gruppo di connessioni, escluso il client che ha richiamato il metodo hub
User Chiama un metodo su tutte le connessioni associate a un utente specifico
Users Chiama un metodo su tutte le connessioni associate agli utenti specificati

Ogni proprietà o metodo nelle tabelle precedenti restituisce un oggetto con un SendAsync metodo . Il SendAsync metodo riceve il nome del metodo client da chiamare ed eventuali parametri.

L'oggetto restituito dai Client metodi e Caller contiene anche un InvokeAsync metodo, che può essere utilizzato per attendere un risultato dal client.

Inviare messaggi ai client

Per effettuare chiamate a client specifici, utilizzare le proprietà dell'oggetto Clients . Nell'esempio seguente sono disponibili tre metodi hub:

  • SendMessage invia un messaggio a tutti i client connessi usando Clients.All.
  • SendMessageToCaller invia un messaggio al chiamante usando Clients.Caller.
  • SendMessageToGroup invia un messaggio a tutti i client del SignalR Users gruppo.
public async Task SendMessage(string user, string message)
    => await Clients.All.SendAsync("ReceiveMessage", user, message);

public async Task SendMessageToCaller(string user, string message)
    => await Clients.Caller.SendAsync("ReceiveMessage", user, message);

public async Task SendMessageToGroup(string user, string message)
    => await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);

Hub fortemente tipizzato

Uno svantaggio dell'uso SendAsync è che si basa su una stringa per specificare il metodo client da chiamare. In questo modo il codice viene aperto per gli errori di runtime se il nome del metodo è stato digitato in modo non corretto o mancante dal client.

Un'alternativa all'uso SendAsync consiste nel digitare fortemente la Hub classe con Hub<T>. Nell'esempio seguente il ChatHub metodo client è stato estratto in un'interfaccia denominata IChatClient:

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

Questa interfaccia può essere usata per effettuare il refactoring dell'esempio precedente ChatHub per essere fortemente tipizzato:

public class StronglyTypedChatHub : Hub<IChatClient>
{
    public async Task SendMessage(string user, string message)
        => await Clients.All.ReceiveMessage(user, message);

    public async Task SendMessageToCaller(string user, string message)
        => await Clients.Caller.ReceiveMessage(user, message);

    public async Task SendMessageToGroup(string user, string message)
        => await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}

L'uso Hub<IChatClient> di abilita il controllo in fase di compilazione dei metodi client. In questo modo si evitano problemi causati dall'uso di stringhe, poiché Hub<T> può fornire l'accesso solo ai metodi definiti nell'interfaccia . L'uso di un oggetto fortemente tipizzato Hub<T> disabilita la possibilità di usare SendAsync.

Nota

Il Async suffisso non viene rimosso dai nomi dei metodi. A meno che un metodo client non sia definito con .on('MyMethodAsync'), non usare MyMethodAsync come nome.

Risultati del client

Oltre a effettuare chiamate ai client, il server può richiedere un risultato da un client. Ciò richiede che il server usi ISingleClientProxy.InvokeAsync e che il client restituisca un risultato dal relativo .On gestore.

Esistono due modi per usare l'API nel server, la prima consiste nel chiamare Client(...) o Caller nella Clients proprietà in un metodo hub:

public class ChatHub : Hub
{
    public async Task<string> WaitForMessage(string connectionId)
    {
        var message = await Clients.Client(connectionId).InvokeAsync<string>(
            "GetMessage");
        return message;
    }
}

Il secondo modo consiste nel chiamare Client(...) su un'istanza di IHubContext<T>:

async Task SomeMethod(IHubContext<MyHub> context)
{
    string result = await context.Clients.Client(connectionID).InvokeAsync<string>(
        "GetMessage");
}

Gli hub fortemente tipizzati possono anche restituire valori dai metodi di interfaccia:

public interface IClient
{
    Task<string> GetMessage();
}

public class ChatHub : Hub<IClient>
{
    public async Task<string> WaitForMessage(string connectionId)
    {
        string message = await Clients.Client(connectionId).GetMessage();
        return message;
    }
}

I client restituiscono i risultati nei relativi .On(...) gestori, come illustrato di seguito:

Client .NET

hubConnection.On("GetMessage", async () =>
{
    Console.WriteLine("Enter message:");
    var message = await Console.In.ReadLineAsync();
    return message;
});

Client Typescript

hubConnection.on("GetMessage", async () => {
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("message");
        }, 100);
    });
    return promise;
});

Client Java

hubConnection.onWithResult("GetMessage", () -> {
    return Single.just("message");
});

Modificare il nome di un metodo hub

Per impostazione predefinita, il nome di un metodo hub server è il nome del metodo .NET. Per modificare questo comportamento predefinito per un metodo specifico, usare l'attributo HubMethodName . Il client deve usare questo nome anziché il nome del metodo .NET quando si richiama il metodo :

[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
    => await Clients.User(user).SendAsync("ReceiveMessage", user, message);

Inserire i servizi in un hub

I costruttori dell'hub possono accettare i servizi di inserimento delle dipendenze come parametri, che possono essere archiviati nelle proprietà della classe da usare in un metodo hub.

Quando si inserisce più servizi per metodi hub diversi o come modo alternativo di scrivere codice, i metodi hub possono anche accettare servizi dall'inserimento delle dipendenze. Per impostazione predefinita, i parametri del metodo hub vengono esaminati e risolti dall'inserimento delle dipendenze, se possibile.

services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();

// ...

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message, IDatabaseService dbService)
    {
        var userName = dbService.GetUserName(user);
        return Clients.All.SendAsync("ReceiveMessage", userName, message);
    }
}

Se la risoluzione implicita dei parametri dai servizi non è desiderata, disabilitarla con DisableImplicitFromServicesParameters. Per specificare in modo esplicito i parametri risolti dall'inserimento delle dipendenze nei metodi hub, usare l'opzione DisableImplicitFromServicesParameters e usare l'attributo o un attributo personalizzato che implementa IFromServiceMetadata nei parametri del metodo hub che devono essere risolti dall'inserimento [FromServices] delle dipendenze.

services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
services.AddSignalR(options =>
{
    options.DisableImplicitFromServicesParameters = true;
});

// ...

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message,
        [FromServices] IDatabaseService dbService)
    {
        var userName = dbService.GetUserName(user);
        return Clients.All.SendAsync("ReceiveMessage", userName, message);
    }
}

Nota

Questa funzionalità usa , che è facoltativamente implementato dalle implementazioni di IServiceProviderIsServiceinserimento delle dipendenze. Se il contenitore di inserimento delle dipendenze dell'app non supporta questa funzionalità, l'inserimento dei servizi nei metodi hub non è supportato.

Gestire gli eventi per una connessione

L'API SignalR Hubs fornisce i OnConnectedAsync metodi virtuali e OnDisconnectedAsync per gestire e tenere traccia delle connessioni. Eseguire l'override del OnConnectedAsync metodo virtuale per eseguire azioni quando un client si connette all'hub, ad esempio aggiungendolo a un gruppo:

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

Eseguire l'override del OnDisconnectedAsync metodo virtuale per eseguire azioni quando un client si disconnette. Se il client si disconnette intenzionalmente, ad esempio chiamando connection.stop(), il exception parametro viene impostato su null. Tuttavia, se il client si disconnette a causa di un errore, ad esempio un errore di rete, il exception parametro contiene un'eccezione che descrive l'errore:

public override async Task OnDisconnectedAsync(Exception? exception)
{
    await base.OnDisconnectedAsync(exception);
}

RemoveFromGroupAsync non deve essere chiamato in OnDisconnectedAsync, viene gestito automaticamente per l'utente.

Gestione degli errori

Le eccezioni generate nei metodi hub vengono inviate al client che ha richiamato il metodo . Nel client JavaScript il invoke metodo restituisce un codice JavaScript Promise. I client possono collegare un catch gestore alla promessa restituita o usarla trycatch/con async/await per gestire le eccezioni:

try {
  await connection.invoke("SendMessage", user, message);
} catch (err) {
  console.error(err);
}

Connessione non vengono chiuse quando un hub genera un'eccezione. Per impostazione predefinita, restituisce SignalR un messaggio di errore generico al client, come illustrato nell'esempio seguente:

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.

Le eccezioni impreviste contengono spesso informazioni riservate, ad esempio il nome di un server di database in un'eccezione attivata quando la connessione al database non riesce. SignalR non espone questi messaggi di errore dettagliati per impostazione predefinita come misura di sicurezza. Per altre informazioni sul motivo per cui i dettagli delle eccezioni vengono eliminati, vedere Considerazioni sulla sicurezza in ASP.NET Core SignalR.

Se è necessario propagare una condizione eccezionale al client, usare la HubException classe . Se viene generata un'eccezione HubException in un metodo hub, SignalRinvia l'intero messaggio di eccezione al client, non modificato:

public Task ThrowException()
    => throw new HubException("This error will be sent to the client!");

Nota

SignalR invia solo la Message proprietà dell'eccezione al client. L'analisi dello stack e altre proprietà sull'eccezione non sono disponibili per il client.

Risorse aggiuntive

Di Rachel Appel e Kevin Griffin

L'API SignalR Hubs consente ai client connessi di chiamare i metodi nel server. Il server definisce i metodi chiamati dal client e il client definisce i metodi chiamati dal server. SignalR si occupa di tutto ciò che è necessario per rendere possibile la comunicazione da client a server e da server a client in tempo reale.

Configurare SignalR hub

Per registrare i servizi richiesti dagli SignalR hub, chiamare AddSignalR in Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddSignalR();

Per configurare SignalR gli endpoint, chiamare MapHubanche in Program.cs:

app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");

app.Run();

Nota

ASP.NET assembly lato server Core SignalR sono ora installati con .NET Core SDK. Per altre informazioni, vedere SignalR assembly nel framework condiviso.

Creare e usare hub

Creare un hub dichiarando una classe che eredita da Hub. Aggiungere public metodi alla classe per renderli chiamabili dai client:

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
        => await Clients.All.SendAsync("ReceiveMessage", user, message);
}

Nota

Gli hub sono temporanei:

  • Non archiviare lo stato in una proprietà della classe hub. Ogni chiamata al metodo hub viene eseguita in una nuova istanza dell'hub.
  • Non creare un'istanza di un hub direttamente tramite l'inserimento delle dipendenze. Per inviare messaggi a un client da un'altra posizione nell'applicazione, usare un oggetto IHubContext.
  • Usare await quando si chiamano metodi asincroni che dipendono dall'hub che rimangono attivi. Ad esempio, un metodo come Clients.All.SendAsync(...) può non riuscire se viene chiamato senza await e il metodo hub viene completato prima SendAsync del completamento.

Oggetto Context

La Hub classe include una Context proprietà che contiene le proprietà seguenti con informazioni sulla connessione:

Proprietà Descrizione
ConnectionId Ottiene l'ID univoco per la connessione, assegnato da SignalR. Esiste un ID di connessione per ogni connessione.
UserIdentifier Ottiene l'identificatore utente. Per impostazione predefinita, SignalR usa l'oggetto ClaimTypes.NameIdentifier dell'oggetto ClaimsPrincipal associato alla connessione come identificatore utente.
User Ottiene l'oggetto ClaimsPrincipal associato all'utente corrente.
Items Ottiene una raccolta chiave/valore che può essere utilizzata per condividere i dati nell'ambito di questa connessione. I dati possono essere archiviati in questa raccolta e verranno mantenuti per la connessione tra diverse chiamate al metodo hub.
Features Ottiene la raccolta di funzionalità disponibili nella connessione. Per il momento, questa raccolta non è necessaria nella maggior parte degli scenari, quindi non è ancora documentata in dettaglio.
ConnectionAborted Ottiene un oggetto CancellationToken che notifica quando la connessione viene interrotta.

Hub.Context contiene anche i metodi seguenti:

metodo Descrizione
GetHttpContext Restituisce per HttpContext la connessione o null se la connessione non è associata a una richiesta HTTP. Per le connessioni HTTP, usare questo metodo per ottenere informazioni quali intestazioni HTTP e stringhe di query.
Abort Interrompe la connessione.

Oggetto Clients

La Hub classe include una Clients proprietà che contiene le proprietà seguenti per la comunicazione tra server e client:

Proprietà Descrizione
All Chiama un metodo su tutti i client connessi
Caller Chiama un metodo sul client che ha richiamato il metodo hub
Others Chiama un metodo su tutti i client connessi, ad eccezione del client che ha richiamato il metodo

Hub.Clients contiene anche i metodi seguenti:

metodo Descrizione
AllExcept Chiama un metodo su tutti i client connessi, ad eccezione delle connessioni specificate
Client Chiama un metodo in un client connesso specifico
Clients Chiama un metodo su client connessi specifici
Group Chiama un metodo su tutte le connessioni nel gruppo specificato
GroupExcept Chiama un metodo su tutte le connessioni nel gruppo specificato, ad eccezione delle connessioni specificate
Groups Chiama un metodo su più gruppi di connessioni
OthersInGroup Chiama un metodo su un gruppo di connessioni, escluso il client che ha richiamato il metodo hub
User Chiama un metodo su tutte le connessioni associate a un utente specifico
Users Chiama un metodo su tutte le connessioni associate agli utenti specificati

Ogni proprietà o metodo nelle tabelle precedenti restituisce un oggetto con un SendAsync metodo . Il SendAsync metodo riceve il nome del metodo client da chiamare ed eventuali parametri.

Inviare messaggi ai client

Per effettuare chiamate a client specifici, utilizzare le proprietà dell'oggetto Clients . Nell'esempio seguente sono disponibili tre metodi hub:

  • SendMessage invia un messaggio a tutti i client connessi usando Clients.All.
  • SendMessageToCaller invia un messaggio al chiamante usando Clients.Caller.
  • SendMessageToGroup invia un messaggio a tutti i client del SignalR Users gruppo.
public async Task SendMessage(string user, string message)
    => await Clients.All.SendAsync("ReceiveMessage", user, message);

public async Task SendMessageToCaller(string user, string message)
    => await Clients.Caller.SendAsync("ReceiveMessage", user, message);

public async Task SendMessageToGroup(string user, string message)
    => await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);

Hub fortemente tipizzato

Uno svantaggio dell'uso SendAsync è che si basa su una stringa per specificare il metodo client da chiamare. In questo modo il codice viene aperto per gli errori di runtime se il nome del metodo è stato digitato in modo non corretto o mancante dal client.

Un'alternativa all'uso SendAsync consiste nel digitare fortemente la Hub classe con Hub<T>. Nell'esempio seguente il ChatHub metodo client è stato estratto in un'interfaccia denominata IChatClient:

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

Questa interfaccia può essere usata per effettuare il refactoring dell'esempio precedente ChatHub per essere fortemente tipizzato:

public class StronglyTypedChatHub : Hub<IChatClient>
{
    public async Task SendMessage(string user, string message)
        => await Clients.All.ReceiveMessage(user, message);

    public async Task SendMessageToCaller(string user, string message)
        => await Clients.Caller.ReceiveMessage(user, message);

    public async Task SendMessageToGroup(string user, string message)
        => await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}

L'uso Hub<IChatClient> di abilita il controllo in fase di compilazione dei metodi client. In questo modo si evitano problemi causati dall'uso di stringhe, poiché Hub<T> può fornire l'accesso solo ai metodi definiti nell'interfaccia . L'uso di un oggetto fortemente tipizzato Hub<T> disabilita la possibilità di usare SendAsync.

Nota

Il Async suffisso non viene rimosso dai nomi dei metodi. A meno che un metodo client non sia definito con .on('MyMethodAsync'), non usare MyMethodAsync come nome.

Modificare il nome di un metodo hub

Per impostazione predefinita, il nome di un metodo hub server è il nome del metodo .NET. Per modificare questo comportamento predefinito per un metodo specifico, usare l'attributo HubMethodName . Il client deve usare questo nome anziché il nome del metodo .NET quando si richiama il metodo :

[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
    => await Clients.User(user).SendAsync("ReceiveMessage", user, message);

Gestire gli eventi per una connessione

L'API SignalR Hubs fornisce i OnConnectedAsync metodi virtuali e OnDisconnectedAsync per gestire e tenere traccia delle connessioni. Eseguire l'override del OnConnectedAsync metodo virtuale per eseguire azioni quando un client si connette all'hub, ad esempio aggiungendolo a un gruppo:

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

Eseguire l'override del OnDisconnectedAsync metodo virtuale per eseguire azioni quando un client si disconnette. Se il client si disconnette intenzionalmente, ad esempio chiamando connection.stop(), il exception parametro viene impostato su null. Tuttavia, se il client si disconnette a causa di un errore, ad esempio un errore di rete, il exception parametro contiene un'eccezione che descrive l'errore:

public override async Task OnDisconnectedAsync(Exception? exception)
{
    await base.OnDisconnectedAsync(exception);
}

RemoveFromGroupAsync non deve essere chiamato in OnDisconnectedAsync, viene gestito automaticamente per l'utente.

Gestione degli errori

Le eccezioni generate nei metodi hub vengono inviate al client che ha richiamato il metodo . Nel client JavaScript il invoke metodo restituisce un codice JavaScript Promise. I client possono collegare un catch gestore alla promessa restituita o usarla trycatch/con async/await per gestire le eccezioni:

try {
  await connection.invoke("SendMessage", user, message);
} catch (err) {
  console.error(err);
}

Connessione non vengono chiuse quando un hub genera un'eccezione. Per impostazione predefinita, restituisce SignalR un messaggio di errore generico al client, come illustrato nell'esempio seguente:

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.

Le eccezioni impreviste contengono spesso informazioni riservate, ad esempio il nome di un server di database in un'eccezione attivata quando la connessione al database non riesce. SignalR non espone questi messaggi di errore dettagliati per impostazione predefinita come misura di sicurezza. Per altre informazioni sul motivo per cui i dettagli delle eccezioni vengono eliminati, vedere Considerazioni sulla sicurezza in ASP.NET Core SignalR.

Se è necessario propagare una condizione eccezionale al client, usare la HubException classe . Se viene generata un'eccezione HubException in un metodo hub, SignalRinvia l'intero messaggio di eccezione al client, non modificato:

public Task ThrowException()
    => throw new HubException("This error will be sent to the client!");

Nota

SignalR invia solo la Message proprietà dell'eccezione al client. L'analisi dello stack e altre proprietà sull'eccezione non sono disponibili per il client.

Risorse aggiuntive

Di Rachel Appel e Kevin Griffin

Visualizzare o scaricare il codice di esempio (come scaricare)

Che cos'è un SignalR hub

L'API SignalR Hubs consente di chiamare i metodi nei client connessi dal server. Nel codice del server si definiscono i metodi chiamati dal client. Nel codice client si definiscono i metodi chiamati dal server. SignalR si occupa di tutto ciò che è dietro le quinte che rende possibili comunicazioni da client a server e da server a client in tempo reale.

Configurare SignalR hub

Il SignalR middleware richiede alcuni servizi, configurati chiamando AddSignalR:

services.AddSignalR();

Quando si aggiungono SignalR funzionalità a un'app ASP.NET Core, configurare SignalR le route chiamando MapHub nel Startup.Configure callback del UseEndpoints metodo:

app.UseRouting();
app.UseEndpoints(endpoints =>
{
    endpoints.MapHub<ChatHub>("/chathub");
});

Nota

ASP.NET assembly lato server Core SignalR sono ora installati con .NET Core SDK. Per altre informazioni, vedere SignalR assembly nel framework condiviso.

Creare e usare hub

Creare un hub dichiarando una classe che eredita da Hube aggiungendo metodi pubblici. I client possono chiamare metodi definiti come public:

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message)
    {
        return Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

È possibile specificare un tipo restituito e parametri, inclusi tipi complessi e matrici, come in qualsiasi metodo C#. SignalR gestisce la serializzazione e la deserializzazione di oggetti e matrici complessi nei parametri e nei valori restituiti.

Nota

Gli hub sono temporanei:

  • Non archiviare lo stato in una proprietà nella classe hub. Ogni chiamata al metodo hub viene eseguita in una nuova istanza dell'hub.
  • Non creare un'istanza di un hub direttamente tramite l'inserimento delle dipendenze. Per inviare messaggi a un client da un'altra posizione nell'applicazione, usare un oggetto IHubContext.
  • Usare await quando si chiamano metodi asincroni che dipendono dall'hub che rimangono attivi. Ad esempio, un metodo come Clients.All.SendAsync(...) può non riuscire se viene chiamato senza await e il metodo hub viene completato prima SendAsync del completamento.

Oggetto Context

La Hub classe ha una Context proprietà che contiene le proprietà seguenti con informazioni sulla connessione:

Proprietà Descrizione
ConnectionId Ottiene l'ID univoco per la connessione, assegnato da SignalR. Esiste un ID di connessione per ogni connessione.
UserIdentifier Ottiene l'identificatore utente. Per impostazione predefinita, SignalR usa l'oggetto ClaimTypes.NameIdentifier dell'oggetto ClaimsPrincipal associato alla connessione come identificatore utente.
User Ottiene l'oggetto ClaimsPrincipal associato all'utente corrente.
Items Ottiene una raccolta chiave/valore che può essere utilizzata per condividere i dati nell'ambito di questa connessione. I dati possono essere archiviati in questa raccolta e verranno mantenuti per la connessione tra diverse chiamate al metodo hub.
Features Ottiene la raccolta di funzionalità disponibili nella connessione. Per il momento, questa raccolta non è necessaria nella maggior parte degli scenari, quindi non è ancora documentata in dettaglio.
ConnectionAborted Ottiene un oggetto CancellationToken che notifica quando la connessione viene interrotta.

Hub.Context contiene anche i metodi seguenti:

metodo Descrizione
GetHttpContext Restituisce per HttpContext la connessione o null se la connessione non è associata a una richiesta HTTP. Per le connessioni HTTP, è possibile usare questo metodo per ottenere informazioni quali intestazioni HTTP e stringhe di query.
Abort Interrompe la connessione.

Oggetto Clients

La Hub classe ha una Clients proprietà che contiene le proprietà seguenti per la comunicazione tra server e client:

Proprietà Descrizione
All Chiama un metodo su tutti i client connessi
Caller Chiama un metodo sul client che ha richiamato il metodo hub
Others Chiama un metodo su tutti i client connessi, ad eccezione del client che ha richiamato il metodo

Hub.Clients contiene anche i metodi seguenti:

metodo Descrizione
AllExcept Chiama un metodo su tutti i client connessi, ad eccezione delle connessioni specificate
Client Chiama un metodo in un client connesso specifico
Clients Chiama un metodo su client connessi specifici
Group Chiama un metodo su tutte le connessioni nel gruppo specificato
GroupExcept Chiama un metodo su tutte le connessioni nel gruppo specificato, ad eccezione delle connessioni specificate
Groups Chiama un metodo su più gruppi di connessioni
OthersInGroup Chiama un metodo su un gruppo di connessioni, escluso il client che ha richiamato il metodo hub
User Chiama un metodo su tutte le connessioni associate a un utente specifico
Users Chiama un metodo su tutte le connessioni associate agli utenti specificati

Ogni proprietà o metodo nelle tabelle precedenti restituisce un oggetto con un SendAsync metodo . Il SendAsync metodo consente di specificare il nome e i parametri del metodo client da chiamare.

Inviare messaggi ai client

Per effettuare chiamate a client specifici, utilizzare le proprietà dell'oggetto Clients . Nell'esempio seguente sono disponibili tre metodi hub:

  • SendMessage invia un messaggio a tutti i client connessi usando Clients.All.
  • SendMessageToCaller invia un messaggio al chiamante usando Clients.Caller.
  • SendMessageToGroup invia un messaggio a tutti i client del SignalR Users gruppo.
public Task SendMessage(string user, string message)
{
    return Clients.All.SendAsync("ReceiveMessage", user, message);
}

public Task SendMessageToCaller(string user, string message)
{
    return Clients.Caller.SendAsync("ReceiveMessage", user, message);
}

public Task SendMessageToGroup(string user, string message)
{
    return Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
}

Hub fortemente tipizzato

Uno svantaggio dell'uso SendAsync è che si basa su una stringa magic per specificare il metodo client da chiamare. In questo modo il codice viene aperto per gli errori di runtime se il nome del metodo è stato digitato in modo non corretto o mancante dal client.

Un'alternativa all'uso SendAsync consiste nel digitare fortemente con HubHub<T>. Nell'esempio seguente i ChatHub metodi client sono stati estratti in un'interfaccia denominata IChatClient.

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

Questa interfaccia può essere usata per effettuare il refactoring dell'esempio precedente ChatHub :

    public class StronglyTypedChatHub : Hub<IChatClient>
    {
        public async Task SendMessage(string user, string message)
        {
            await Clients.All.ReceiveMessage(user, message);
        }

        public Task SendMessageToCaller(string user, string message)
        {
            return Clients.Caller.ReceiveMessage(user, message);
        }
}

L'uso Hub<IChatClient> di abilita il controllo in fase di compilazione dei metodi client. In questo modo si evitano problemi causati dall'uso di stringhe magic, poiché Hub<T> può fornire l'accesso solo ai metodi definiti nell'interfaccia.

L'uso di un oggetto fortemente tipizzato Hub<T> disabilita la possibilità di usare SendAsync. Tutti i metodi definiti nell'interfaccia possono comunque essere definiti come asincroni. In effetti, ognuno di questi metodi deve restituire un oggetto Task. Poiché si tratta di un'interfaccia, non usare la async parola chiave . Ad esempio:

public interface IClient
{
    Task ClientMethod();
}

Nota

Il Async suffisso non viene rimosso dal nome del metodo. A meno che il metodo client non sia definito con .on('MyMethodAsync'), non è consigliabile usare MyMethodAsync come nome.

Modificare il nome di un metodo hub

Per impostazione predefinita, il nome di un metodo hub server è il nome del metodo .NET. Tuttavia, è possibile usare l'attributo HubMethodName per modificare questo valore predefinito e specificare manualmente un nome per il metodo. Il client deve usare questo nome, anziché il nome del metodo .NET, quando si richiama il metodo :

[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
    return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}

Gestire gli eventi per una connessione

L'API SignalR Hubs fornisce i OnConnectedAsync metodi virtuali e OnDisconnectedAsync per gestire e tenere traccia delle connessioni. Eseguire l'override del OnConnectedAsync metodo virtuale per eseguire azioni quando un client si connette all'hub, ad esempio aggiungendolo a un gruppo:

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

Eseguire l'override del OnDisconnectedAsync metodo virtuale per eseguire azioni quando un client si disconnette. Se il client si disconnette intenzionalmente (chiamando connection.stop(), ad esempio), il exception parametro sarà null. Tuttavia, se il client è disconnesso a causa di un errore (ad esempio un errore di rete), il exception parametro conterrà un'eccezione che descrive l'errore:

public override async Task OnDisconnectedAsync(Exception exception)
{
    await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
    await base.OnDisconnectedAsync(exception);
}

RemoveFromGroupAsync non deve essere chiamato in OnDisconnectedAsync, viene gestito automaticamente per l'utente.

Avviso

Avviso di sicurezza: l'esposizione ConnectionId può causare una rappresentazione dannosa se la versione del server o del SignalR client è ASP.NET Core 2.2 o versioni precedenti.

Gestione degli errori

Le eccezioni generate nei metodi hub vengono inviate al client che ha richiamato il metodo . Nel client JavaScript il invoke metodo restituisce un codice JavaScript Promise. Quando il client riceve un errore con un gestore associato alla promessa usando catch, viene richiamato e passato come oggetto JavaScript Error :

connection.invoke("SendMessage", user, message).catch(err => console.error(err));

Se l'hub genera un'eccezione, le connessioni non vengono chiuse. Per impostazione predefinita, restituisce SignalR un messaggio di errore generico al client. Ad esempio:

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'MethodName' on the server.

Le eccezioni impreviste contengono spesso informazioni riservate, ad esempio il nome di un server di database in un'eccezione attivata quando la connessione al database non riesce. SignalR non espone questi messaggi di errore dettagliati per impostazione predefinita come misura di sicurezza. Per altre informazioni sul motivo per cui i dettagli delle eccezioni vengono eliminati, vedere Considerazioni sulla sicurezza in ASP.NET Core SignalR.

Se si ha una condizione eccezionale che si vuole propagare al client, è possibile usare la HubException classe . Se si genera un oggetto HubException dal metodo hub, SignalRinvierà l'intero messaggio al client, senza modifiche:

public Task ThrowException()
{
    throw new HubException("This error will be sent to the client!");
}

Nota

SignalR invia solo la Message proprietà dell'eccezione al client. L'analisi dello stack e altre proprietà sull'eccezione non sono disponibili per il client.

Risorse aggiuntive

Di Rachel Appel e Kevin Griffin

Visualizzare o scaricare il codice di esempio (come scaricare)

Che cos'è un SignalR hub

L'API SignalR Hubs consente di chiamare i metodi nei client connessi dal server. Nel codice del server si definiscono i metodi chiamati dal client. Nel codice client si definiscono i metodi chiamati dal server. SignalR si occupa di tutto ciò che è dietro le quinte che rende possibili comunicazioni da client a server e da server a client in tempo reale.

Configurare SignalR hub

Il SignalR middleware richiede alcuni servizi, configurati chiamando AddSignalR:

services.AddSignalR();

Quando si aggiungono SignalR funzionalità a un'app ASP.NET Core, configurare SignalR le route chiamando UseSignalR nel Startup.Configure metodo :

app.UseSignalR(route =>
{
    route.MapHub<ChatHub>("/chathub");
});

Creare e usare hub

Creare un hub dichiarando una classe che eredita da Hube aggiungendo metodi pubblici. I client possono chiamare metodi definiti come public:

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message)
    {
        return Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

È possibile specificare un tipo restituito e parametri, inclusi tipi complessi e matrici, come in qualsiasi metodo C#. SignalR gestisce la serializzazione e la deserializzazione di oggetti e matrici complessi nei parametri e nei valori restituiti.

Nota

Gli hub sono temporanei:

  • Non archiviare lo stato in una proprietà nella classe hub. Ogni chiamata al metodo hub viene eseguita in una nuova istanza dell'hub.
  • Non creare un'istanza di un hub direttamente tramite l'inserimento delle dipendenze. Per inviare messaggi a un client da un'altra posizione nell'applicazione, usare un oggetto IHubContext.
  • Usare await quando si chiamano metodi asincroni che dipendono dall'hub che rimangono attivi. Ad esempio, un metodo come Clients.All.SendAsync(...) può non riuscire se viene chiamato senza await e il metodo hub viene completato prima SendAsync del completamento.

Oggetto Context

La Hub classe ha una Context proprietà che contiene le proprietà seguenti con informazioni sulla connessione:

Proprietà Descrizione
ConnectionId Ottiene l'ID univoco per la connessione, assegnato da SignalR. Esiste un ID di connessione per ogni connessione.
UserIdentifier Ottiene l'identificatore utente. Per impostazione predefinita, SignalR usa l'oggetto ClaimTypes.NameIdentifier dell'oggetto ClaimsPrincipal associato alla connessione come identificatore utente.
User Ottiene l'oggetto ClaimsPrincipal associato all'utente corrente.
Items Ottiene una raccolta chiave/valore che può essere utilizzata per condividere i dati nell'ambito di questa connessione. I dati possono essere archiviati in questa raccolta e verranno mantenuti per la connessione tra diverse chiamate al metodo hub.
Features Ottiene la raccolta di funzionalità disponibili nella connessione. Per il momento, questa raccolta non è necessaria nella maggior parte degli scenari, quindi non è ancora documentata in dettaglio.
ConnectionAborted Ottiene un oggetto CancellationToken che notifica quando la connessione viene interrotta.

Hub.Context contiene anche i metodi seguenti:

metodo Descrizione
GetHttpContext Restituisce per HttpContext la connessione o null se la connessione non è associata a una richiesta HTTP. Per le connessioni HTTP, è possibile usare questo metodo per ottenere informazioni quali intestazioni HTTP e stringhe di query.
Abort Interrompe la connessione.

Oggetto Clients

La Hub classe ha una Clients proprietà che contiene le proprietà seguenti per la comunicazione tra server e client:

Proprietà Descrizione
All Chiama un metodo su tutti i client connessi
Caller Chiama un metodo sul client che ha richiamato il metodo hub
Others Chiama un metodo su tutti i client connessi, ad eccezione del client che ha richiamato il metodo

Hub.Clients contiene anche i metodi seguenti:

metodo Descrizione
AllExcept Chiama un metodo su tutti i client connessi, ad eccezione delle connessioni specificate
Client Chiama un metodo in un client connesso specifico
Clients Chiama un metodo su client connessi specifici
Group Chiama un metodo su tutte le connessioni nel gruppo specificato
GroupExcept Chiama un metodo su tutte le connessioni nel gruppo specificato, ad eccezione delle connessioni specificate
Groups Chiama un metodo su più gruppi di connessioni
OthersInGroup Chiama un metodo su un gruppo di connessioni, escluso il client che ha richiamato il metodo hub
User Chiama un metodo su tutte le connessioni associate a un utente specifico
Users Chiama un metodo su tutte le connessioni associate agli utenti specificati

Ogni proprietà o metodo nelle tabelle precedenti restituisce un oggetto con un SendAsync metodo . Il SendAsync metodo consente di specificare il nome e i parametri del metodo client da chiamare.

Inviare messaggi ai client

Per effettuare chiamate a client specifici, utilizzare le proprietà dell'oggetto Clients . Nell'esempio seguente sono disponibili tre metodi hub:

  • SendMessage invia un messaggio a tutti i client connessi usando Clients.All.
  • SendMessageToCaller invia un messaggio al chiamante usando Clients.Caller.
  • SendMessageToGroup invia un messaggio a tutti i client del SignalR Users gruppo.
public Task SendMessage(string user, string message)
{
    return Clients.All.SendAsync("ReceiveMessage", user, message);
}

public Task SendMessageToCaller(string user, string message)
{
    return Clients.Caller.SendAsync("ReceiveMessage", user, message);
}

public Task SendMessageToGroup(string user, string message)
{
    return Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
}

Hub fortemente tipizzato

Uno svantaggio dell'uso SendAsync è che si basa su una stringa magic per specificare il metodo client da chiamare. In questo modo il codice viene aperto per gli errori di runtime se il nome del metodo è stato digitato in modo non corretto o mancante dal client.

Un'alternativa all'uso SendAsync consiste nel digitare fortemente con HubHub<T>. Nell'esempio seguente i ChatHub metodi client sono stati estratti in un'interfaccia denominata IChatClient.

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

Questa interfaccia può essere usata per effettuare il refactoring dell'esempio precedente ChatHub :

    public class StronglyTypedChatHub : Hub<IChatClient>
    {
        public async Task SendMessage(string user, string message)
        {
            await Clients.All.ReceiveMessage(user, message);
        }

        public Task SendMessageToCaller(string user, string message)
        {
            return Clients.Caller.ReceiveMessage(user, message);
        }
}

L'uso Hub<IChatClient> di abilita il controllo in fase di compilazione dei metodi client. In questo modo si evitano problemi causati dall'uso di stringhe magic, poiché Hub<T> può fornire l'accesso solo ai metodi definiti nell'interfaccia.

L'uso di un oggetto fortemente tipizzato Hub<T> disabilita la possibilità di usare SendAsync. Tutti i metodi definiti nell'interfaccia possono comunque essere definiti come asincroni. In effetti, ognuno di questi metodi deve restituire un oggetto Task. Poiché si tratta di un'interfaccia, non usare la async parola chiave . Ad esempio:

public interface IClient
{
    Task ClientMethod();
}

Nota

Il Async suffisso non viene rimosso dal nome del metodo. A meno che il metodo client non sia definito con .on('MyMethodAsync'), non è consigliabile usare MyMethodAsync come nome.

Modificare il nome di un metodo hub

Per impostazione predefinita, il nome di un metodo hub server è il nome del metodo .NET. Tuttavia, è possibile usare l'attributo HubMethodName per modificare questo valore predefinito e specificare manualmente un nome per il metodo. Il client deve usare questo nome, anziché il nome del metodo .NET, quando si richiama il metodo :

[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
    return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}

Gestire gli eventi per una connessione

L'API SignalR Hubs fornisce i OnConnectedAsync metodi virtuali e OnDisconnectedAsync per gestire e tenere traccia delle connessioni. Eseguire l'override del OnConnectedAsync metodo virtuale per eseguire azioni quando un client si connette all'hub, ad esempio aggiungendolo a un gruppo:

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

Eseguire l'override del OnDisconnectedAsync metodo virtuale per eseguire azioni quando un client si disconnette. Se il client si disconnette intenzionalmente (chiamando connection.stop(), ad esempio), il exception parametro sarà null. Tuttavia, se il client è disconnesso a causa di un errore (ad esempio un errore di rete), il exception parametro conterrà un'eccezione che descrive l'errore:

public override async Task OnDisconnectedAsync(Exception exception)
{
    await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
    await base.OnDisconnectedAsync(exception);
}

RemoveFromGroupAsync non deve essere chiamato in OnDisconnectedAsync, viene gestito automaticamente per l'utente.

Avviso

Avviso di sicurezza: l'esposizione ConnectionId può causare una rappresentazione dannosa se la versione del server o del SignalR client è ASP.NET Core 2.2 o versioni precedenti.

Gestione degli errori

Le eccezioni generate nei metodi hub vengono inviate al client che ha richiamato il metodo . Nel client JavaScript il invoke metodo restituisce un codice JavaScript Promise. Quando il client riceve un errore con un gestore associato alla promessa usando catch, viene richiamato e passato come oggetto JavaScript Error :

connection.invoke("SendMessage", user, message).catch(err => console.error(err));

Se l'hub genera un'eccezione, le connessioni non vengono chiuse. Per impostazione predefinita, restituisce SignalR un messaggio di errore generico al client. Ad esempio:

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'MethodName' on the server.

Le eccezioni impreviste contengono spesso informazioni riservate, ad esempio il nome di un server di database in un'eccezione attivata quando la connessione al database non riesce. SignalR non espone questi messaggi di errore dettagliati per impostazione predefinita come misura di sicurezza. Per altre informazioni sul motivo per cui i dettagli delle eccezioni vengono eliminati, vedere Considerazioni sulla sicurezza in ASP.NET Core SignalR.

Se si ha una condizione eccezionale che si vuole propagare al client, è possibile usare la HubException classe . Se si genera un oggetto HubException dal metodo hub, SignalRinvierà l'intero messaggio al client, senza modifiche:

public Task ThrowException()
{
    throw new HubException("This error will be sent to the client!");
}

Nota

SignalR invia solo la Message proprietà dell'eccezione al client. L'analisi dello stack e altre proprietà sull'eccezione non sono disponibili per il client.

Risorse aggiuntive