5

在 SignalR 连接设置期间,如何获取在其他功能正常的 Web 应用程序中发生的异常的完整堆栈?

背景

我是使用 C# 客户端维护 Web 应用程序的团队的一员,该应用程序使用极其基本的 SignalR 设置(2.2 版)在长时间运行的服务器进程期间有效地提供有关进度的推送通知。比如开箱即用,

app.MapSignalR();
HubConnection connection = new HubConnection(_applicationConfiguration.ApiBaseUri + "/signalr");
await connection.Start();

基本的。我们的一些客户端在远程服务上运行,并定期遇到 Web 应用程序的其他功能正常工作的问题,但调用的客户端代码connection.Start()返回 500 内部服务器错误,没有更多信息。他们可以通过刷新远程连接来解决这个问题,但这并不理想,所以我试图获取一些关于连接设置过程中发生此错误的位置的信息。

问题

按照有关在 MSDN 上为 SignalR 设置错误处理的信息,我尝试通过将以下管道模块插入到中来模拟问题GlobalHost.HubPipeline

public class HubErrorHandlingModule : HubPipelineModule
  {
    public override Func<IHub, Task> BuildConnect(Func<IHub, Task> connect)
    {
      throw new InvalidOperationException("Testing Connection Exceptions");
    }

    protected override void OnIncomingError(ExceptionContext exceptionContext, 
      IHubIncomingInvokerContext invokerContext)
    {
      // some logging happens here
      base.OnIncomingError(exceptionContext, invokerContext);
    }
  }

它有点工作,因为我可以看到管道代码中抛出了异常,并且我的测试 C# 客户端也看到了 500 内部服务器错误,没有更多信息。

但它也有点行不通,因为我已经在断点中删除并且 OnIncomingError 代码永远不会被命中。这是有道理的,因为它不是导致异常的任何 Hub 方法中的代码,但我不知道这个异常发生在哪里;它可能在客户端调用期间的任何地方connection.Start

我也尝试过传递替代方案HubConfigurationEnableDetailedErrors = true但这似乎并没有改善任何东西。

从哪里获得完整的堆栈跟踪并不重要,因为我同时控制服务器和客户端代码,但为了理解他们的问题,我需要在某处查看完整的跟踪。

我尝试了什么以及为什么它不起作用

app.MapSignalR(new HubConfiguration { EnableDetailedErrors = true });

我认为这是为了显示Hub处理中的详细错误,而不是连接握手?假设它的目的是发送一条标记为错误的消息,即使它从未冒泡给任何消费者,也可能被连接跟踪。很遗憾...

var writer = new StreamWriter("C:\\Logs\\ClientLog.txt");
writer.AutoFlush = true;
connection.TraceLevel = TraceLevels.All;
connection.TraceWriter = writer;

一旦我删除了故意的管道错误,这确实会跟踪到 SignalR 后端的成功通信。但是当我重新设置它时,我看到的只是建立连接的失败尝试和 500 内部服务器错误。没有痕迹。

<system.diagnostics>
  <sharedListeners ... >
  <switches ...>
  <sources ...>
  <trace autoflush="true" />
</system.diagnostics>

在 MSDN 跟踪详细信息GitHub 上的此评论之后进行设置。这两组细节都不起作用。当我通过将管道异常移动到不同的管道事件来进行游戏时,有时我可以看到堆栈跟踪出现在 SignalR.HubDispatcher 源中,仅在 GitHub 详细信息中提到,但是当我在建立连接后抛出异常时会发生这种情况并且到达客户端的错误与 500 内部服务器错误不同,因此这可能发生得太晚了,无法成为客户端安装的任何问题。

4

2 回答 2

1

就我而言,我必须将 SignalR.cs 放在我的根路径中。

在此处输入图像描述

然后在视图中我包含脚本:

<script src="~/signalr/hubs"></script>

这就是我的 SignalR.cs 的样子:

public class NotificationHub : Hub
{
    public void SendUpdateNotification(string message)
    {
        // message = "show" / "hide"
        if (message.Equals("show"))
            Config._MaintenanceMode = true;
        else
            Config._MaintenanceMode = false;

        // Call the broadcastUpdate method to update clients.
        Clients.All.broadcastUpdate(message);
    }
}
于 2020-03-12T03:45:38.990 回答
-1

要处理 SignalR 引发的错误,您可以为连接对象上的错误事件添加处理程序

connection.Error += ex => Console.WriteLine("SignalR error: {0}", ex.StackTrace);

要处理来自方法调用的错误,请将代码包装在 try-catch 块中。

HubConnection connection = new HubConnection(_applicationConfiguration.ApiBaseUri + "/signalr");
try
{   
    await connection.Start(); 
}
catch (Exception ex)
{
    Console.WriteLine("Error " + ex);
}

要启用详细的错误消息以进行故障排除,

var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
App.MapSignalR(hubConfiguration);

在您的代码中,集线器管道模块我没有看到您正在记录/打印错误

Console.WriteLine("Exception " + exceptionContext.Error.Message);
base.OnIncomingError(exceptionContext, invokerContext);

现在连接我们创建的自定义 HubPipelineModule,这是在启动类中实现的

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        GlobalHost.HubPipeline.AddModule(new HubErrorHandlingModule());

        app.MapSignalR();
    }
}

参考:

SignalR 通知用户断开连接
SingalR 如何处理错误
SignalR 500 内部服务器错误

于 2020-03-07T09:24:10.137 回答