Если я потратил много часов на эту проблему, и я нашел много разных стратегий, но ни одна из них не сработала для меня.(Этот код является просто доказательством концепции курса.)
У меня есть следующая настройка с использованием Asp.net core 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);
}
}
}
Я также создал класс, который обновляет случайное число каждые 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");
});
}
}
}
Вот класс случайных чисел:
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;
}
}
}
Теперь из этого класса (как я написал в комментарии) я хочу отправить новое случайное число с помощью SignalR.Только как получить там хаб-контекст?
Также я хочу иметь возможность доступа к методу Stop () для класса из контроллера, как я могу получить к нему доступ?
Iсейчас это хорошо обсуждаемая тема, но все равно я нигде не могу найти рабочее решение.Надеюсь, что вы можете помочь мне.
РЕДАКТИРОВАТЬ
Вопрос 1
Пока запускается случайный цикл (большое спасибодо рашараша), еще остались некоторые вопросы.Теперь я не могу ввести правильный 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;
}
}
И изменение метода add singleton таким образом, чтобы он использовал интерфейс:
services.AddSingleton<IUpdateRandomNumber>(provider =>
{
var hubContext = provider.GetService<IHubContext<TestHub>>();
var updateRandomNumber = new UpdateRandomNumber(hubContext);
return updateRandomNumber;
});
Теперь я могу создать контроллер с методом для остановки цикла randomnumber:
[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 из контроллера?
Вопрос 2
Из моего класса UpdateRandomNumber я могу теперь вызывать:
testHub.Clients.All.SendAsync("ReceiveRandomBumber", number);
Но почему я сделал метод в моем testhub:
public async Task SendRandomNumber(int number)
{
await Clients.All.SendAsync("ReceiveRandomBumber", number);
}
Было бы гораздо удобнее создавать методы в хабе, и они вызывали их напрямую.Можно ли это сделать?