web-dev-qa-db-fra.com

SignalR + poster un message sur un Hub via une méthode d'action

J'utilise la fonction hub de SignalR ( https://github.com/SignalR/SignalR ) pour publier des messages à tous les clients abonnés:

public class NewsFeedHub : Hub
public void Send(string channel, string content)
{
    Clients[channel].addMessage(content);
}

Cela fonctionne bien lorsque vous appelez "Envoyer" via Javascript, mais j'aimerais également que l'application Web publie des messages (à partir d'une méthode d'action ASP.NET MVC). J'ai déjà essayé d'instancier un nouvel objet ob NewsFeedHub et d'appeler la méthode Send, mais cela entraîne une erreur (car la "connexion" sous-jacente du concentrateur n'est pas définie). Existe-t-il un moyen d'utiliser le hub sans connexion?

62
ollifant

Veuillez noter que l'API SignalR a changé plusieurs fois depuis que cette question a été posée. Il est possible que certaines réponses deviennent obsolètes. Cela ne signifie pas qu'ils devraient être rejetés car ils étaient corrects au moment de la rédaction

Il y a une autre réponse mise à jour pour cela, comme vu dans le SignalR Wiki

c #

Public ActionResult MyControllerMethod()
{
    var context = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
    context.Clients.All.methodInJavascript("hello world");
    // or
    context.Clients.Group("groupname").methodInJavascript("hello world");
}

vb.net

Public Function MyControllerMethod() As ActionResult
    Dim context = GlobalHost.ConnectionManager.GetHubContext(Of MyHub)()
    context.Clients.All.methodInJavascript("hello world")
    '' or
    context.Clients.Group("groupname").methodInJavascript("hello world")
End Function

Mise à jour

Ce code a été mis à jour. Suivez http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-server pour les modifications.

Si vous utilisez un conteneur DI

Si vous utilisez un conteneur DI pour câbler vos concentrateurs, récupérez IConnectionManager à partir de votre conteneur et appelez GetHubContext sur ce gestionnaire de connexion.

92
Tim B James

Février 2018, solution courte et simple

Pour résoudre ce problème, je conçois généralement mes hubs de la manière suivante:

public class NewsFeedHub : Hub 
{
    private static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<NewsFeedHub>();

    // Call this from JS: hub.client.send(channel, content)
    public void Send(string channel, string content)
    {
        Clients.Group(channel).addMessage(content);
    }

    // Call this from C#: NewsFeedHub.Static_Send(channel, content)
    public static void Static_Send(string channel, string content)
    {
        hubContext.Clients.Group(channel).addMessage(content);
    }

}

Il est donc facile d'appeler à partir de Javascript et à partir du code principal. Les deux méthodes entraînent le même événement chez le client.

55
DDan

mise à jour 2012: Cette réponse est également ancienne! L'API publique de SignalR est en constante évolution, semble-t-il. Tim B James a la nouvelle utilisation correcte de l'API en juillet 2012.

mise à jour 2019 N'utilisez plus cette réponse. Les nouvelles versions de SignalR qui fonctionnent sur AspNetCore devraient faire référence à la réponse acceptée par Tim B James, ou à d'autres réponses votées. Je laisse cette réponse ici pour l'histoire.


La réponse actuellement acceptée de Mike est ancienne et ne fonctionne plus avec la dernière version de SignalR.

Voici une version mise à jour qui montre comment publier un message sur un concentrateur à partir d'une action de contrôleur MVC:

public ActionResult MyControllerMethod() 
{
     // Important: .Resolve is an extension method inside SignalR.Infrastructure namespace.
     var connectionManager = AspNetHost.DependencyResolver.Resolve<IConnectionManager>();
     var clients = connectionManager.GetClients<MyHub>();

     // Broadcast to all clients.
     clients.MethodOnTheJavascript("Good news!");

     // Broadcast only to clients in a group.
     clients["someGroupName"].MethodOnTheJavascript("Hello, some group!");

     // Broadcast only to a particular client.
     clients["someConnectionId"].MethodOnTheJavascript("Hello, particular client!");
 } 
10

À la suite de la réponse de DDan, vous pouvez créer une méthode statique surchargée et conserver la logique commune dans une seule méthode - j'utilise ce modèle

public class ChatHub : Hub
{
    private static IHubConnectionContext<dynamic> GetClients(ChatHub chatHub)
    {
        if (chatHub == null)
            return GlobalHost.ConnectionManager.GetHubContext<ChatHub>().Clients;
        else
            return chatHub.Clients;
    }

    // Call from JavaScript
    public void Send(string message)
    {
        Send(message, this);
    }

    // Call from C# eg: Hubs.ChatHub.Send(message, null);
    public static void Send(string message, ChatHub chatHub)
    {
        IHubConnectionContext<dynamic> clients = GetClients(chatHub);
        // common logic goes here 
        clients.All.receiveSend(message);
    }
}

Ensuite, à partir de votre contrôleur, vous pouvez utiliser

Hubs.ChatHub.Send(arg1, null);
2
J45