How can I get the full stack of an exception that's happening in an otherwise functioning Web application during SignalR connection setup?
I'm part of a team maintaining a Web application with C# clients that uses an extremely basic SignalR setup (version 2.2) to effectively deliver push notifications about progress during long-running server processes. Like, out-of-the-box,
app.MapSignalR();
HubConnection connection = new HubConnection(_applicationConfiguration.ApiBaseUri + "/signalr");
await connection.Start();
basic. Some of our clients run on remoting services and periodically run into an issue where the other functions of the Web application work fine, but the client code that calls connection.Start()
returns a 500 internal server error with no further information. They can address it by refreshing the remote connection but this is less than ideal, so I'm trying to get some information about where in the connection setup process this error is happening.
Following the information about setting up error handling for SignalR on MSDN, I've tried to simulate the problem by inserting the following pipeline module into the 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);
}
}
and it kind of works, in that I can see the exception get thrown in the pipeline code, and my test C# client is also seeing a 500 internal server error with no further information.
But it also kind of doesn't work, in that I've dropped in breakpoints and the OnIncomingError code is never hit. That sort of makes sense, since it's not code in any Hub method that's causing the exception, but I don't know where this exception is happening; it could be anywhere during the client call to connection.Start
.
I've also tried passing in an alternate HubConfiguration
with EnableDetailedErrors = true
but that doesn't seem to improve anything.
It doesn't really matter where I get the full stack trace, since I control both the server and the client code, but in order to understand their problem I need to see the full trace somewhere.
app.MapSignalR(new HubConfiguration { EnableDetailedErrors = true });
I think this is meant to show detailed errors from Hub
processing, not connection handshaking? Supposedly it's meant to send a message tagged as an error that might be traced by the connection even if it's never bubbled up to any consumer. Unfortunately...
var writer = new StreamWriter("C:\\Logs\\ClientLog.txt");
writer.AutoFlush = true;
connection.TraceLevel = TraceLevels.All;
connection.TraceWriter = writer;
This does trace successful communication to the SignalR backend, once I remove the deliberate pipeline error. But when I set it back up, all I see is a failed attempt to establish the connection and a 500 internal server error. No trace.
<system.diagnostics>
<sharedListeners ... >
<switches ...>
<sources ...>
<trace autoflush="true" />
</system.diagnostics>
Set up both after the MSDN trace details and this commentary on GitHub. Neither set of details works. As I play around by moving the pipeline exception to different pipeline events, I can sometimes see a stack trace show up in the SignalR.HubDispatcher source mentioned only in the GitHub details, but it happens when I throw the exception after the connection's been established and what arrives at the client side is a different error than just a 500 internal server error, so that's probably happening too late to be whatever's going wrong at the client installation.
In my case I have to put the SignalR.cs in my root path.
Then in the view I include the script:
<script src="~/signalr/hubs"></script>
This is what my SignalR.cs looks like:
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With