La réponse actuelle ne répond pas à la question posée.
La réponse simple est que vous ne pouvez pas appeler directement une méthode de hub depuis un contrôleur MVC ou autre. C'est une question de conception. Pensez au hub comme contenant les points finaux que les clients SignalR Core doivent appeler, et non les méthodes du serveur ou du contrôleur.
Voici ce que Microsoft dit (il s'agit d'une documentation antérieure à SignalR Core, mais elle s'applique toujours à SignalR Core) :
Vous n'instanciez pas la classe Hub ou n'appelez pas ses méthodes à partir de votre propre code sur le serveur ; tout cela est fait pour vous par le pipeline SignalR Hubs. SignalR crée une nouvelle instance de votre classe Hub chaque fois qu'il doit gérer une opération Hub, comme lorsqu'un client se connecte, se déconnecte ou fait un appel de méthode au serveur.
Les instances de la classe Hub étant transitoires, vous ne pouvez pas les utiliser pour maintenir l'état d'un appel de méthode à l'autre. Chaque fois que le serveur reçoit un appel de méthode d'un client, une nouvelle instance de votre classe Hub traite le message. Pour maintenir l'état à travers de multiples connexions et appels de méthode, utilisez une autre méthode telle qu'une base de données, une variable statique de la classe Hub ou une classe différente qui ne dérive pas de Hub. Si vous conservez les données en mémoire, en utilisant une méthode telle qu'une variable statique sur la classe Hub, les données seront perdues lorsque le domaine d'application se recycle.
Si vous voulez envoyer des messages aux clients à partir de votre propre code qui s'exécute en dehors de la classe Hub, vous ne pouvez pas le faire en instanciant une instance de classe Hub, mais vous pouvez le faire en obtenant une référence à l'objet de contexte SignalR pour votre classe Hub...
S'il y a du code dans le concentrateur que vous devez appeler, il est préférable de le placer dans une classe ou un service externe accessible de partout.
Voici donc un exemple utilisant le simple cadre DI intégré à ASP.NET Core :
En supposant que le code que vous devez appeler est dans DoStuff.cs :
public class DoStuff : IDoStuff
{
public string GetData()
{
return "MyData";
}
}
public interface IDoStuff
{
string GetData();
}
Dans Startup.cs, configurez un singleton en utilisant le conteneur intégré :
services.AddSingleton<IDoStuff, DoStuff>();
Le fichier Startup.cs complet ressemble à ceci :
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddSignalR();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<IDoStuff, DoStuff>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseSignalR(routes =>
{
routes.MapHub<MyHub>("/myhub");
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Pour votre classe hub, injectez le singleton, et utilisez-le dans une méthode :
public class MyHub : Hub
{
private readonly IDoStuff _doStuff;
public MyHub(IDoStuff doStuff)
{
_doStuff = doStuff;
}
public string GetData()
{
return _doStuff.GetData();
}
}
Ensuite, dans votre contrôleur, injectez le IHubContext et le singleton :
public class HomeController : Controller
{
private readonly IDoStuff _doStuff;
private readonly IHubContext<MyHub> _hub;
public HomeController(IDoStuff doStuff, IHubContext<MyHub> hub)
{
_doStuff = doStuff;
_hub = hub;
}
public async Task<IActionResult> Index()
{
var data = _doStuff.GetData();
await _hub.Clients.All.SendAsync("show_data", data);
return View();
}
}
Bien entendu, votre client Javascript ou autre doit avoir un callback show_data configuré.
Remarquez que nous utilisons le contexte du hub injecté pour envoyer les données à tous les clients SignalR : _hub.Clients.All.SendAsync(...)