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?
When user click on send button, the message to be posted to server side using signalR connection hub. Thus whenever you post any message after clicking the join group button, the message will appear to all the clients who has joined the group.
What is a SignalR hub. The SignalR Hubs API enables you to call methods on connected clients from the server. In the server code, you define methods that are called by client. In the client code, you define methods that are called from the server.
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...
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With