【问题标题】:Invoking SignalR Hub not working for Asp.Net Core Web API调用 SignalR Hub 不适用于 Asp.Net Core Web API
【发布时间】:2019-01-28 19:03:53
【问题描述】:

我是 SignalR 的新手。我正在尝试设置一个 Asp.Net Core WebAPI,以便其他客户端可以使用 SignalR 连接到它并获取实时数据。 我的 Hub 课程是:

public class TimeHub : Hub
{
    public async Task UpdateTime(string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", message);
    }
}

我有一个接力班如下:

public class TimeRelay : ITimeRelay
{
    private readonly IHubContext<TimeHub> _timeHubContext;

    public TimeRelay(IHubContext<TimeHub> context)
    {

        _timeHubContext = context;
        Task.Factory.StartNew(async () =>
        {
            while (true)
            {
                await context.Clients.All.SendAsync("UpdateTime", DateTime.Now.ToShortDateString());
                Thread.Sleep(2000);
            }
        });
    }
}

启动类:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    services.AddSignalR();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseDeveloperExceptionPage();

    app.UseHttpsRedirection();

    app.UseSignalR((x) =>
    {
        x.MapHub<TimeHub>("/timeHub");
    });
    app.UseMvc();
}

客户端是一个控制台应用,代码是:

class Program
{    
    static Action<string> OnReceivedAction = OnReceived;

    static void Main(string[] args)
    {
        Connect();
        Console.ReadLine();
    }

    private static async void Connect()
    {
        var hubConnectionBuilder = new HubConnectionBuilder();

        var hubConnection = hubConnectionBuilder.WithUrl("http://localhost:60211/timeHub").Build();

        await hubConnection.StartAsync();

        var on = hubConnection.On("ReceiveMessage", OnReceivedAction);

        Console.ReadLine();    
        on.Dispose();
        await hubConnection.StopAsync();
    }

    static void OnReceived(string message)
    {
        System.Console.WriteLine($"{message}");
    }
}

我尝试调试应用程序。客户端成功连接到TimeHub。当客户端连接时,Clients.All 中的连接数从 0 变为 1。但是,当await context.Clients.All.SendAsync("UpdateTime", DateTime.Now.ToShortDateString());被执行时,TimeHub中的UpdateTime函数没有被执行,客户端也没有收到任何消息。

我尝试在TimeRelay 类的Clients.All.SendAsync 中使用"UpdateTime"、"SendMessage" 和"ReceiveMessage" 作为方法。没有任何效果。有人可以指出我在这方面的错误。

【问题讨论】:

  • 你在哪里打电话给TimeRelay? TimeRelay 和 TimeHub 在同一个项目中吗?您对TimeRelay 的预期结果是什么?一般来说,Clients.All.SendAsync,它用于调用客户端方法而不是服务器方法。如果您更喜欢从TimeRelay 调用TimeHub.UpdateTime,请尝试注册TimeHub 类并调用TimeHub.UpdateTime(),或者直接从TimeRelay 调用ReceiveMessage 通过await context.Clients.All.SendAsync("ReceiveMessage", DateTime.Now.ToShortDateString());。
  • 现在,我从 HomeController 调用 TimeRelay。来回答你。是的,TimeRelay 和 TimeHub 在同一个项目中。我会尝试注册TimeHub。另外,我确实在Clients.All.SendAsync 中尝试过"ReceiveMessage",但没有成功。
  • 我想知道在控制器动作中启动一个新线程是否合理。我在控制器index 操作中调用TimeHub 进行了测试,它仅适用于第二个请求。我会继续检查这种行为。
  • @TaoZhou 谢谢。在 Controller 中启动线程只是一种临时方法。坦率地说,目前,我无法想出另一种方式来启动它。首先,我试图让 SignalR 先工作。
  • @AlenAlex 就像上面评论中提到的Clients.All.SendAsync 将直接调用客户端方法。然而,上面还提到了手动实例化集线器和调用集线器方法。这是非常错误的,永远不要获取集线器实例,因为它不会设置正确的属性。如果您想从控制器调用“集线器方法”,则需要重构代码,以便集线器方法和控制器调用相同的代码,然后您可以从集线器和控制器使用Clients.All.SendAsync 发送到客户端使用重构方法返回的数据。

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


【解决方案1】:

对于Clients,如果没有客户端连接到服务器,它将为空。对于同时启动Asp.Net Core SignalR和Console App,Clients可能为空,因为Index可能在Console App连接signalR服务器之前被调用。

尝试以下步骤:

  1. 更改TimeHub

    public class TimeHub: Hub
    {
    public async Task UpdateTime(string message)
    {
        if (Clients != null)
        {
            await Clients.All.SendAsync("ReceiveMessage", message);
        }
    }
    }
    
  2. 注册TimeHub

     services.AddSingleton<TimeHub>();  
    
  3. 控制器

     public class HomeController : Controller
    {
    private readonly TimeHub _timeHub;
    public HomeController(TimeHub timeHub)
    {
        _timeHub = timeHub;
    }
    public IActionResult Index()
    {
        Task.Factory.StartNew(async () =>
        {
            while (true)
            {
                try
                {
                    await _timeHub.UpdateTime(DateTime.Now.ToShortDateString());
                    Thread.Sleep(2000);
                }
                catch (Exception ex)
                {
    
                }
            }
        });
        return View();
    }
    

【讨论】:

  • 嗨@TaoZhou。谢谢。这现在按要求工作。但是,我认为这不是正确的做法。我相信 IHubContext 是正确的做法。正如原始问题中所说,它似乎对我不起作用。
  • @AlenAlex 这种方式怎么样?更改TimeRelaylike public TimeRelay(IHubContext&lt;TimeHub&gt; context) 并将while(true) 替换为if (Clients != null) { await Clients.All.SendAsync("ReceiveMessage", message); }
  • service.addsingleton 调用有什么作用?
【解决方案2】:

我得到它的工作,并认为我会在这里回答它。感谢@TaoZhou 的提示。

我的错误是从服务器发送“UpdateTime”并在客户端等待“ReceiveMessage”。

理想情况下,代码应如下所示:

SignalR 服务器:
await context.Clients.All.SendAsync("UpdateTime", DateTime.Now.ToShortDateString());

SignalR 客户端:
var on = hubConnection.On("UpdateTime", OnReceivedAction);

在这种情况下,从服务器发送的任何消息都会立即在客户端收到。
请参阅问题中提供的代码以获取更多信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-04
    相关资源
    最近更新 更多