如何从控制器调用SignalR核心集线器方法?
我使用的是ASP.NET Core2.0和Microsoft.AspNetCore.SignalR (1.0.0-字母2-决赛)。
我有windows服务,它与Excel、SolidEdge .操作完成后,在ASP.NET核心应用程序中将请求发送给我的控制器。现在,我需要通知所有与SignalR连接到服务器的客户端,外部程序完成了一些任务。
我无法改变窗口服务的工作方式。(无法从窗口服务连接到SignalR )。
我为旧SignalR (GlobalHost.ConnectionManager.GetHubContext
)找到了大量的解决方案,但是已经发生了很大的变化,这些解决方案不再起作用了。
我的控制器:
[Route("API/vardesigncomm")]
public class VarDesignCommController : Controller
{
[HttpPut("ProcessVarDesignCommResponse/{id}")]
public async Task<IActionResult> 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);
}
}
发布于 2017-10-24 01:27:08
解决方案1
另一种可能是将HubContext注入控制器,如下所示:
public VarDesignCommController(IHubContext<VarDesignHub> hubcontext)
{
HubContext = hubcontext;
...
}
private IHubContext<VarDesignHub> HubContext
{ get; set; }
然后你也可以打电话给
await this.HubContext.Clients.All.InvokeAsync("Completed", id);
但是,您将在所有客户端上直接调用方法。
解决方案2
您还可以使用类型化集线器:简单地创建一个接口,在其中定义服务器可以在客户端上调用哪些方法:
public interface ITypedHubClient
{
Task BroadcastMessage(string name, string message);
}
从中心继承:
public class ChatHub : Hub<ITypedHubClient>
{
public void Send(string name, string message)
{
Clients.All.BroadcastMessage(name, message);
}
}
将输入的hubcontext注入控制器,并使用它:
[Route("api/demo")]
public class DemoController : Controller
{
IHubContext<ChatHub, ITypedHubClient> _chatHubContext;
public DemoController(IHubContext<ChatHub, ITypedHubClient> chatHubContext)
{
_chatHubContext = chatHubContext;
}
// GET: api/values
[HttpGet]
public IEnumerable<string> Get()
{
_chatHubContext.Clients.All.BroadcastMessage("test", "test");
return new string[] { "value1", "value2" };
}
}
发布于 2018-10-29 09:01:03
目前的答案没有回答提出的问题。
简单的答案是,您不能直接从MVC控制器或其他地方调用hub方法。这是故意的。将集线器想象为包含要调用的SignalR核心客户端的端点,而不是服务器或控制器方法。
下面是微软他说 (这是前SignalR文档,但仍然适用于SignalR Core):
您不实例化集线器类,也不从服务器上自己的代码调用它的方法;所有这些都是由SignalR集线器管道为您完成的。每次需要处理集线器操作时,例如当客户端连接、断开连接或对服务器进行方法调用时,SignalR都会创建集线器类的新实例。 因为集线器类的实例是短暂的,所以不能使用它们来维护从一个方法调用到下一个方法的状态。每当服务器从客户端接收到方法调用时,集线器类的新实例将处理该消息。若要通过多个连接和方法调用来维护状态,请使用其他方法,如数据库、集线器类上的静态变量或不从集线器派生的其他类。如果使用Hub类上的静态变量等方法将数据持久化在内存中,则应用域回收时数据将丢失。 如果您希望从运行在集线器类之外的自己代码中向客户端发送消息,则不能通过实例化集线器类实例来完成此任务,但可以通过获取对集线器类的SignalR上下文对象的引用来实现.
如果集线器中有您需要调用的代码,最好将其放入可从任何地方访问的外部类或服务中。
下面是一个例子,它使用了一个简单的ASP.NET内核内置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; }
// 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?}");
});
}
}
对于hub类,注入单例,并在方法中使用它:
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<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回调。
注意,我们使用注入的集线器上下文将数据发送到所有SignalR客户端:_hub.Clients.All.SendAsync(.)
发布于 2019-06-23 07:01:41
这现在已经有了很好的记录,这里。
通过将IHubContext实例添加到构造函数中,可以将它注入控制器: 公共类HomeController :控制器{私有只读IHubContext _hubContext;公共HomeController(IHubContext hubContext) { _hubContext = hubContext;} 现在,通过对IHubContext实例的访问,您可以像调用集线器本身一样调用hub方法。 公共异步任务索引(){等待_hubContext.Clients.All.SendAsync(“通知”,$“加载在:{DateTime.Now}上的主页”);返回视图();}
https://stackoverflow.com/questions/46904678
复制