Reputation: 6226
I am trying to call a method in the signalr Hub class from an (ASP.NET Core) MVC Controller, but I cannot find an example online that shows how to.
Note: There are lots of examples using older versions of signalr with the .Net Framework, but none that I can see that show how to do this in .Net Core.
I need to pass an id from the an MVC Action Result directly through to my Hub, without passing the id to the page, and then having to get a client connection back through to the hub.
public class ChatHub : Hub
{
public async Task DoSomething(int id)
{
//// Something in here.
}
}
public class HomeController : Controller
{
private readonly IHubContext<ChatHub> _hubContext;
public HomeController(IHubContext<ChatHub> hubContext)
{
_hubContext = hubContext;
}
public async Task<ActionResult> Index(int id)
{
//// Call the DoSomething method from here, passing the id across.
await _hubContext.Clients.All.SendAsync("AddToGroup", groupId);
}
}
Is there a way to do this please? (Or am I looking at this the wrong way, and is there a better way to achieve the same result?)
Update: If I pass the Id into the view, and then use JavaScript to call the Hub, this then calls the DoSomething method, so I can see it all hangs together correctly, but not when I try to call it in C#.
Upvotes: 3
Views: 7618
Reputation: 724
I used the code here https://stackoverflow.com/a/53062957/6453193 for my HUB connection.
Since the js client-side code was not posted here. Just wanna share how I do it in js.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chatHub")
.configureLogging(signalR.LogLevel.Information)
.withAutomaticReconnect()
.build();
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
// Trigger if server-side code call it using NotificationUpdate
connection.on("NotificationUpdate", (message) => {
alert(message);
});
// Start the connection.
start();
and my controller notifying the client-side
await _hubContext.Clients.User(User.Identity.Name).NotificationUpdate($"This is an update");
Upvotes: 0
Reputation: 1737
I think you're misunderstanding how it all works together (which is the same thing I did up until yesterday), the hub code is for the client-side script code to call back into and then action, whereas the IHubContext is used as the strongly typed methods that will be sent to the Client-side
Hub
// This class is used by the JavaScript Client to call into the .net core application.
public class ChatHub : Hub<IChatClient>
{
public static ConcurrentDictionary<string, string> Connections = new ConcurrentDictionary<string, string>();
// As an example, On connection save the user name with a link to the client Id for later user callback
public override Task OnConnectedAsync()
{
var user = Context.User.Identity.Name;
Connections.AddOrUpdate(this.Context.ConnectionId, user, (key, oldValue) => user);
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception exception)
{
// Do something on disconnect.
}
// Add other methods you want to be able to call from JavaScript side in here...
public void SendMessage(int id, string message)
{
// Message doing stuff here.
}
}
ChatClient Interface
// This provides strongly-typed methods that you'll have on the Client side but these don't exist on the server.
public interface IChatClient
{
//So this method is a JS one not a .net one and will be called on the client(s)
Task DoSomething(int id);
Task NotificationUpdate(int id, string message);
}
Controller
public class HomeController : Controller
{
private readonly IHubContext<ChatHub, IChatClient> _hubContext;
public HomeController(IHubContext<ChatHub, IChatClient> hubContext)
{
_hubContext = hubContext;
}
public async Task<ActionResult> Index(int id)
{
// This calls the method on the Client-side
await _hubContext.Clients.All.DoSomething(id);
}
}
Upvotes: 5
Reputation: 2494
You can use the IHubContext
to do this:
public class HomeController : Controller
{
private readonly IHubContext<ChatHub> _hubContext;
public HomeController(IHubContext<ChatHub> hubContext)
{
_hubContext = hubContext;
}
public async Task<ActionResult> Index(int id)
{
//// Call the DoSomething method from here, passing the id across.
await _hubContext.Clients.All.SendAsync("DoSomething", id);
}
}
Upvotes: 2