ASP.NET Core SignalR 从任何地方访问 Hub 的方法
ASP.NET Core SignalR acces Hub method from anywhere
如果我在这个问题上花了很多时间,我发现了很多不同的策略,但是 none 其中对我有用。 (此代码当然只是概念证明。)
我使用 Asp.net 核心 2.1(在 .Net Framwork 4.7.2 上)进行了以下设置:
我制作了一个信号集线器,它有一个发送号码的方法:
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
namespace TestRandomNumberSignalR
{
public class TestHub : Hub
{
public async Task SendRandomNumber(int number)
{
await Clients.All.SendAsync("ReceiveRandomBumber", number);
}
}
}
我还制作了一个 class 每 3 秒更新一个随机数并将其添加为单例:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace TestRandomNumberSignalR
{
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.AddSingleton(new UpdateRandomNumber());
services.AddSignalR();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// 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();
}
app.UseMvc();
app.UseSignalR(routes =>
{
routes.MapHub<TestHub>("/testHub");
});
}
}
}
这里是随机数class:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TestRandomNumberSignalR
{
public class UpdateRandomNumber
{
private bool _continue = true;
public UpdateRandomNumber()
{
var task = new Task(() => RandomNumberLoop(),
TaskCreationOptions.LongRunning);
task.Start();
}
private void RandomNumberLoop()
{
Random r = new Random();
while (_continue)
{
Thread.Sleep(3000);
int number = r.Next(0, 100);
Console.WriteLine("The random number is now " + number);
// Send new random number to connected subscribers here
// Something like TestHub.SendRandomNumber(number);
}
}
public void Stop()
{
_continue = false;
}
}
}
现在从这个 class(正如我在评论中所写)我想使用 SignalR 发送新的随机数。只有如何在其中获取中心上下文?
我还希望能够从控制器中访问 class 上的 Stop() 方法,我该如何访问它?
我现在这是一个讨论得很好的主题,但我仍然无法在任何地方找到可行的解决方案。希望你能帮助我。
编辑
问题一
虽然随机循环现在开始(非常感谢 rasharasha),但仍然存在一些问题。我现在无法将正确的 UpdateRandomNumber 注入控制器。可以说我希望能够停止调用 UpdateRandomNumber.Stop() 方法的循环,我怎样才能将 UpdateRandomNumber 单例注入控制器。我尝试创建一个界面:
public interface IUpdateRandomNumber
{
void Stop();
}
更改 RandomNumber 方法以实现此:
public class UpdateRandomNumber : IUpdateRandomNumber
{
private bool _continue = true;
private IHubContext<TestHub> testHub;
public UpdateRandomNumber(IHubContext<TestHub> testHub)
{
this.testHub = testHub;
var task = new Task(() => RandomNumberLoop(),
TaskCreationOptions.LongRunning);
task.Start();
}
private void RandomNumberLoop()
{
Random r = new Random();
while (_continue)
{
Thread.Sleep(3000);
int number = r.Next(0, 100);
Console.WriteLine("The random number is now " + number);
// Send new random number to connected subscribers here
// Something like TestHub.SendRandomNumber(number);
}
}
public void Stop()
{
_continue = false;
}
}
并更改添加单例方法以使用接口:
services.AddSingleton<IUpdateRandomNumber>(provider =>
{
var hubContext = provider.GetService<IHubContext<TestHub>>();
var updateRandomNumber = new UpdateRandomNumber(hubContext);
return updateRandomNumber;
});
我现在可以创建一个带有停止随机数循环的方法的控制器:
[Route("api/[controller]")]
[ApiController]
public class RandomController : ControllerBase
{
private readonly IUpdateRandomNumber _updateRandomNumber;
public RandomController(IUpdateRandomNumber updateRandomNumber)
{
_updateRandomNumber = updateRandomNumber;
}
// POST api/random
[HttpPost]
public void Post()
{
_updateRandomNumber.Stop();
}
但是,此实现将阻止循环再次开始。那么如何从控制器访问 rondomnumber 单例呢?
问题二
从我的 UpdateRandomNumber class 我现在可以调用:
testHub.Clients.All.SendAsync("ReceiveRandomBumber", number);
但是为什么我在我的testhub中制作了这个方法:
public async Task SendRandomNumber(int number)
{
await Clients.All.SendAsync("ReceiveRandomBumber", number);
}
在 hub 中创建方法并直接调用它们会更方便。这能做到吗?
您可以使用构造函数注入将 TestHub 注入控制器。因为它已经在 DI 容器中注册了。
public class UpdateRandomNumber
{
private bool _continue = true;
private IHubContext<TestHub> testHub;
private Task randomNumberTask;
public UpdateRandomNumber(IHubContext<TestHub> testHub)
{
this.testHub=testHub;
randomNumberTask = new Task(() => RandomNumberLoop(),
TaskCreationOptions.LongRunning);
randomNumberTask.Start();
}
private async void RandomNumberLoop()
{
Random r = new Random();
while (_continue)
{
Thread.Sleep(3000);
int number = r.Next(0, 100);
Console.WriteLine("The random number is now " + number);
// Send new random number to connected subscribers here
await testHub.Clients.All.SendAsync($"ReceiveRandomNumber", number);
}
}
public void Stop()
{
_continue = false;
}
}
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.AddSignalR();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddSingleton(provider =>
{
var hubContext = provider.GetService<IHubContext<TestHub>>();
var updateRandomNumber = new UpdateRandomNumber(hubContext);
return updateRandomNumber;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var updateRandonNumber = app.ApplicationServices.GetService<UpdateRandomNumber>();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
app.UseSignalR(routes =>
{
routes.MapHub<TestHub>("/testHub");
});
}
}
如果我在这个问题上花了很多时间,我发现了很多不同的策略,但是 none 其中对我有用。 (此代码当然只是概念证明。)
我使用 Asp.net 核心 2.1(在 .Net Framwork 4.7.2 上)进行了以下设置:
我制作了一个信号集线器,它有一个发送号码的方法:
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
namespace TestRandomNumberSignalR
{
public class TestHub : Hub
{
public async Task SendRandomNumber(int number)
{
await Clients.All.SendAsync("ReceiveRandomBumber", number);
}
}
}
我还制作了一个 class 每 3 秒更新一个随机数并将其添加为单例:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace TestRandomNumberSignalR
{
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.AddSingleton(new UpdateRandomNumber());
services.AddSignalR();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// 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();
}
app.UseMvc();
app.UseSignalR(routes =>
{
routes.MapHub<TestHub>("/testHub");
});
}
}
}
这里是随机数class:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace TestRandomNumberSignalR
{
public class UpdateRandomNumber
{
private bool _continue = true;
public UpdateRandomNumber()
{
var task = new Task(() => RandomNumberLoop(),
TaskCreationOptions.LongRunning);
task.Start();
}
private void RandomNumberLoop()
{
Random r = new Random();
while (_continue)
{
Thread.Sleep(3000);
int number = r.Next(0, 100);
Console.WriteLine("The random number is now " + number);
// Send new random number to connected subscribers here
// Something like TestHub.SendRandomNumber(number);
}
}
public void Stop()
{
_continue = false;
}
}
}
现在从这个 class(正如我在评论中所写)我想使用 SignalR 发送新的随机数。只有如何在其中获取中心上下文?
我还希望能够从控制器中访问 class 上的 Stop() 方法,我该如何访问它?
我现在这是一个讨论得很好的主题,但我仍然无法在任何地方找到可行的解决方案。希望你能帮助我。
编辑
问题一
虽然随机循环现在开始(非常感谢 rasharasha),但仍然存在一些问题。我现在无法将正确的 UpdateRandomNumber 注入控制器。可以说我希望能够停止调用 UpdateRandomNumber.Stop() 方法的循环,我怎样才能将 UpdateRandomNumber 单例注入控制器。我尝试创建一个界面:
public interface IUpdateRandomNumber
{
void Stop();
}
更改 RandomNumber 方法以实现此:
public class UpdateRandomNumber : IUpdateRandomNumber
{
private bool _continue = true;
private IHubContext<TestHub> testHub;
public UpdateRandomNumber(IHubContext<TestHub> testHub)
{
this.testHub = testHub;
var task = new Task(() => RandomNumberLoop(),
TaskCreationOptions.LongRunning);
task.Start();
}
private void RandomNumberLoop()
{
Random r = new Random();
while (_continue)
{
Thread.Sleep(3000);
int number = r.Next(0, 100);
Console.WriteLine("The random number is now " + number);
// Send new random number to connected subscribers here
// Something like TestHub.SendRandomNumber(number);
}
}
public void Stop()
{
_continue = false;
}
}
并更改添加单例方法以使用接口:
services.AddSingleton<IUpdateRandomNumber>(provider =>
{
var hubContext = provider.GetService<IHubContext<TestHub>>();
var updateRandomNumber = new UpdateRandomNumber(hubContext);
return updateRandomNumber;
});
我现在可以创建一个带有停止随机数循环的方法的控制器:
[Route("api/[controller]")]
[ApiController]
public class RandomController : ControllerBase
{
private readonly IUpdateRandomNumber _updateRandomNumber;
public RandomController(IUpdateRandomNumber updateRandomNumber)
{
_updateRandomNumber = updateRandomNumber;
}
// POST api/random
[HttpPost]
public void Post()
{
_updateRandomNumber.Stop();
}
但是,此实现将阻止循环再次开始。那么如何从控制器访问 rondomnumber 单例呢?
问题二
从我的 UpdateRandomNumber class 我现在可以调用:
testHub.Clients.All.SendAsync("ReceiveRandomBumber", number);
但是为什么我在我的testhub中制作了这个方法:
public async Task SendRandomNumber(int number)
{
await Clients.All.SendAsync("ReceiveRandomBumber", number);
}
在 hub 中创建方法并直接调用它们会更方便。这能做到吗?
您可以使用构造函数注入将 TestHub 注入控制器。因为它已经在 DI 容器中注册了。
public class UpdateRandomNumber
{
private bool _continue = true;
private IHubContext<TestHub> testHub;
private Task randomNumberTask;
public UpdateRandomNumber(IHubContext<TestHub> testHub)
{
this.testHub=testHub;
randomNumberTask = new Task(() => RandomNumberLoop(),
TaskCreationOptions.LongRunning);
randomNumberTask.Start();
}
private async void RandomNumberLoop()
{
Random r = new Random();
while (_continue)
{
Thread.Sleep(3000);
int number = r.Next(0, 100);
Console.WriteLine("The random number is now " + number);
// Send new random number to connected subscribers here
await testHub.Clients.All.SendAsync($"ReceiveRandomNumber", number);
}
}
public void Stop()
{
_continue = false;
}
}
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.AddSignalR();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddSingleton(provider =>
{
var hubContext = provider.GetService<IHubContext<TestHub>>();
var updateRandomNumber = new UpdateRandomNumber(hubContext);
return updateRandomNumber;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var updateRandonNumber = app.ApplicationServices.GetService<UpdateRandomNumber>();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
app.UseSignalR(routes =>
{
routes.MapHub<TestHub>("/testHub");
});
}
}