skip to Main Content

I try to get a very basic SignalR example to work that is based on Microsoft’s tutorial and the Weatherforecast .NET/Angular SPA created by Visual Studio as a basis as this is the same type of project I later want to use SignalR with. The entire source code is at GitHub.

It looks as if the handshake/negotiation works and a websocket connection is established – but no messages are flowing there. This is what the Chrome Developer Tools show:
enter image description here

I have the feeling I overlooked something minor, but I’m struggling to see what it could be.

I started by adjusting the Program.cs file, this is the relevant code:

builder.Services.AddSignalR(options =>
{
    options.EnableDetailedErrors = true;
});

var app = builder.Build();

...

app.UseCors();
  
//app.MapHub<ProgressHub>("/progressHub");
app.UseEndpoints(endpoints =>
{
    endpoints.MapHub<ProgressHub>("/progresshub"); // Map the hub URL here
});

app.Run();

Note that MS suggests to use app.MapHub<ProgressHub>("/progressHub"); but som resources suggested to use app.UseEndpoints instead. It doesn’t seem to make any difference. Also, I tried using app.UseWebSockets(); but that did not change anything either. Also, I made sure to enable CORS.

This is the controller method I added which is supposed to send messages on the SignalR channel:

[HttpPost("startProcess")]
public async Task<IActionResult> StartProcess()
{
    // Some logic to start the long-running process
    for (int i = 0; i < 10; i++)
    {
        await Task.Delay(1000);

        // Report progress to the client
        await _hubContext.Clients.All.SendAsync("ReceiveProgressUpdate", $"Step {i + 1} completed.");
    }

    return Ok("[]");
}

When stepping through the code, no exceptions are thrown, the code runs without any issues. On the Angular client side I have installed the signalr package and created a service:

export class SignalRService {
  private hubConnection: HubConnection;
  private progressSubject: Subject<string> = new Subject<string>();

  constructor() {
    this.hubConnection = new HubConnectionBuilder()
      .withUrl('https://localhost:44429/progresshub')
      .build();

    this.hubConnection.on('ReceiveProgressUpdate', (progressMessage: string) => {
      this.progressSubject.next(progressMessage);
    });

    this.hubConnection.start().catch(err => console.error(err));
  }

  getProgressUpdates() {
    return this.progressSubject.asObservable();
  }
}

Now I use that service in my SignalR component, but the progressUpdates array remains empty:

export class SignalRComponent implements OnInit {
  progressUpdates: string[] = [];
  _httpClient: HttpClient;

  constructor(private httpClient: HttpClient, private signalRService: SignalRService) {
    this._httpClient = httpClient;
  }

  ngOnInit() {
    this.signalRService.getProgressUpdates().subscribe((progressMessage: string) => {
      this.progressUpdates.push(progressMessage);
    });
  }

  startProcess() {
    this.httpClient.post('https://localhost:44429/weatherforecast/startProcess', {}).subscribe();
  }
}

Also, I have turned on the WebSocket Protocol in Windows as this was suggested on SO as well:
enter image description here

2

Answers


  1. Chosen as BEST ANSWER

    I finally found the culprit, it is the ASP proxy which per default configuration does not allow websocket connections. The PROXY_CONFIG const in proxy.conf.js needs to be set like this:

    const PROXY_CONFIG = [
      {
        context: ["/progresshub"], 
        target: target,
        secure: false,
        ws: true // Enable WebSocket proxying
      },
      {
        context: [
          "/weatherforecast",
       ],
        target: target,
        secure: false,
        headers: {
          Connection: 'Keep-Alive'
        }
      }
    ]
    

    The configuration needs to be split into separate contexts for the weatherforecast (or any other) API and the websocket as the Keep-Alive headers are not allowed for websocket connections.

    Credit goes to this post on reddit.


  2. I download your repo and change the proxy.conf.js file like below. And it works well. You can according your needs to change other settings.

    I also enable the client side logging so that we can make the connection is established.

    Test Result

    enter image description here

    proxy.conf.js

    const { env } = require('process');
    
    const target = env.ASPNETCORE_HTTPS_PORT ? `https://localhost:${env.ASPNETCORE_HTTPS_PORT}` :
      env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'http://localhost:50822';
    
    
    
    const PROXY_CONFIG = [
      {
        context: [
          "/weatherforecast",
          "/progresshub"
       ],
        target: target, 
        changeOrigin: true,  
        logLevel: "debug",
        rejectUnauthorzied: true, 
        secure: false,            
        strictSSL: true,          
        withCredentials: true,
        ws: true
      }
    ]
    
    module.exports = PROXY_CONFIG;
    

    signal-r.service.ts

    import { Injectable } from '@angular/core';
    import { HubConnection, HubConnectionBuilder } from '@microsoft/signalr';
    import * as signalR from '@microsoft/signalr';
    import { Subject } from 'rxjs';
    
    @Injectable({
      providedIn: 'root'
    })
    export class SignalRService {
      private hubConnection: HubConnection;
      private progressSubject: Subject<string> = new Subject<string>();
    
      constructor() {
        this.hubConnection = new signalR.HubConnectionBuilder()
          .withUrl('https://localhost:44429/progresshub', signalR.HttpTransportType.WebSockets | signalR.HttpTransportType.LongPolling).configureLogging(signalR.LogLevel.Debug)
          .build();
    
        this.hubConnection.on('ReceiveProgressUpdate', (progressMessage: string) => {
          this.progressSubject.next(progressMessage);
        });
        this.hubConnection.start().catch(err => console.error(err));
      }
    
      getProgressUpdates() {
        return this.progressSubject.asObservable();
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search