【问题标题】:Should asyc or non-async methods be used in SignalR Hub?SignalR Hub 中应该使用异步方法还是非异步方法?
【发布时间】:2019-12-02 06:02:52
【问题描述】:

我在SignalR 部分中有以下Hub 类,在这里我定义了与连接相关的所有方法:

public override Task OnConnected()
{
    // here I cannot call this, and need to convert this method async
     await AddToGroup("stockGroup");
    //

    string name = Context.User.Identity.Name;
    _connections.Add(name, Context.ConnectionId);
    return base.OnConnected();
}

public async Task AddToGroup(string groupName)
{
    await Groups.Add(Context.ConnectionId, groupName);
    await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} joined");
}

我查看了许多关于这些连接方法(和其他 Hub 方法)的不同示例,发现其中一些使用 async 方法,而另一些则不使用。在上面的示例中,我需要将 OnConnected() 方法转换为 async 以便调用 AddToGroup() 方法。当然相反的情况也可以,但我不确定哪个更好。那么,对于Hub 中的所有方法,我应该使用async 方法还是非异步方法?任何帮助,将不胜感激。

更新 1: 转换方法(到异步)。

public override async Task OnConnected()
{        
    await AddToGroup("stockGroup");

    string name = Context.User.Identity.Name;
    _connections.Add(name, Context.ConnectionId);
    return base.OnConnected();
}


更新 2:

public override async Task OnConnected()
{
    // #1 There is no async method in "Microsoft.AspNet.SignalR" library. 
    //await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");  

    // #2 I just have sync version of "AddToGroupAsync()" and used it
    await Groups.Add(Context.ConnectionId, "SignalR Users");

    /* #3 I think there is no need to use this custom method in the Hub. 
    Because the same method is already exist in the IGroupManager interface */
    //await AddToGroup("jiraGroup");        

    string name = Context.User.Identity.Name;
    _connections.Add(name, Context.ConnectionId);

    // #4 Here also the same problem and I used sync version of OnConnected()
    //await base.OnConnectedAsync();
    await base.OnConnected();
}

【问题讨论】:

  • 听起来有点基于意见......这取决于你需要什么。是否需要等到执行结束?你说'有一些问题我看到集线器中的异步调用有时可能导致无法连接到集线器',什么问题?你的用例中有它们吗?如果发生这种情况,这对您的用例是否至关重要?
  • @nilsK 对不起,你是对的。我变得更干净了。这个问题似乎是基于意见的,但由于这是我第一次使用 SignalR 并且在构建我的 Hub 类时遇到了这个问题,所以我想为一般情况选择最佳选项(你更喜欢 Hub 方法中的什么?异步或同步?)。当然两者都是可能的,但这两种选择的优缺点是什么?在此先感谢...
  • 恕我直言,你问错问题了。在您写“因为在网络上存在一些问题我看到Hub 中的async 调用可能会导致有时无法连接到集线器。”,您应该询问如何解决这个问题。如果答案是不使用async,那就应该这样。
  • @LGSon 好的,我从我的问题中删除了该部分。我现在可以听听你的意见吗?
  • 征求意见是"off-topic"在SO。

标签: c# asp.net-mvc asp.net-core async-await signalr


【解决方案1】:

如果您需要 await 在方法中,只需添加 asyncasync 是编译器生成异步状态机的标记。

should I use async- 如果需要等待,请使用。

如果您不需要await,只需返回任务本身而不需要async。在这种情况下,您可以避免创建状态机。

也请阅读 Stephen Toub 的Async/Await FAQ

当你用“async”关键字标记一个方法时,你真的在​​告诉 编译器两件事:

  1. 您是在告诉编译器您希望能够使用 方法中的“await”关键字(如果 并且仅当它所在的方法或 lambda 被标记为异步时)。这样做 所以,你告诉编译器使用状态来编译方法 机器,这样该方法将能够暂停然后恢复 在等待点异步。

  2. 您是在告诉编译器“提升” 方法的结果或可能发生的任何异常 返回类型。对于返回 Task 或 Task 的方法,此 表示任何返回值或异常在 该方法存储在结果任务中。对于返回的方法 void,这意味着任何异常都会传播到调用者的 通过当时当前的任何“SynchronizationContext”上下文 方法的初始调用。

【讨论】:

  • 感谢回复。我认为您描述了将方法转换为异步方法。但我需要知道我应该使用哪一个。 Hub 方法中的异步或非异步。有什么原因吗?
  • @hexadecimal 这里的主要思想是你应该返回Task 以支持一路异步执行。如果您需要方法中的任务结果,您应该添加asyncawait。没有任何限制。
  • 非常感谢,投了赞成票。你能看看更新1吗?当我将此方法转换为异步时,我遇到由于“HubBase.OnConnected()”是返回“任务”的异步方法,因此返回关键字后面不能跟对象表达式。您是否打算返回“Task”错误。我尝试使用 Task 等来定义返回类型但不固定。有什么想法吗?
  • @hexadecimal await base.OnConnected();
  • 一个重要的问题:当我转换我的方法时,我发现某些类没有相关调用的异步方法。
【解决方案2】:

您应该将 Async 方法与 Await 一起使用并返回 Task。

异步是病毒式的,所以你应该避免 Async Void

不好

 public async void MethodAsync()
    {
        var result = await SendAsync();
        DoSomething(result);
    }

不错

 public async Task MethodAsync()
    {
        var result = await SendAsync();
        DoSomething(result);
    }

@davidfowl here 提供了一些很棒的异步指南

更新:删除返回

public override async Task OnConnected()
{        
    await AddToGroup("stockGroup");

    string name = Context.User.Identity.Name;
    _connections.Add(name, Context.ConnectionId);
    await base.OnConnected();
}

【讨论】:

  • 您能看看更新 1 吗?当我将此方法转换为异步时,我遇到 由于“HubBase.OnConnected()”是返回“任务”的异步方法,因此返回关键字后面不能跟对象表达式。您是否打算返回 'Task' 错误。我尝试使用 Task 等来定义返回类型但不固定。有什么想法吗?
  • 只需返回任务并使用等待。此方法不需要 Task
  • 是的,我想是的,但仍然是同样的错误,如果我不理会 return 错误就消失了(“return 关键字后面不能跟对象表达式”) .但是我需要返回 base.OnConnected()。有什么想法吗?
  • 公共覆盖异步任务 OnConnected() { await AddToGroup("stockGroup");字符串名称 = Context.User.Identity.Name; _connections.Add(name, Context.ConnectionId); base.OnConnected(); }
  • 非常感谢您和@mtkachenko 的帮助。 await base.OnConnected(); 修复了问题(也如 mtkachenko 所说添加)。由于 mtkachenko 首先发布,我标记了他的答案 :) 但当然对你的两个问题都投了赞成票。问候...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-31
  • 1970-01-01
  • 2017-03-06
  • 2016-10-13
相关资源
最近更新 更多