Mak*_*kla 39 c# signalr asp.net-core-2.0 asp.net-core-signalr
如何从Controller调用SignalR Core Hub方法?
我使用ASP.NET Core 2.0与Microsoft.AspNetCore.SignalR(1.0.0-alpha2-final).
我有与Excel,SolidEdge通信的Windows服务...当操作完成后,它会在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);
}
}
Run Code Online (Sandbox Code Playgroud)
我的中心:
public class VarDesignHub : Hub
{
public async Task TaskCompleted(int id)
{
await Clients.All.InvokeAsync("Completed", id);
}
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*phu 58
解决方案1
另一种可能性是将HubContext注入您的控制器,如:
public VarDesignCommController(IHubContext<VarDesignHub> hubcontext)
{
HubContext = hubcontext;
...
}
private IHubContext<VarDesignHub> HubContext
{ get; set; }
Run Code Online (Sandbox Code Playgroud)
然后你也可以打电话
await this.HubContext.Clients.All.InvokeAsync("Completed", id);
Run Code Online (Sandbox Code Playgroud)
但是,您将在所有客户端上直接调用方法.
解决方案2
您还可以使用类型化集线器:简单创建一个接口,您可以在其中定义服务器可以在客户端上调用的方法:
public interface ITypedHubClient
{
Task BroadcastMessage(string name, string message);
}
Run Code Online (Sandbox Code Playgroud)
从Hub继承:
public class ChatHub : Hub<ITypedHubClient>
{
public void Send(string name, string message)
{
Clients.All.BroadcastMessage(name, message);
}
}
Run Code Online (Sandbox Code Playgroud)
将键入的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" };
}
}
Run Code Online (Sandbox Code Playgroud)
小智 23
目前的答案没有回答提出的问题.
简单的答案是您不能直接从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();
}
Run Code Online (Sandbox Code Playgroud)
在Startup.cs中,使用内置容器配置单例:
services.AddSingleton<IDoStuff, DoStuff>();
Run Code Online (Sandbox Code Playgroud)
完整的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?}");
});
}
}
Run Code Online (Sandbox Code Playgroud)
对于您的集线器类,请注入单例,并在方法中使用它:
public class MyHub : Hub
{
private readonly IDoStuff _doStuff;
public MyHub(IDoStuff doStuff)
{
_doStuff = doStuff;
}
public string GetData()
{
return _doStuff.GetData();
}
}
Run Code Online (Sandbox Code Playgroud)
然后在你的控制器中,注入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();
}
}
Run Code Online (Sandbox Code Playgroud)
当然,您的Javascript或其他客户端应该配置show_data回调.
请注意,我们正在使用注入的集线器上下文将数据发送到所有SignalR客户端:_hub.Clients.All.SendAsync(...)
另一个不使用注入的答案在这里。
我设计了我的中心类,如下所示。
public class NotificationHub : Microsoft.AspNetCore.SignalR.Hub
{
public static IHubContext<NotificationHub> Current { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在你的创业班
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
NotificationHub.Current = app.ApplicationServices.GetService<IHubContext<NotificationFromServerHub>>();
}
Run Code Online (Sandbox Code Playgroud)
所以,你可以从任何地方像这样使用。
public class MyBizClass
{
public void DoSomething()
{
NotificationHub.Current.MyMethod(...);
}
}
Run Code Online (Sandbox Code Playgroud)
现在这里有充分的证明
您可以将IHubContext实例添加到控制器中,方法是将其添加到构造函数中:
Run Code Online (Sandbox Code Playgroud)public class HomeController : Controller { private readonly IHubContext<NotificationHub> _hubContext; public HomeController(IHubContext<NotificationHub> hubContext) { _hubContext = hubContext; } }现在,通过访问IHubContext实例,您可以像调用集线器本身一样调用集线器方法。
Run Code Online (Sandbox Code Playgroud)public async Task<IActionResult> Index() { await _hubContext.Clients.All.SendAsync("Notify", $"Home page loaded at: {DateTime.Now}"); return View(); }
| 归档时间: |
|
| 查看次数: |
30130 次 |
| 最近记录: |