如何在Controller以外的地方调用SignalR Clients.All.InvokeAsync()?

时间:2018-01-26 18:03:52

标签: c# dependency-injection asp.net-core asp.net-core-webapi asp.net-core-signalr

我可以通过构造函数中的DI在我的.NET Core WebAPI控制器中访问我的IHubContext<MyHub>精细和花花公子,但我也想在其他地方访问它。

具体来说,当我从RabbitMQ使用消息时,有时我想通过_myHubContext.Clients.All.InvokeAsync()更新客户端,但我无法弄清楚如何获取它。

我也在寻找在控制器之外做这种事情的文档时遇到了问题。

任何帮助都将不胜感激。

修改

要添加一些细节,以及我的问题可能产生的原因,我正在尝试访问ConfigureServices类中的IHubContext(以及我在Startup中注册的一些服务),特别是在IApplicationLifetime ApplicationStartedApplicationStopped期间调用RabbitMQ使用者的连接和断开方法。

我是正确的猜测我可能无法访问Startup课程中的注册服务?如果是这样,我将如何开始这些服务?

更新

services.AddSignalR()以及在启动时调用的一些服务移至WebHost.ConfigureServices中的Program.cs解决了我的一些问题,但当然还有更多。

当我从RabbitMQ收到消息时,我的JS客户端上没有收到任何消息,但我的客户端已成功连接。 “很奇怪......”我想。为了获得更多信息,我在控制器中连接了一个GET动作,通过SignalR Hub发送了一些内容。每当我打电话给GET时,它都有效...... IHubContext<MyHub>。我通过RabbitMQ监听器中的构造函数得到hubContext,就像我对控制器一样。

新问题:在控制器中注入的内容与在启动时注册的服务中注入的内容不同吗?怎么这样,我该如何克服呢?

一些代码可以使用它......

摘录自Program.cs

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseKestrel()
        .UseIISIntegration()
        .ConfigureServices(services => {
            services.AddSignalR();
            services.AddTransient<ISubscriber, Subscriber>();
            services.AddTransient<IDataService, DataService>();
            services.AddTransient<IHealthCheckProcessor, HealthCheckProcessor>();
            services.AddTransient<INodeProcessor, NodeProcessor>();
        })
        .UseStartup<Startup>()
        .Build();

来自Startup.cs

public class Startup
{
    public Startup(IConfiguration _configuration, ISubscriber _subscriber)
    {
        configuration = _configuration;
        subscriber = _subscriber;
    }
    public IConfiguration configuration { get; }
    public ISubscriber subscriber { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors();
        services.AddMvc();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime applicationLifetime)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseCors(builder => builder
            // CORS stuff);

        app.UseSignalR(routes =>
        {
            routes.MapHub<StatusHub>("Status");
        });
        app.UseMvc();
        applicationLifetime.ApplicationStarted.Register(OnStartup);
        applicationLifetime.ApplicationStopping.Register(OnShutdown);
    }

    private void OnStartup() {
        // MessageBroker stuff
        subscriber.Start(messageBroker);
    }

    private void OnShutdown() {
        subscriber.Stop();
    }
}

来自Subscriber.cs

public class Subscriber : ISubscriber {
    public static IConnection connection;
    public static IModel channel;
    public IHubContext<StatusHub> hubContext;

    public static IHealthCheckProcessor healthCheckProcessor;
    public static INodeProcessor nodeProcessor;

    public Subscriber(IHubContext<StatusHub> _hubContext, INodeProcessor _nodeProcessor, IHealthCheckProcessor _healthCheckProcessor)
    {
        connection = new ConnectionFactory().CreateConnection();
        channel = connection.CreateModel();
        hubContext = _hubContext;
        nodeProcessor = _nodeProcessor;
        healthCheckProcessor = _healthCheckProcessor;
    }

    public void Start(MessageBroker messageBroker)
    {
        var factory = new ConnectionFactory() { HostName = messageBroker.URL }.CreateConnection();

        foreach (Queue queue in messageBroker.Queues)
        {
            channel.QueueDeclare(
                queue: queue.Name,
                durable: queue.Durable,
                exclusive: queue.Exclusive,
                autoDelete: queue.AutoDelete,
                arguments: null
            );

            EventingBasicConsumer consumer = new EventingBasicConsumer(channel);

            consumer.Received += (model, ea) =>
            {
                byte[] body = ea.Body;
                string message = Encoding.UTF8.GetString(body);

                RouteMessage(queue, message);
            };

            channel.BasicConsume(
                    queue: queue.Name,
                    autoAck: queue.AutoAck,
                    consumer: consumer
                );
            hubContext.Clients.All.InvokeAsync("Send", "It worked - from the subscriber");
        }
    }

    public void RouteMessage(Queue queue, string message) {
        if(queue.Name == "discovery") {
            nodeProcessor.Process(message);
        }
        if(queue.Name == "health") {
            healthCheckProcessor.Process(message);
        }
    }

    public void Stop()
    {
        Console.WriteLine("Terminating connection to RabbitMQ instance.");
        channel.Close(200, "Goodbye");
        connection.Close();
    }
}

来自HealthCheckProcessor.cs

public class HealthCheckProcessor : IHealthCheckProcessor {
    private IDataService dataService;
    private IHubContext<StatusHub> hubContext;

    public HealthCheckProcessor(IDataService _dataService, IHubContext<StatusHub> _hubContext)
    {
        dataService = _dataService;
        hubContext = _hubContext;
    }
    public void Process(string message) {
        HealthCheck health = JsonConvert.DeserializeObject<HealthCheck>(message);
        Node node = dataService.GetSingle(health.NodeId);
        node.Health = health;

        dataService.Update(node);
        Console.WriteLine("It's sending.");
        hubContext.Clients.All.InvokeAsync("Send", "It worked - from the processor");
    }
}

来自Controller:

[Route("api/[controller]")]
public class MyController: Controller
{
    private IDataService _dataService;
    private readonly IConfiguration configuration;
    private static IHubContext<StatusHub> hubContext;

    public NodesController(IConfiguration config, IDataService dataService, IHubContext<StatusHub> _hubContext)
    {
        _dataService = dataService;
        configuration = config;
        hubContext = _hubContext;
    }

    [HttpGet]
    public string Get()
    {
        hubContext.Clients.All.InvokeAsync("Send", "Blarg!");
        return "Well, I tried.";
    }
}

1 个答案:

答案 0 :(得分:2)

您正在尝试访问请求时无法使用的服务。

java.lang.ClassCastException: application.model.Usuario cannot be cast to application.model.Usuario at application.core.user.dao.implementation.UserDaoImplementation.findById(UserDaoImplementation.java:35) at application.core.user.service.implementation.UserServiceImplementation.findById(UserServiceImplementation.java:17) at application.security.UserDetailsApp.loadUserByUsername(UserDetailsApp.java:34) at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:114) at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:144) at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174) at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199) at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748) 专门在Configure之后调用,以便可以访问注册的所有服务。

ConfigureServices

现在,您应该能够在构建主机时删除便利public class Startup { public Startup(IConfiguration _configuration) { configuration = _configuration; } public IConfiguration configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddCors(); services.AddMvc(); services.AddSignalR(); services.AddTransient<ISubscriber, Subscriber>(); services.AddTransient<IDataService, DataService>(); services.AddTransient<IHealthCheckProcessor, HealthCheckProcessor>(); services.AddTransient<INodeProcessor, NodeProcessor>(); } public void Configure( IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime applicationLifetime, IServiceProvider sp ) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseCors(builder => builder // CORS stuff); app.UseMvc(); app.UseSignalR(routes => { routes.MapHub<StatusHub>("Status"); }); //At this point all the necessary dependencies have been registered and configured var subscriber = sp.GetService<ISubscriber>(); applicationLifetime.ApplicationStarted.Register(() => OnStartup(subscriber)); applicationLifetime.ApplicationStopping.Register(() => OnShutdown(subscriber)); } private void OnStartup(ISubscriber subscriber) { // MessageBroker stuff subscriber.Start(messageBroker); } private void OnShutdown(ISubscriber subscriber) { subscriber.Stop(); } }

ConfigureServices