Saltar al contenido

Llamar al método SignalR Core Hub desde el controlador

No dejes de compartir nuestra web y códigos en tus redes sociales, necesitamos tu ayuda para aumentar nuestra comunidad.

Solución:

Solucion 1

Otra posibilidad es inyectar su HubContext en su controlador como:

public VarDesignCommController(IHubContext hubcontext)

    HubContext = hubcontext;
    ...


private IHubContext HubContext
 get; set; 

Entonces también puedes llamar

await this.HubContext.Clients.All.InvokeAsync("Completed", id);

Pero luego dirigirá los métodos de llamada a todos los clientes.

Solucion 2

También puede trabajar con concentradores escritos: Simple cree una interfaz en la que defina qué métodos puede llamar su servidor en los clientes:

public interface ITypedHubClient

    Task BroadcastMessage(string name, string message);

Heredar de Hub:

public class ChatHub : Hub

    public void Send(string name, string message)
    
        Clients.All.BroadcastMessage(name, message);
    

Inyecte el hubcontext escrito en su controlador y trabaje con él:

[Route("api/demo")]
public class DemoController : Controller

    IHubContext _chatHubContext;
    public DemoController(IHubContext chatHubContext)
    
        _chatHubContext = chatHubContext;
    

    // GET: api/values
    [HttpGet]
    public IEnumerable Get()
    
        _chatHubContext.Clients.All.BroadcastMessage("test", "test");
        return new string[]  "value1", "value2" ;
    

La respuesta actual no responde a la pregunta planteada.

La respuesta simple es que no puede llamar directamente a un método de concentrador desde un controlador MVC o desde otro lugar. Esto es por diseño. Piense en el concentrador como que contiene los puntos finales para que los clientes de SignalR Core llamen, no para los métodos del servidor o del controlador.

Esto es lo que dice Microsoft (esta es la documentación anterior a SignalR Core, pero aún se aplica a SignalR Core):

No crea una instancia de la clase Hub ni llama a sus métodos desde su propio código en el servidor; todo eso lo hace la canalización de SignalR Hubs. SignalR crea una nueva instancia de su clase Hub cada vez que necesita manejar una operación de Hub, como cuando un cliente se conecta, desconecta o realiza una llamada de método al servidor.

Debido a que las instancias de la clase Hub son transitorias, no puede usarlas para mantener el estado de una llamada a un método a la siguiente. Cada vez que el servidor recibe una llamada a un método de un cliente, una nueva instancia de su clase Hub procesa el mensaje. Para mantener el estado a través de múltiples conexiones y llamadas a métodos, use algún otro método, como una base de datos o una static variable en la clase Hub, o una clase diferente que no se derive de Hub. Si persiste los datos en la memoria, utilizando un método como un static variable en la clase Hub, los datos se perderán cuando el dominio de la aplicación se recicle.

Si desea enviar mensajes a los clientes desde su propio código que se ejecuta fuera de la clase Hub, no puede hacerlo creando una instancia de la clase Hub, pero puede hacerlo obteniendo una referencia al objeto de contexto SignalR para su clase Hub …

Si hay un código en el concentrador al que necesita llamar, es mejor colocarlo en una clase o servicio externo que sea accesible desde cualquier lugar.

Así que aquí hay un ejemplo que usa el marco DI integrado simple para ASP.NET Core:

Suponiendo que el código al que necesita llamar está en DoStuff.cs:

public class DoStuff : IDoStuff

    public string GetData()
    
        return "MyData";
    


public interface IDoStuff

    string GetData();

En Startup.cs, configure un singleton usando el contenedor integrado:

services.AddSingleton();

El Startup.cs completo se ve así:

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(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.AddSignalR();

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

        services.AddSingleton();
    

    // 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("/Home/Error");
            app.UseHsts();
        

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseCookiePolicy();
        app.UseSignalR(routes =>
        
            routes.MapHub("/myhub");
        );

        app.UseMvc(routes =>
        
            routes.MapRoute(
                name: "default",
                template: "controller=Home/action=Index/id?");
        );
    

Para su clase de concentrador, inyecte el singleton y utilícelo en un método:

public class MyHub : Hub

    private readonly IDoStuff _doStuff;

    public MyHub(IDoStuff doStuff)
    
        _doStuff = doStuff;
    

    public string GetData()
    
       return  _doStuff.GetData();
    

Luego, en su controlador, inyecte el IHubContext y el singleton:

public class HomeController : Controller

    private readonly IDoStuff _doStuff;
    private readonly IHubContext _hub;

    public HomeController(IDoStuff doStuff, IHubContext hub)
    
        _doStuff = doStuff;
        _hub = hub;
    

    public async Task Index()
    
        var data = _doStuff.GetData();
        await _hub.Clients.All.SendAsync("show_data", data);

        return View();
    

Por supuesto, su Javascript u otro cliente debe tener configurada una devolución de llamada show_data.

Observe que estamos usando el contexto del concentrador inyectado para enviar los datos a todos los clientes de SignalR: _hub.Clients.All.SendAsync (…)

Esto ahora está bien documentado aquí.

Puede inyectar una instancia de IHubContext en un controlador agregándolo a su constructor:

public class HomeController : Controller

    private readonly IHubContext _hubContext;

    public HomeController(IHubContext hubContext)
    
        _hubContext = hubContext;
    

Ahora, con acceso a una instancia de IHubContext, puede llamar a métodos de concentrador como si estuviera en el propio concentrador.

public async Task Index()

    await _hubContext.Clients.All.SendAsync("Notify", $"Home page loaded at: DateTime.Now");
    return View();

Reseñas y calificaciones

Si estás de acuerdo, tienes el poder dejar un ensayo acerca de qué le añadirías a esta reseña.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *