Передача хаб-контекста не классу контроллера - PullRequest
0 голосов
/ 24 января 2020

Я пытаюсь отправить сообщение клиенту на сервере, используя SignalR

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

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.Configure<ConfigurationModel>(Configuration.GetSection("configurationModel"));

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

        services.AddSignalR();
    }

    // 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("/Error");
        }

        app.UseStaticFiles();
        app.UseCookiePolicy();

        app.UseMvc();

        app.UseSignalR(routes => { routes.MapHub<MoveViewHub>("/movehub"); });
    }
}

В моей программе это:

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();

    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

Это в моем хабе:

public class MoveViewHub : Hub
{
    private async void ReceiveTagNumber(object sender, EventArgs e)
    {
        await Clients.All.SendAsync("ReceivedFromServer", sender.ToString());
    }

    public async Task MoveViewFromServer(float newX, float newY)
    {
        Console.WriteLine(@"Receive position from Server app: " + newX + "/"  + newY);
        await Clients.Others.SendAsync("ReceivedNewPosition", newX, newY);
        //await Clients.All.SendAsync("ReceivedNewPosition", newX, newY);
    }

    public async Task WriteThisMessage(string message)
    {
        Console.WriteLine(message);
        await Clients.Others.SendAsync("ReceivedStatus", "Message was received. Thank you.");
    }

    public override Task OnConnectedAsync()
    {
        Console.WriteLine("Client has connected");
        RfidClass rfidClass = new RfidClass("THE HUB CONTEXT SHOULD BE HERE"); ====>> I NEED TO PASS MY HUBCONTEXT
        rfidClass.sas();
        RfidClass.SendTagNumber += ReceiveTagNumber;
        System.Diagnostics.Process.Start(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Notepad++", @"notepad++.exe"));
        return base.OnConnectedAsync();
    }

    public override Task OnDisconnectedAsync(Exception exception)
    {
        Console.Write("Client has disconnected");
        return base.OnDisconnectedAsync(exception);
    }
}

Это RfidClass:

private IHubContext<MoveViewHub> hubContext;
public RfidClass(IHubContext<MoveViewHub> hubContext)
{
    this.hubContext = hubContext;
}

public void sas()
{
    Start();
}

private void Start()
{
    try
    {
        hubContext.Clients.Others.SendAsync("ReceivedFromServer", "You are connected");
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        throw;
    }
}

Пожалуйста, помогите мне, как сделать это правильно.

1 Ответ

4 голосов
/ 24 января 2020

Вам нужно ввести IServiceProvider в ваш Hub с помощью. NET Core DI (как в стандартный контроллер, ввод с помощью конструктора):

public class MoveViewHub : Hub
{
    private readonly IServiceProvider provider

    public MovieViewHub(IServiceProvider provider)
    {
        this.provider = provider
    }
}

Затем вы можете сделать что-то вроде этого:

    public override Task OnConnectedAsync()
    {
        Console.WriteLine("Client has connected");

        // you need to inject service provider to your hub, then get hub context from
        // registered services
        using (var scope = this.provider.CreateScope())
        {
            // get instance of hub from service provider
            var scopedServices = scope.ServiceProvider;
            var hub = scopedServices.GetRequiredService<IHubContext<MoveViewHub>>

            // pass hub to class constructor
            RfidClass rfidClass = new RfidClass(hub)
            rfidClass.sas();
            RfidClass.SendTagNumber += ReceiveTagNumber;
        }

        System.Diagnostics.Process.Start(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Notepad++", @"notepad++.exe"));
        return base.OnConnectedAsync();
    }

РЕДАКТИРОВАТЬ:

Если вы просто хотите SignalR работать, вам не нужно работать на Hub. Вместо этого сделайте сервис. В этом сервисе введите HubContext<> вашего Hub:

    // you need to make your own class and interface and inject hub context
    public interface ISignalRService
    {
        Task SendMessageToAll(string message);
    }

    public class SignalRService : ISignalRService
    {
        private readonly IHubContext<YourHub> hubContext;

        public SignalRService (IHubContext<NotificationHub> hubContext)
        {
            this.hubContext = hubContext;
        }

        public async Task SendMessageToAll(string message)
        {
            await this.hubContext.Clients.All.SendAsync("ReciveMessage", message);
        }
    }

Затем зарегистрируйте этот сервис в вашем Startup классе:

services.AddScoped<ISignalRService, SignalRService>();

После этого вы сможете позвонить SignalRService Везде, где вы хотите, чтобы нормальный сервис из контейнера .NetCore DI:

private readonly ISignalRService notificationService;


public SomeController(ISignalRService notificationService)
{
    this.notificationService = notificationService;
}

[HttpGet]
public async Task<IActionResult> Send()
{
    await this.notificationService.SendMessageToAll("message");
    return Ok();
}

Вам не нужно немного работать, как RfidClass.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...