title: Since upgrading to Angular 9 Signalr doesn't work
body: <p>I have an angular application that uses signalR. It is hosted in a .NET core 3.1 application. Since upgrading to Angular 9, signalR no longer works. Everything was working fine in Angular 8. Since update, I've been getting errors like</p>
  <blockquote>
  <p>404 Error: Failed to complete negotiation with the server</p>
  <p>Failed to start the connection</p>
  </blockquote>
  <p>I am using MessagePackHubProtocol. In the <code>package.json</code> file I have the following packages:</p>
  <pre><code>&quot;@microsoft/signalr&quot;: &quot;3.1.2&quot;,
  &quot;@microsoft/signalr-protocol-msgpack&quot;:&quot;3.1.2&quot;
  </code></pre>
  <p>In .NET core I have packages:</p>
  <pre><code>Microsoft.AspNetCore.SignalR.Common 3.1.2 Microsoft.AspNetCore.SignalR.Protocols.MessagePack 3.1.2
  </code></pre>
  <p>The Typescript version I'm using is v3.7.5. I have SSL enabled.</p>
  <hr />
  <p>I tried adding CORS as stated in <a href="https://stackoverflow.com/questions/52086158/angular-signalr-error-failed-to-complete-negotiation-with-the-server">this post</a> and I also tried adding the following options to my client application.</p>
  <pre class="lang-js prettyprint-override"><code>{
    skipNegotiation: true,
    transport: signalR.HttpTransportType.WebSockets
  }
  </code></pre>
  <p>Unfortunately, neither worked.</p>
  <p>Startup.cs:</p>
  <pre><code>using Microsoft.AspNetCore.Builder;
  using Microsoft.AspNetCore.Hosting;
  using Microsoft.AspNetCore.Http;
  using Microsoft.AspNetCore.Mvc;
  using Microsoft.AspNetCore.Mvc.ViewFeatures;
  using Microsoft.AspNetCore.Server.IISIntegration;
  using Microsoft.AspNetCore.SpaServices.AngularCli;
  using Microsoft.Extensions.Configuration;
  using Microsoft.Extensions.DependencyInjection;
  using Microsoft.Extensions.DependencyInjection.Extensions;
  using Microsoft.Extensions.FileProviders;
  using Microsoft.Extensions.Hosting;
  using System.IO;
  
  
  public class Startup
  {
      public Startup(IConfiguration configuration)
      {
          Configuration = configuration;
      }
  
      public static IConfiguration Configuration
      {
          get; set;
      }
  
      // This method gets called by the runtime. Use this method to add services to the container.
      public void ConfigureServices(IServiceCollection services)
      {
          services.Configure&lt;AppConfig&gt;(options =&gt;
          {
              Configuration.GetSection(&quot;AppConfig&quot;).Bind(options);
          });
  
          // In production, the Angular files will be served from this directory
          services.AddSpaStaticFiles(configuration =&gt;
          {
              configuration.RootPath = &quot;ClientApp/dist&quot;;
          });
  
          services.TryAddSingleton&lt;IHttpContextAccessor, HttpContextAccessor&gt;();
  
          services.AddAuthentication(IISDefaults.AuthenticationScheme);
  
          services.Configure&lt;CookiePolicyOptions&gt;(options =&gt;
          {
              // This lambda determines whether user consent for non-essential cookies is needed for a given request.
              options.CheckConsentNeeded = context =&gt; true;
              options.MinimumSameSitePolicy = SameSiteMode.None;
          });
  
  
          services.AddSingleton&lt;ITempDataProvider, CookieTempDataProvider&gt;();
  
          services.AddSignalR(o =&gt;
          {
              o.EnableDetailedErrors = true;
              o.MaximumReceiveMessageSize = 1000000;
          }).AddMessagePackProtocol();
  
          services.AddControllersWithViews()
                          .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
                          .AddJsonOptions(options =&gt;
                          {
                              options.JsonSerializerOptions.PropertyNamingPolicy = null;
                              options.JsonSerializerOptions.DictionaryKeyPolicy = null;
                          });
  
          services.AddRazorPages();
      }
  
      // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
      public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
      {
          if(env.IsDevelopment())
          {
              app.UseDeveloperExceptionPage();
          }
          else
          {
              app.UseExceptionHandler(&quot;/Error&quot;);
              // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
              app.UseHsts();
          }
  
  
          app.UseHttpContext();
          app.UseHttpsRedirection();
          app.UseStaticFiles();
          app.UseStaticFiles(new StaticFileOptions()
          {
              FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), @&quot;Uploads&quot;)),
              RequestPath = new PathString(&quot;/Uploads&quot;)
          });
  
          app.Use(async (context, next) =&gt;
          {
              context.Response.Headers.Remove(&quot;X-XSS-Protection&quot;);
              context.Response.Headers.Add(&quot;X-Xss-Protection&quot;, &quot;1&quot;);
              context.Response.Headers.Remove(&quot;X-Frame-Options&quot;);
              context.Response.Headers.Add(&quot;X-Frame-Options&quot;, &quot;DENY&quot;);
              context.Response.Headers.Remove(&quot;Referrer-Policy&quot;);
              context.Response.Headers.Add(&quot;Referrer-Policy&quot;, &quot;no-referrer&quot;);
              context.Response.Headers.Remove(&quot;X-Content-Type-Options&quot;);
              context.Response.Headers.Add(&quot;X-Content-Type-Options&quot;, &quot;nosniff&quot;);
              //context.Response.Headers.Remove(&quot;Content-Security-Policy&quot;);
              //context.Response.Headers.Add(
              //    &quot;Content-Security-Policy&quot;,
              //    &quot;default-src 'self'; &quot; +
              //    &quot;img-src 'self' myblobacc.blob.core.windows.net; &quot; +
              //    &quot;font-src 'self'; &quot; +
              //    &quot;style-src 'self'; &quot; +
              //    &quot;script-src 'self' 'nonce-KIBdfgEKjb34ueiw567bfkshbvfi4KhtIUE3IWF' 'nonce-rewgljnOIBU3iu2btli4tbllwwe'; &quot; +
              //    &quot;frame-src 'self';&quot; +
              //    &quot;connect-src 'self';&quot;);
  
              await next();
          });
  
  
          if(!env.IsDevelopment())
          {
              app.UseSpaStaticFiles();
          }
  
  
          app.UseRouting();
  
          app.UseAuthentication();
  
          WebSocketOptions webSocketOptions = new WebSocketOptions();
          webSocketOptions.AllowedOrigins.Add(&quot;*&quot;);
  
          app.UseWebSockets(webSocketOptions);
  
          app.UseEndpoints(endpoints =&gt;
         {
             endpoints.MapControllers();
             endpoints.MapHub&lt;AppHub&gt;(&quot;/appHub&quot;);
  
             endpoints.MapControllerRoute(
                  name: &quot;default&quot;,
                  pattern: &quot;{controller}/{action=Index}/{id?}&quot;);
         });
  
          app.UseSpa(spa =&gt;
          {
              // To learn more about options for serving an Angular SPA from ASP.NET Core,
              // see https://go.microsoft.com/fwlink/?linkid=864501
  
              spa.Options.SourcePath = &quot;ClientApp&quot;;
  
              if(env.IsDevelopment())
              {
                  spa.UseAngularCliServer(npmScript: &quot;start&quot;);
              }
          });
  
          app.UseCookiePolicy();
  
      }
  
  
  
  
  
  
  
  
  
  
  }
  </code></pre>
  <p>My angular signalR service:</p>
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>import { Location } from '@angular/common';
  import { EventEmitter, Injectable, OnDestroy } from '@angular/core';
  import { HubConnection, HubConnectionBuilder, HubConnectionState, IHubProtocol, LogLevel } from '@microsoft/signalr';
  import { MessagePackHubProtocol } from '@microsoft/signalr-protocol-msgpack';
  import { Subscription } from 'rxjs';
  
  @Injectable()
  export class AppSignalRService implements OnDestroy
  {
    public connectionEstablished = new EventEmitter&lt;Boolean&gt;();
    public startConnectionTimeoutDelay: number = 3000;
    public protocol: IHubProtocol = new MessagePackHubProtocol();
    public autoReconnect: boolean = true;
  
    private _userId: number = 0;
    private _connectionIsEstablished: boolean = false;
    private _hubConnection: HubConnection;
  
    private connectedSubscription: Subscription;
  
    constructor(public location: Location)
    {
  
  
    }
  
    createConnection(huburl: string, userId: number)
    {
      this._userId = userId;
  
      if (!this._hubConnection &amp;&amp; this._userId &gt; 0)
      {
        let hubConnectionBuilder: HubConnectionBuilder = new HubConnectionBuilder();
  
        hubConnectionBuilder.withUrl(this.location.path.name + huburl);
        hubConnectionBuilder.withHubProtocol(this.protocol);
        hubConnectionBuilder.configureLogging(LogLevel.Information);
  
        if (this.autoReconnect)
        {
          hubConnectionBuilder.withAutomaticReconnect([0, 1000, 1000, 1000, 1000, 1000, 2000, 5000, 10000, 20000, 30000, null]);
        }
  
        this._hubConnection = hubConnectionBuilder.build();
  
        this.hubConnection.onclose((msg) =&gt;
        {
          console.log(msg.message);
          this.startConnection();
        });
  
        this.hubConnection.onreconnected((connectionId: string) =&gt;
        {
          this.hubConnection.invoke("RegisterConnection", this._userId)
        });
      }
    }
  
    startConnection()
    {
      if (this._hubConnection.state == HubConnectionState.Disconnected)
      {
        this._hubConnection
          .start()
          .then(() =&gt;
          {
            this._connectionIsEstablished = true;
            console.log('Hub connection started');
            this.connectionEstablished.emit(true);
  
            this.hubConnection.invoke("RegisterConnection", this._userId);
          })
          .catch(err =&gt;
          {
            this._connectionIsEstablished = false;
            console.log('Error while establishing connection, retrying...');
  
            setTimeout(() =&gt;
            {
              this.startConnection();
            }, this.startConnectionTimeoutDelay);
          });
      }
    }
  
    // ...args: any[] allows you to pass any number of arguments
    run(method: string, ...args: any[])
    {
      switch (this.hubConnection.state)
      {
        case HubConnectionState.Connected: ;
          this.hubConnection.invoke(method, ...args);
          break;
        case HubConnectionState.Connecting:
          this.connectedSubscription = this.connectionEstablished.subscribe((data: any) =&gt;
          {
            this.hubConnection.invoke(method, ...args);
  
            this.connectedSubscription.unsubscribe();
          });
          break;
        default:
          this.hubConnection.start()
            .then(() =&gt;
            {
              this.hubConnection.invoke(method, args)
  
              this.hubConnection.invoke("RegisterConnection", this._userId);
            })
            .catch(err =&gt; console.error(err.toString()));
          break;
      }
    }
  
  
  
  
    get connectionIsEstablished(): boolean
    {
      return this._connectionIsEstablished;
    }
  
    get hubConnection(): HubConnection
    {
      return this._hubConnection;
    }
  
  
  
    ngOnDestroy()
    {
      if (this.connectedSubscription)
      {
        // prevent memory leak when component destroyed
        this.connectedSubscription.unsubscribe();
      }
    }
  
  
  }  </code></pre>
  </div>
  </div>
  </p>
  <p>My package.json:</p>
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>{
    "name": "mic",
    "private": true,
    "version": "1.0.0",
    "scripts": {
      "ng": "ng",
      "start": "ng serve --live-reload=false",
      "build": "ng build",
      "build:ssr": "ng run MIC:server:dev",
      "test": "ng test",
      "lint": "ng lint",
      "e2e": "ng e2e"
    },
    "postcss": {},
    "dependencies": {
      "@angular/animations": "9.0.2",
      "@angular/cdk": "9.0.1",
      "@angular/common": "9.0.2",
      "@angular/compiler": "9.0.2",
      "@angular/core": "9.0.2",
      "@angular/flex-layout": "9.0.0-beta.29",
      "@angular/forms": "9.0.2",
      "@angular/localize": "9.0.2",
      "@angular/material": "9.0.1",
      "@angular/material-moment-adapter": "9.0.1",
      "@angular/platform-browser": "9.0.2",
      "@angular/platform-browser-dynamic": "9.0.2",
      "@angular/platform-server": "9.0.2",
      "@angular/router": "9.0.2",
      "@angular-devkit/schematics": "9.0.3",
      "@fortawesome/angular-fontawesome": "0.6.0",
      "@fortawesome/fontawesome-svg-core": "1.2.27",
      "@fortawesome/free-regular-svg-icons": "5.12.1",
      "@fortawesome/free-solid-svg-icons": "5.12.1",
      "@microsoft/signalr": "3.1.2",
      "@microsoft/signalr-protocol-msgpack": "3.1.2",
      "@ng-bootstrap/ng-bootstrap": "6.0.0",
      "@ngmodule/material-carousel": "0.6.0",
      "@ng-select/ng-select": "3.7.2",
      "@nguniversal/module-map-ngfactory-loader": "9.0.0-next.9",
      "@swimlane/ngx-charts": "13.0.2",
      "angular2-notifications": "3.0.0",
      "angular-dual-listbox": "5.0.1",
      "aspnet-prerendering": "^3.0.1",
      "bootstrap": "4.4.1",
      "classlist.js": "1.1.20150312",
      "core-js": "3.6.4",
      "date-fns": "2.9.0",
      "hammerjs": "2.0.8",
      "hammer-timejs": "1.1.0",
      "hash-sum": "2.0.0",
      "immutable": "4.0.0-rc.12",
      "intl": "1.2.5",
      "jquery": "3.4.1",
      "jwt-decode": "2.2.0",
      "material-design-icons": "3.0.1",
      "moment": "^2.24.0",
      "ng-validator": "2.0.0",
      "ngx-material-timepicker": "^5.3.0",
      "oidc-client": "1.10.1",
      "popper.js": "1.16.1",
      "primeicons": "2.0.0",
      "primeng": "9.0.0-rc.4",
      "rxjs": "6.5.4",
      "tippy.js": "5.2.1",
      "tslib": "^1.10.0",
      "web-animations-js": "^2.3.2",
      "zone.js": "0.10.2"
    },
    "devDependencies": {
      "@angular-devkit/build-angular": "0.900.3",
      "@angular/cli": "9.0.3",
      "@angular/compiler-cli": "9.0.2",
      "@angular/language-service": "9.0.2",
      "@intervolga/optimize-cssnano-plugin": "1.0.6",
      "@types/jasmine": "3.5.3",
      "@types/jasminewd2": "2.0.8",
      "@types/jwt-decode": "2.2.1",
      "@types/node": "13.7.4",
      "autoprefixer": "9.7.4",
      "codelyzer": "5.2.1",
      "jasmine-core": "3.5.0",
      "jasmine-spec-reporter": "4.2.1",
      "karma": "4.4.1",
      "karma-chrome-launcher": "3.1.0",
      "karma-coverage-istanbul-reporter": "2.1.1",
      "karma-jasmine": "3.1.1",
      "karma-jasmine-html-reporter": "1.5.2",
      "karma-scss-preprocessor": "4.0.0",
      "typescript": "3.7.5"
    },
    "optionalDependencies": {
      "node-sass": "4.13.1",
      "protractor": "6.0.0",
      "tslint": "6.0.0",
      "ts-node": "8.6.2"
    }
  }</code></pre>
  </div>
  </div>
  </p>