We added SignalR to one of our microservices and Angular frontend using the following guide: https://docs.abp.io/en/abp/latest/SignalR-Integration
When we try to use it from our frontend, the two negotiation requests resolve fine, but then when it tries to connect we get a TimeOut Exception. When we try to debug the OnConnectedAsync method in the hub we see that it doesn't stop at a breakpoint, so I understand it doesn't even execute it. The microservice (OperacionesService) doesn't throw any errors.
This is the Hub in our microservice:
public class DemoHub: AbpHub<PlanillaDespachosAppService>
{
private readonly IPlanillaDespachoRepository _planillaDespachoRepository;
public DemoHub(IPlanillaDespachoRepository planillaDespachoRepository)
{
_planillaDespachoRepository = planillaDespachoRepository;
}
public async override Task OnConnectedAsync()
{
var x = CurrentUser.Id;
Console.WriteLine(x);
await base.OnConnectedAsync();
}
public async override Task OnDisconnectedAsync(Exception exception)
{
var x = CurrentUser.Id;
Console.WriteLine(x);
await base.OnDisconnectedAsync(exception);
}
}
This is the OnApplicationInitialization in our WebGateway:
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCorrelationId();
app.UseCors();
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Web Gateway API");
var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>();
options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]);
});
app.UseAbpSerilogEnrichers();
app.MapWhen(
ctx => ctx.Request.Path.ToString().StartsWith("/api/abp/api-definition") ||
ctx.Request.Path.ToString().TrimEnd('/').Equals(""),
app2 =>
{
app2.UseRouting();
app2.UseConfiguredEndpoints();
}
);
app.UseWebSockets();
app.UseOcelot().Wait();
}
The SignalR config in appsettings.json of WebGateway:
{
"DownstreamPathTemplate": "/signalr-hubs/{everything}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 44878
}
],
"UpstreamPathTemplate": "/signalr-hubs/{everything}",
"UpstreamHttpMethod": [
"Put",
"Delete",
"Get",
"Post"
]
},
{
"DownstreamPathTemplate": "/ws",
"UpstreamPathTemplate": "/",
"DownstreamScheme": "ws",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 44878
}
]
}
The connection methods in our frontend (Angular):
private createConnection() {
if (!this.connection) {
this.connection = new HubConnectionBuilder()
.withUrl('https://localhost:44325/signalr-hubs/demo',
{
accessTokenFactory: () => this.userService.getAccessToken(),
transport: HttpTransportType.ServerSentEvents
})
// .withUrl('/Notifications',
// {
// accessTokenFactory: () => userId,
// // THis will use websockets by default, if it does not work try uncommenting this line
// // transport: HttpTransportType.ServerSentEvents
// })
.withAutomaticReconnect()
// .configureLogging(LogLevel.Debug)
.build();
}
}
connectNotifications() {
if (!this.userService.hasValidAccessToken()) return;
this.createConnection();
if (this.connection.state == HubConnectionState.Disconnected)
this.connection
.start()
.catch(err => console.log('Error while starting connection to notification service: ' + err));
this.connection.on('1q1q', console.log);
}
sendMessage(val: string) {
console.log(this.connection.state);
this.connection.send('1q1q', val)
}
When we load the page that tries to connect to the hub we get the following logs and Network status:
WebGateway:
2024-03-12 16:03:43.651 -03:00 [INF] Request starting HTTP/2 OPTIONS https://localhost:44325/signalr-hubs/demo/negotiate?negotiateVersion=1 - -
2024-03-12 16:03:43.651 -03:00 [INF] CORS policy execution successful.
2024-03-12 16:03:43.651 -03:00 [INF] Request finished HTTP/2 OPTIONS https://localhost:44325/signalr-hubs/demo/negotiate?negotiateVersion=1 - - - 204 - - 0.2349ms
2024-03-12 16:03:43.663 -03:00 [INF] Request starting HTTP/2 POST https://localhost:44325/signalr-hubs/demo/negotiate?negotiateVersion=1 - 0
2024-03-12 16:03:43.664 -03:00 [INF] CORS policy execution successful.
2024-03-12 16:03:43.664 -03:00 [INF] requestId: 0HN22O3N3S1OM:00000001, previousRequestId: no previous request id, message: EndpointRateLimiting is not enabled for /signalr-hubs/{everything}
2024-03-12 16:03:43.664 -03:00 [INF] requestId: 0HN22O3N3S1OM:00000001, previousRequestId: no previous request id, message: No authentication needed for /signalr-hubs/demo/negotiate
2024-03-12 16:03:43.664 -03:00 [INF] requestId: 0HN22O3N3S1OM:00000001, previousRequestId: no previous request id, message: /signalr-hubs/{everything} route does not require user to be authorized
2024-03-12 16:03:43.895 -03:00 [INF] requestId: 0HN22O3N3S1OM:00000001, previousRequestId: no previous request id, message: 200 (OK) status code, request uri: https://localhost:44878/signalr-hubs/demo/negotiate?negotiateVersion=1
2024-03-12 16:03:43.895 -03:00 [INF] Request finished HTTP/2 POST https://localhost:44325/signalr-hubs/demo/negotiate?negotiateVersion=1 - 0 - 200 316 application/json 231.5712ms
2024-03-12 16:03:43.906 -03:00 [INF] Request starting HTTP/2 GET https://localhost:44325/signalr-hubs/demo?id=RnQFLvileEO8aoDcl7QboQ&access_token=eyJh...asd - -
2024-03-12 16:03:43.906 -03:00 [INF] CORS policy execution successful.
2024-03-12 16:03:43.907 -03:00 [INF] requestId: 0HN22O3N3S1OM:00000003, previousRequestId: no previous request id, message: EndpointRateLimiting is not enabled for /signalr-hubs/{everything}
2024-03-12 16:03:43.907 -03:00 [INF] requestId: 0HN22O3N3S1OM:00000003, previousRequestId: no previous request id, message: No authentication needed for /signalr-hubs/demo
2024-03-12 16:03:43.907 -03:00 [INF] requestId: 0HN22O3N3S1OM:00000003, previousRequestId: no previous request id, message: /signalr-hubs/{everything} route does not require user to be authorized
2024-03-12 16:05:13.908 -03:00 [WRN] requestId: 0HN22O3N3S1OM:00000003, previousRequestId: no previous request id, message: Error Code: RequestTimedOutError Message: Timeout making http request, exception: System.Threading.Tasks.TaskCanceledException: The request was canceled due to the configured HttpClient.Timeout of 90 seconds elapsing.
---> System.TimeoutException: The operation was canceled.
---> System.Threading.Tasks.TaskCanceledException: The operation was canceled.
---> System.IO.IOException: Unable to read data from the transport connection: La operación de E/S se anuló por una salida de subproceso o por una solicitud de aplicación..
---> System.Net.Sockets.SocketException (995): La operación de E/S se anuló por una salida de subproceso o por una solicitud de aplicación.
--- End of inner exception stack trace ---
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource<System.Int32>.GetResult(Int16 token)
at System.Net.Security.SslStream.EnsureFullTlsFrameAsync[TIOAdapter](CancellationToken cancellationToken)
at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](Memory`1 buffer, CancellationToken cancellationToken)
at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
at System.Net.Http.HttpConnection.FillAsync(Boolean async)
at System.Net.Http.HttpConnection.ChunkedEncodingReadStream.CopyToAsyncCore(Stream destination, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.HttpConnection.ChunkedEncodingReadStream.CopyToAsyncCore(Stream destination, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionResponseContent.<SerializeToStreamAsync>g__Impl|6_0(Stream stream, TransportContext context, CancellationToken cancellationToken)
at System.Net.Http.HttpContent.LoadIntoBufferAsyncCore(Task serializeToStreamTask, MemoryStream tempBuffer)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
at System.Net.Http.HttpClient.HandleFailure(Exception e, Boolean telemetryStarted, HttpResponseMessage response, CancellationTokenSource cts, CancellationToken cancellationToken, CancellationTokenSource pendingRequestsCts)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at Ocelot.Requester.HttpClientHttpRequester.GetResponse(HttpContext httpContext) errors found in ResponderMiddleware. Setting error response for request path:/signalr-hubs/demo, request method: GET
2024-03-12 16:05:13.908 -03:00 [INF] Request finished HTTP/2 GET https://localhost:44325/signalr-hubs/demo?id=RnQFLvileEO8aoDcl7QboQ&access_token=eyJh...asd - - - 503 0 - 90002.9186ms
OperacionesService:
2024-03-12 16:03:43.676 -03:00 [INF] Request starting HTTP/1.1 POST https://localhost:44878/signalr-hubs/demo/negotiate?negotiateVersion=1 - 0
2024-03-12 16:03:43.889 -03:00 [INF] Executing endpoint '/signalr-hubs/demo/negotiate'
2024-03-12 16:03:43.894 -03:00 [INF] Executed endpoint '/signalr-hubs/demo/negotiate'
2024-03-12 16:03:43.895 -03:00 [INF] Request finished HTTP/1.1 POST https://localhost:44878/signalr-hubs/demo/negotiate?negotiateVersion=1 - 0 - 200 316 application/json 218.4628ms
2024-03-12 16:03:43.908 -03:00 [INF] Request starting HTTP/1.1 GET https://localhost:44878/signalr-hubs/demo?id=RnQFLvileEO8aoDcl7QboQ&access_token=eyJhb...asd - 0
2024-03-12 16:03:43.910 -03:00 [INF] Executing endpoint '/signalr-hubs/demo'
2024-03-12 16:05:13.918 -03:00 [INF] Executed endpoint '/signalr-hubs/demo'
2024-03-12 16:05:13.920 -03:00 [INF] Request finished HTTP/1.1 GET https://localhost:44878/signalr-hubs/demo?id=RnQFLvileEO8aoDcl7QboQ&access_token=eyJhb...asd - 0 - 200 - text/event-stream 90013.2758ms