J'utilise Microsoft.AspNetCore.SignalR
(dernière version) et souhaite obtenir le contexte du hub à partir d'un autre objet qui n'est pas un Controller
. Dans le "plein" SignalR, je pourrais utiliser GlobalHost.ConnectionManager.GetHubContext<MyCoolHub>();
J'ai vu beaucoup d'exemples d'ajouts simplement Microsoft.AspNetCore.SignalR.IHubContext<MyCoolHub>
en tant que paramètre du Ctor d'un Controller
, mais aucun exemple (qui fonctionne) pour le contraire.
ETA:
Donc, voici ce que je travaille. Est-ce hacky?
public class MyHub : Hub
public static IHubContext<MyHub> GlobalContext { get; private set; }
public MyHub(IHubContext<MyHub> ctx){
GlobalContext = ctx;
}
}
Ensuite, je peux l'appeler ainsi:
await MyHub.GlobalContext.Clients.All.InvokeAsync(...)
Il suffit de définir IHubContext<MyHub> hubContext
sur le constructeur côté appelant.
Je recommanderais d'utiliser le mécanisme de conteneur DI par défaut du noyau .net, sans créer de propriété statique.
Veuillez vous référer à Comment puis-je obtenir une référence à un hub?
public class MyHub : Hub
{
}
public class CallingSideClass
{
private readonly IHubContext<MyHub> _hubContext;
public CallingSideClass(IHubContext<MyHub> hubContext)
{
_hubContext = hubContext;
}
public async Task FooMethod(...)
{
await _hubContext.Clients.All.InvokeAsync(...);
}
}
public class Startup
{...
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
services.AddScoped<CallingSideClass>();
}
...
}
Donc, après avoir regardé cet exemple à partir de la réponse acceptée, je ne comprenais pas vraiment où il allait, alors j'ai essayé quelques solutions et je pense avoir compris ce qu'il disait. Donc, pour les gens qui ont ce problème à l'avenir, je veux changer cet exemple en un exemple pleinement fonctionnel.
Nous allons donc créer une "méthode partagée", comme dans l'exemple:
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
namespace YouDontNeedToKnow.Core.Main.Hubs
{
internal class HubMethods<THub> where THub : Hub
{
private readonly IHubContext<THub> _hubContext;
public HubMethods(IHubContext<THub> hubContext)
{
_hubContext = hubContext;
}
public Task InvokeOnGroupAsync(string groupName, string method, params object[] args) =>
_hubContext.Clients.Group(groupName).InvokeAsync(method, args);
public Task InvokeOnAllAsync(string method, params object[] args) =>
_hubContext.Clients.All.InvokeAsync(method, args);
public Task AddConnectionIdToGroupAsync(string connectionId, string groupName) =>
_hubContext.Groups.AddAsync(connectionId, groupName);
// ...
}
}
Ensuite, dans votre objet Hub
, vous ajoutez un constructeur, comme suit:
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
namespace YouDontNeedToKnow.Core.Main.Hubs
{
internal class MyHub : Hub
{
public static string HubName => "myHub";
private readonly HubMethods<MyHub> _hubMethods;
public PlayerServicesHub(HubMethods<MyHub> hubMethods)
{
_hubMethods = hubMethods;
}
public override Task OnConnectedAsync()
{
return base.OnConnectedAsync();
}
}
}
Dans votre Startup.cs
, vous injectez la classe partagée comme suit:
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<HubMethods<MyHub>>();
services.AddSignalR();
services.AddMvc();
}
Cela fonctionne toujours comme d'habitude:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider sp)
{
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseSignalR(routes =>
{
routes.MapHub<MyHub>(MyHub.HubName);
});
app.UseMvc();
// This is just an example line of how you can get the hub with context:
var myHub = sp.GetService<HubMethods<MyHub>>();
}