Pregunta

I am just starting to explore signalR and I would like to able to send messages from the server to all clients.

Here is my Hub

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using SignalR;
using SignalR.Hubs;
using SignalR.Hosting.Common;
using SignalR.Hosting.AspNet;
using System.Threading.Tasks;

namespace MvcApplication1
{
    public class Chat : Hub
    {
        public void Send(String message)
        {
            // Call the addMessage methods on all clients
            Clients.addMessage(message);
        }
    }
}

Here is my client Page

      <script type="text/javascript">

         $(function () {

             //Proxy created on the fly
             var chat = $.connection.chat;

             // Declare a function on the chat hub so the server can invoke it
             chat.addMessage = function (message) {
                 $("#messages").append("<li>" + message + "</li>");
             };

             $("#broadcast").click(function () {
                 // call the chat method on the server
                 chat.send($("#msg").val());
             });

             $.connection.hub.start();
         });
    </script>


}



<input type="text" id="msg" />
        <input type="button" id="broadcast" value="broadcast" />

        <ul id="messages" class="round">


        </ul>

This all works perfectly, I am able to "chat" between 2 different browsers.

The next thing I want to do is initiate a message from the server to all clients.

So I tried this.

 using SignalR;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using System;
using System.Web.Routing;
using SignalR;
using SignalR.Hubs;

namespace MvcApplication1
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {            
            var aTimer = new System.Timers.Timer(1000);

            aTimer.Elapsed += aTimer_Elapsed;
            aTimer.Interval = 3000;
            aTimer.Enabled = true;

            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
        }

        void aTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            var context = GlobalHost.ConnectionManager.GetHubContext<Chat>();
            context.Clients.Send("Hello");      
        }
    }
}

This doesn't seem to work. The Timer works, The "aTimer_Elapsed" event handeler runs every 3 seconds but the "Send" method on the chat hub is never run.

Any ideas?

¿Fue útil?

Solución

I think it should be

 void aTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        var context = GlobalHost.ConnectionManager.GetHubContext<Chat>();
        context.Clients.All.addMessage("Hello");      
    }

instead. With Send you are calling the method used by the client to call the server...

Otros consejos

Yes you must set that line to:

void aTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        var context = GlobalHost.ConnectionManager.GetHubContext<Chat>();
        context.Clients.All.addMessage("Hello");      
    }

However this is only half way and still wont work.

In your Js you need to write:

$(function () {

//Proxy created on the fly
var chat = $.connection.chat;

// Declare a function on the chat hub so the server can invoke it
chat.client.addMessage = function (message) {
    $("#messages").append("<li>" + message + "</li>");
};

$("#broadcast").click(function () {
    // call the chat method on the server
    chat.client.addMessage($("#msg").val());
});

$.connection.hub.start();
});

I added the chat.clientthis will add a client-side hub method that the server will call.

In case you come across this question many years after it was asked, and you happen to use .NET 5.0 (or similar), the following may be useful as you might be using a framework that no longer offers the class GlobalHost.

.NET 5.0 (and similar) make heavy use of dependency injection (DI) and it's not a surprise it is used here as well. The following sample code shows how to do this. It doesn't use the class GlobalHost.

Given the ChatHub class as follows:

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

in class Startup add a line as indicated in the following code snippet:

   public class Startup
   {
      // other code omitted for brevity

      public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
      {
         // other code omitted for brevity

         app.UseEndpoints(endpoints =>
         {
            endpoints.MapControllers();
            endpoints.MapHub<ChatHub>("/chatHub"); // <====== add this ======
         });

         // other code omitted for brevity
      }
   }

Then in a controller where you want to send messages to SignalR message, add the ChatHub as a dependency. The following example demonstrates how to do that for constructor injection:

   public class WeatherForecastController : ControllerBase
   {
      private readonly IHubContext<ChatHub> _hubContext;

      public WeatherForecastController(
         IHubContext<ChatHub> hubContext, // <============ add this ==========
         ILogger<WeatherForecastController> logger)
      {
         _hubContext = hubContext;
         _logger = logger;
      }
      
      [HttpGet]
      public virtual async Task<IEnumerable<WeatherForecastModel>> Get()
      {
         var rng = new Random();
         WeatherForecastModel[] weatherForecastModels = Enumerable.Range(1, 5).Select(index => new WeatherForecastModel
         {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)],
         }).ToArray();

         // Notify connected SignalR clients with some data:
         await _hubContext.Clients.All.SendAsync("ReceiveMessage", "the weatherman", $" The temperature will be {weatherForecastModels[0].TemperatureC}").ConfigureAwait(false);

         return weatherForecastModels;
      }

      // other code omitted for brevity
   }

This example also shows how to then send messages in the Get() method by using await _hubContext.Clients.All.SendAsync( ... )

For more information see Microsoft's documentation.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top