从Controller调用SignalR Core Hub方法
如何从Controller调用SignalR Core Hub方法?
我使用ASP.NET Core 2.0与Microsoft.AspNetCore.SignalR(1.0.0-alpha2-final)。
我有与Excel,SolidEdge通信的Windows服务…当操作完成后,它会在ASP.NET Core应用程序中向我的控制器发送请求。 现在我需要通过SignalR通知连接到服务器的所有客户端外部程序完成了一些任务。
我无法改变窗口服务的工作方式。 (无法从窗口服务连接到SignalR)。
我为旧的SignalR(GlobalHost.ConnectionManager.GetHubContext)找到了很多解决方案,但是已经发生了很多变化,这些解决方案不再适用了。
我的控制器:
[Route("API/vardesigncomm")] public class VarDesignCommController : Controller { [HttpPut("ProcessVarDesignCommResponse/{id}")] public async Task ProcessVarDesignCommResponse(int id) { //call method TaskCompleted in Hub !!!! How? return new JsonResult(true); } }
我的中心:
public class VarDesignHub : Hub { public async Task TaskCompleted(int id) { await Clients.All.InvokeAsync("Completed", id); } }
解决方案1
另一种可能性是将HubContext注入您的控制器,如:
public VarDesignCommController(IHubContext hubcontext) { HubContext = hubcontext; ... } private IHubContext HubContext { get; set; }
然后你也可以打电话
await this.HubContext.Clients.All.InvokeAsync("Completed", id);
但是,您将在所有客户端上直接调用方法。
解决方案2
您还可以使用类型化集线器:简单创建一个接口,您可以在其中定义服务器可以在客户端上调用的方法:
public interface ITypedHubClient { Task BroadcastMessage(string name, string message); }
从Hubinheritance:
public class ChatHub : Hub { public void Send(string name, string message) { Clients.All.BroadcastMessage(name, message); } }
将键入的hubcontext注入控制器,然后使用它:
[Route("api/demo")] public class DemoController : Controller { IHubContext _chatHubContext; public DemoController(IHubContext chatHubContext) { _chatHubContext = chatHubContext; } // GET: api/values [HttpGet] public IEnumerable Get() { _chatHubContext.Clients.All.BroadcastMessage("test", "test"); return new string[] { "value1", "value2" }; } }
目前的答案没有回答提出的问题。
简单的答案是您不能直接从MVC控制器或其他地方调用集线器方法。 这是设计的。 可以将集线器视为包含SignalR Core客户端要调用的端点,而不是服务器或控制器方法。
这就是微软所说的 (这是SignalR之前的Core文档,但它仍然适用于SignalR Core):
您没有实例化Hub类或从服务器上自己的代码调用其方法; SignalR Hubs管道为您完成的所有工作。 每次需要处理Hub操作时,SignalR都会创建Hub类的新实例,例如客户端连接,断开连接或对服务器进行方法调用时。
因为Hub类的实例是瞬态的,所以不能使用它们来维持从一个方法调用到下一个方法调用的状态。 每次服务器从客户端接收方法调用时,Hub类的新实例都会处理该消息。 要通过多个连接和方法调用来维护状态,请使用其他方法,例如数据库,Hub类上的静态变量,或不从Hub派生的其他类。 如果将数据保留在内存中,使用Hub类上的静态变量等方法,则应用程序域回收时数据将丢失。
如果要从在Hub类外部运行的自己的代码向客户端发送消息,则不能通过实例化Hub类实例来实现,但可以通过获取Hub类的SignalR上下文对象的引用来实现。 …
如果集线器中存在需要调用的代码,最好将其放入可从任何位置访问的外部类或服务中。
这是一个使用ASP.NET Core的简单内置DI框架的示例:
假设您需要调用的代码在DoStuff.cs中:
public class DoStuff : IDoStuff { public string GetData() { return "MyData"; } } public interface IDoStuff { string GetData(); }
在Startup.cs中,使用内置容器配置单例:
services.AddSingleton();
完整的Startup.cs如下所示:
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(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(); } // 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"); }); 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和单例:
public class HomeController : Controller { private readonly IDoStuff _doStuff; private readonly IHubContext _hub; public HomeController(IDoStuff doStuff, IHubContext hub) { _doStuff = doStuff; _hub = hub; } public async Task Index() { var data = _doStuff.GetData(); await _hub.Clients.All.SendAsync("show_data", data); return View(); } }
当然,您的Javascript或其他客户端应该配置show_data回调。
请注意,我们使用注入的集线器上下文将数据发送到所有SignalR客户端:_hub.Clients.All.SendAsync(…)
- .Net Core 2.0中Controller和BaseController中的dependency injection重复
- 从.NET Core 2中的类读取appsettings.json
- 在ASP.NET Core 2.0中从另一个(无用户交互)授权一个应用程序服务
- 在.Net Core 2.0和Angular中使用’dotnet publish’时找不到模块’aspnet-webpack’
- asp.net core 2.0中System.Web.Hosting.HostingEnvironment.RegisterObject的替代方案
- ASP.NET Core 2.0中缺少声明转换支持
- 未指定authenticationScheme,并且未找到具有默认身份validation和自定义授权的DefaultChallengeScheme
- 为HTTPS配置ASP.NET Core 2.0 Kestrel
- 如何在Asp.net core 2.0中使用log4net