Получение контекста концентратора для ASPNet.Core Signal-R (.NET Core 2.1) RC - PullRequest
0 голосов
/ 01 июня 2018

Я использую ASP.NET Core 2.1 RC1.Я также использую для этого Signal-R (находится здесь):

https://docs.microsoft.com/en-us/aspnet/core/signalr/javascript-client?view=aspnetcore-2.1

Я создаю консольное приложение .NET Core, которое содержит Kestrel, и использую Signal-R.Я установил точно , поскольку в документации по началу работы указывается настройка запуска.

Все это прекрасно работает.Я могу подключиться к нему, получить свой HTML-код со скриптом signal-R, получить сообщения, созданные с помощью Clients.All.SendAsync.Отлично работает.

НО Я хочу иметь возможность отправлять сообщения клиентам, находящимся за пределами Хаба.Где в моем приложении происходит какое-то событие, и клиентам отправляется сообщение.В полном .NET я бы использовал GlobalHost и получил контекст.В ALL моих поисках по переполнению стека они ссылаются на то, что больше не работает или не используется внутри контроллера REST API, который передается в IHubContext.

В моем файле program.cs есть прослушиватель событий, и когда событие запускается, я бы хотел иметь возможность отправить сообщение на мой UserInterfaceHub.

Итак, как это сделать?Я получаю контекст концентратора в Program.CS - так что я могу отправлять ему сообщения (вызывать метод SwitchUI) из делегата события, который есть у меня в Program.CS?

StartUp.cs

public void ConfigureServices(IServiceCollection services)  {
    services.Configure<CookiePolicyOptions>(options => {
        options.CheckConsentNeeded      = context => true;
        options.MinimumSameSitePolicy   = SameSiteMode.None;
    });
    services.AddMvc();

    services.AddCors(options => options.AddPolicy("CorsPolicy",
        builder =>  {builder.AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin().AllowCredentials();}));
    services.AddSignalR();

    var provider = services.BuildServiceProvider();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
    if (env.IsDevelopment())    app.UseDeveloperExceptionPage();

    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseCors("CorsPolicy");
    app.UseSignalR(routes => {routes.MapHub<UserInterfaceHub>("/uihub");});
    app.UseMvc();



    //app.Run(async (context) =>{await context.Response.WriteAsync("Active");});
}

Program.CS

    CreateWebHostBuilder(args)
        .UseKestrel()
        .UseUrls("http://0.0.0.0:" + appProperties.HostPort.ToString().Trim())
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseIISIntegration()
        .Build()
    .Start();

UserInterfaceHub.cs

namespace InterfaceModule.Hubs  {
    public class UserInterfaceHub : Hub  {
        public async Task SwitchUI(string message) {
            await Clients.All.SendAsync("ReceiveEvent", message);
        }

        public override async Task OnConnectedAsync()   {
            //await SwitchUI("HOWDY NEW PERSON!");
            await base.OnConnectedAsync();
        }
    }
}

edit добавление ясности.

В Program.CS у меня есть делегат этого события: // теперь, когда мы готовы, начните слушать.жду

deviceClient.SetInputMessageHandlerAsync(ModuleProperties.InputName, OnReceiveEvent, deviceClient);
            Console.WriteLine("INIT: Event Message Input handler created: [{0}]", ModuleProperties.InputName);

что это:

        static async Task<MessageResponse> OnReceiveEvent(Message message, object userContext)  {
//HOW DO I REACH THE HUB FROM HERE SO I CAN SEND A MESSAGE TO THE LISTENERS?
}

Ответы [ 3 ]

0 голосов
/ 02 июня 2018

Эта строка кода:

 app.UseSignalR(routes => {routes.MapHub<UserInterfaceHub>("/uihub");});

зарегистрирует ваш концентратор в контейнере DI.Затем, чтобы получить к нему доступ, вы можете использовать инжектор конструктора для внедрения в IHubContext<UserInterfaceHub> (это работает, например, в веб-контроллере) или получить к нему доступ непосредственно из контейнера DI, выполнив следующие действия:

 var hub = app.ApplicationServices.GetRequiredService<IHubContext<UserInterfaceHub>>();

(например, если выполняется в методе startup.cs Configure)

Если у вас нет доступа к app.ApplicationServices, который по сути является IServiceProvider в том месте, где вам нужен доступ к концентратору, тогда вам нужно будет либо 1) заставить этот класс работать с внедрением зависимостей для внедрения в IHubContext<UserInterfaceHub> или IServiceProvider 2) настроить глобальную переменную static Services через Configure, чтобы вы могли иметь доступ к одному из нихили найдите какой-то другой способ доступа к контейнеру DI (он же IServiceProvider), чтобы получить концентратор с помощью приведенной выше строки кода.

Если у вас есть концентратор, отправка сообщения зарегистрированным клиентам выполняется просто.как вызов метода на вашем хабе.

 await hub.Clients.All.SendAsync("ReceiveEvent", message); 
0 голосов
/ 27 июня 2018

Я столкнулся с подобной ситуацией, и вот как ее решить:

На вашем уровне обслуживания создайте интерфейс, называемый чем-то вроде ISendHubMessage.Иметь метод Send (), который принимает параметры, которые вы хотите отправить через SignalR.Создайте класс в том же файле с именем SendHubMessage, который реализует интерфейс.Пусть он просто вернет.

В вашем проекте верхнего уровня (где расположен файл Startup.cs) создайте еще один класс с именем SendHubMessage, который реализует тот же интерфейс ISendHubMessage из вашего уровня Service.В этом SendHubMessage вы можете использовать DI, чтобы добраться до концентратора, как описано выше.Этот метод выполняет фактическую логику отправки через SignalR.

В свой метод запуска ConfigureServices () добавьте следующую строку:

services.AddTransient <"Service" .ISendHubMessage, "TopLevel".SendHubMessage> ();

(где «Service» - это пространство имен вашего проекта уровня сервиса, а «TopLevel» - пространство имен вашего проекта верхнего уровня).

What you 'в этой строке говорится: «Когда объект запрашивает зависимость ISendHubMessage от сервисного уровня, предоставьте ему класс SendHubMessage, определенный в моем проекте верхнего уровня».

Наконец, во всех местах кода вневашего проекта верхнего уровня, который вы хотите отправлять сообщения через концентратор, вставьте эту зависимость ISendHubMessage в конструктор.Затем вы можете обратиться к нему в методах класса, и когда вы вызовете Send (), он вызовет метод Send (), определенный в вашем классе SendHubMessage в вашем проекте верхнего уровня.

0 голосов
/ 01 июня 2018

Ваш вопрос немного неясен, но я предполагаю, что вы хотите заменить следующее на что-то, что может отправить сообщение через ваш хаб:

app.Run(async (context) =>{await context.Response.WriteAsync("Active");});

Так как это в вашемConfigure метод, вы можете просто добавить IServiceCollection services к вашим Configure параметрам методов.Затем вы можете сделать:

var hub = services.GetRequiredService<IHubContext<MyHub>>();

Однако я не уверен, что в конечном итоге это действительно поможет.При запуске у вас логически не будет клиентов с подписками.В результате отправка сообщения через ваш хаб в этот момент, по сути, ни к чему не приведет.К тому времени, когда пользователь действительно заходит на ваш сайт и подключается к вашему хабу, эта часть вашего приложения уже запущена и больше не будет попадать.

...