Использование Hub из отдельного класса в ASP.NET Core 3 - PullRequest
3 голосов
/ 24 октября 2019

Я работаю над программой, в которой я получаю данные от SignalR, выполняю обработку, а затем отправляю сообщение SignalR обратно клиенту после завершения обработки. Я нашел пару из ресурсов о том, как это сделать, но я не могу понять, как реализовать это в моем проекте.

Вот как выглядит мой код:

Начальная загрузка


    public static void Main(string[] args)
    {
        CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
        List<ISystem> systems = new List<ISystem>
        {
            new FirstProcessingSystem(),
            new SecondProcessingSystem(),
        };
        Processor processor = new Processor(
            cancellationToken: cancellationTokenSource.Token,
            systems: systems);
        processor.Start();
        CreateHostBuilder(args).Build().Run();
        cancellationTokenSource.Cancel();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });

    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSignalR();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapHub<TestHub>("/testHub");
            });
        }
    }

TestHub.cs


    public class TestHub : Hub
    {
        public async Task DoStuff(Work work)
        {
            FirstProcessingSystem.ItemsToProcess.Add(work);
        }
    }

Work.cs


    public class Work
    {
        public readonly string ConnectionId;
        public readonly string Data;

        public Work(string connectionId, string data)
        {
            ConnectionId = connectionId;
            Data = data;
        }
    }

Processor.cs

    public class Processor
    {
        readonly CancellationToken CancellationToken;
        readonly List<ISystem> Systems;

        public Processor(
            CancellationToken cancellationToken,
            List<ISystem> systems)
        {
            CancellationToken = cancellationToken;
            Systems = systems;
        }

        public void Start()
        {
            Task.Run(() =>
            {
                while (!CancellationToken.IsCancellationRequested)
                {
                    foreach (var s in Systems)
                        s.Process();
                }
            });
        }
    }

Системы


    public interface ISystem
    {
        void Process();
    }

    public class FirstProcessingSystem : ISystem
    {
        public static ConcurrentBag<Work> ItemsToProcess = new ConcurrentBag<Work>();

        public void Process()
        {
            while (!ItemsToProcess.IsEmpty)
            {
                Work work;
                if (ItemsToProcess.TryTake(out work))
                {
                    // Do things...
                    SecondProcessingSystem.ItemsToProcess.Add(work);
                }
            }
        }
    }

    public class SecondProcessingSystem : ISystem
    {
        public static ConcurrentBag<Work> ItemsToProcess = new ConcurrentBag<Work>();

        public void Process()
        {
            while (!ItemsToProcess.IsEmpty)
            {
                Work work;
                if (ItemsToProcess.TryTake(out work))
                {
                    // Do more things...
                    // Hub.Send(work.ConnectionId, "Finished");
                }
            }
        }
    }

Я знаю, что могу выполнить обработку в концентраторе, а затем отправить обратно вызов "Finished", но я бы хотелотделить мою обработку от входящих сообщений таким образом, чтобы я мог добавить больше ISystems, когда это необходимо.

Может кто-нибудь, пожалуйста, с этим? (Также, если у кого-то есть лучший способ структурировать мою программу, я также буду благодарен за отзыв)

1 Ответ

2 голосов
/ 24 октября 2019

aspnet имеет очень мощную систему внедрения зависимостей, почему бы вам не использовать ее? Создавая ваши рабочие сервисы без внедрения зависимостей, вам будет сложно использовать все, что предоставляется aspnet.

Поскольку ваши «процессинговые системы», похоже, являются долго работающими сервисами, вы, как правило, будете внедрять их * 1003. *, затем создайте общий сервисный стартер ( отсюда ):

public class BackgroundServiceStarter<T> : IHostedService where T : IHostedService
{
    readonly T _backgroundService;

    public BackgroundServiceStarter(T backgroundService)
    {
        _backgroundService = backgroundService;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        return _backgroundService.StartAsync(cancellationToken);
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return _backgroundService.StopAsync(cancellationToken);
    }
}

и зарегистрируйте их в контейнере DI в ConfigureServices:

// make the classes injectable
services.AddSingleton<FirstProcessingSystem>();
services.AddSingleton<SecondProcessingSystem>();

// start them up
services.AddHostedService<BackgroundServiceStarter<FirstProcessingSystem>>();
services.AddHostedService<BackgroundServiceStarter<SecondProcessingSystem>>();

Теперь, когда вы все правильно настроили, вы можете просто вставить ссылку на ваш концентратор signalR, используя IHubContext<TestHub> context в параметрах конструктора любого класса, который в этом нуждается (как описано в некоторых опубликованных вами ссылках).

...