Kald SignalR Core Hub-metoden fra controlleren

Kald SignalR Core Hub-metoden fra controlleren

Løsning 1

En anden mulighed er at injicere din HubContext i din controller som:

public VarDesignCommController(IHubContext<VarDesignHub> hubcontext)
{
    HubContext = hubcontext;
    ...
}

private IHubContext<VarDesignHub> HubContext
{ get; set; }

Så kan du også ringe

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

Men så vil du dirigere opkaldsmetoder på alle klienter.

Løsning 2

Du kan også arbejde med indtastede hubs:Simpelt opret en grænseflade, hvor du definerer, hvilke metoder din server kan kalde på klienterne:

public interface ITypedHubClient
{
    Task BroadcastMessage(string name, string message);
}

Arv fra Hub:

public class ChatHub : Hub<ITypedHubClient>
{
    public void Send(string name, string message)
    {
        Clients.All.BroadcastMessage(name, message);
    }
}

Injicer den indtastede hubcontext i din controller, og arbejd med den:

[Route("api/demo")]
public class DemoController : Controller
{
    IHubContext<ChatHub, ITypedHubClient> _chatHubContext;
    public DemoController(IHubContext<ChatHub, ITypedHubClient> chatHubContext)
    {
        _chatHubContext = chatHubContext;
    }

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

Det aktuelle svar besvarer ikke det stillede spørgsmål.

Det enkle svar er, at du ikke direkte kan kalde en hub-metode fra en MVC-controller eller andre steder. Dette er ved design. Tænk på hubben som indeholdende slutpunkterne for SignalR Core-klienter at kalde, ikke for server- eller controllermetoderne.

Her er, hvad Microsoft siger (dette er præ-SignalR Core-dokumentation, men det gælder stadig for SignalR Core):

Hvis der er kode i hub'en, som du skal ringe til, er det bedre at placere den i en ekstern klasse eller tjeneste, der er tilgængelig fra hvor som helst.

Så her er et eksempel, der bruger den enkle indbyggede DI-ramme til ASP.NET Core:

Forudsat at koden du skal ringe til er i DoStuff.cs:

public class DoStuff : IDoStuff
{
    public string GetData()
    {
        return "MyData";
    }
}

public interface IDoStuff
{
    string GetData();
}

I Startup.cs skal du konfigurere en singleton ved hjælp af den indbyggede container:

services.AddSingleton<IDoStuff, DoStuff>();

Hele Startup.cs ser sådan ud:

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

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

        services.AddSingleton<IDoStuff, DoStuff>();
    }

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

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

For din hub-klasse, injicer singletonen, og brug den i en metode:

public class MyHub : Hub
{
    private readonly IDoStuff _doStuff;

    public MyHub(IDoStuff doStuff)
    {
        _doStuff = doStuff;
    }

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

Injicer derefter IHubContext og singletonen i din controller:

public class HomeController : Controller
{
    private readonly IDoStuff _doStuff;
    private readonly IHubContext<MyHub> _hub;

    public HomeController(IDoStuff doStuff, IHubContext<MyHub> hub)
    {
        _doStuff = doStuff;
        _hub = hub;
    }

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

        return View();
    }
}

Selvfølgelig skal dit Javascript eller en anden klient have et show_data-tilbagekald konfigureret.

Bemærk, at vi bruger den injicerede hub-kontekst til at sende data til alle SignalR-klienter:_hub.Clients.All.SendAsync(...)


Dette er nu veldokumenteret her