当前答案并没有回答提出的问题。
简单的答案是你不能直接从MVC控制器或其他地方调用hub方法。这是有意为之的设计。将hub视为包含SignalR Core客户端调用终点,而不是服务器或控制器方法的终点。
Microsoft在此处(这是针对预-SignalR Core文档的说明,但同样适用于SignalR Core)提到:
您不需要在服务器上的自己的代码中实例化Hub类或调用其方法; SignalR Hubs管道会为您完成所有这些操作。每当处理Hub操作时(例如客户端连接、断开连接或向服务器发出方法调用)SignalR会新建一个Hub类的实例。
由于Hub类的实例是短暂的,因此无法使用它们来在一次方法调用和下一次方法调用之间维护状态。 每当服务器从客户端接收到一个方法调用时,您的Hub类的新实例将处理消息。要通过多个连接和方法调用维护状态,请使用其他方法,例如数据库或Hub类上的静态变量或不派生自Hub的不同类。如果在内存中持久保存数据,如使用Hub类上的静态变量这样的方法,则应用程序域重新启动时数据将丢失。
如果您想从运行在Hub类外部的自己的代码向客户端发送消息,则不能通过实例化Hub类实例来完成,但可以通过获取对Hub类的SignalR上下文对象的引用来完成...
如果需要调用hub中的代码,则最好将其放入可从任何地方访问的外部类或服务中。
以下是使用ASP.NET Core的简单内置DI框架的示例:
假设您需要调用的代码位于DoStuff.cs中:
public class DoStuff : IDoStuff
{
public string GetData()
{
return "MyData";
}
}
public interface IDoStuff
{
string GetData();
}
在Startup.cs中,使用内置容器配置一个单例:
services.AddSingleton<IDoStuff, DoStuff>()
完整的 Startup.cs 如下所示:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddSignalR();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<IDoStuff, DoStuff>();
}
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?}");
});
}
}
对于您的中心类,请注入单例并在方法中使用:
public class MyHub : Hub
{
private readonly IDoStuff _doStuff;
public MyHub(IDoStuff doStuff)
{
_doStuff = doStuff;
}
public string GetData()
{
return _doStuff.GetData();
}
}
然后在您的控制器中注入IHubContext和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();
}
}
当然,您的JavaScript或其他客户端应该配置一个show_data回调函数。
请注意,我们使用注入的Hub上下文将数据发送到所有SignalR客户端:_hub.Clients.All.SendAsync(...)