-2

I am using signal to get real time data in my angular application and using .net core 2.2 API for back-end but when i run project i get CORS error in browser console.

VehicleHub.cs

using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BusinessLayer.HubConfig
{
    public class VehicleHub:Hub
    {
        public int id { get; set; }
        public string name { get; set; }
        public string vehicleType { get; set; }
        public string modelNo { get; set; }
        public string registrationNo { get; set; }
        public int? lcsVehicleNo { get; set; }
        public int relationShipOfficerId { get; set; }
        public int driverId { get; set; }
        public string driverName { get; set; }
        public string relationShipOfficerName { get; set; }
        public bool isActive { get; set; }
        public DateTime createdOn { get; set; }
        public string createdBy { get; set; }
        public DateTime modifiedOn { get; set; }
        public string modifyBy { get; set; }
        public int locationId { get; set; }
        public int createdById { get; set; }
        public int? modifyById { get; set; }
    }
}

here is my starup.cs file

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using BusinessLayer.Helpers;
using MatechEssential;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using WebAPICore.Helpers;
using WebAPICore.middleware;
using WebAPICore.Services;
using WebAPICore.Utility;
using BusinessLayer.HubConfig;

namespace WebAPICore
{
    public class Startup
    {
        private readonly IHostingEnvironment _hostingEnvironment;

        public Startup(IConfiguration configuration, IHostingEnvironment env)
        {
            Configuration = configuration;
            _hostingEnvironment = env;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(o => o.AddPolicy("CorsPolicy", builder =>
            {
                builder.AllowAnyOrigin()
                       .AllowAnyMethod()
                       .AllowAnyHeader()
                       .SetIsOriginAllowed((host) => true);
            }));
            services.AddSignalR();
            services.AddMvc(options =>
            {
                options.Filters.Add(new ErrorHandlingFilter());
            }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            // configure strongly typed settings objects
            var appSettingsSection = Configuration.GetSection("AppSettings");
            services.Configure<AppSettings>(appSettingsSection);

            // configure jwt authentication
            var appSettings = appSettingsSection.Get<AppSettings>();
            SQLHelper._ConStr = appSettings.ConnectionString != null? appSettings.ConnectionString:"" ;

            var key = Encoding.ASCII.GetBytes(appSettings.Secret);
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = "bearer";
                x.DefaultChallengeScheme = "bearer";
            })
            .AddJwtBearer("bearer", options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateAudience = false,
                    ValidateIssuer = false,
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(appSettings.Secret)),
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.Zero
                    // TimeSpan.Zero //the default for this setting is 5 minutes
                };
                options.Events = new JwtBearerEvents
                {
                    OnAuthenticationFailed = context =>
                    {
                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                        {
                            context.Response.Headers.Add("Token-Expired", "true");
                        }
                        return Task.CompletedTask;
                    }
                };
                options.SaveToken = true;
            });

            var physicalProvider = _hostingEnvironment.ContentRootFileProvider;
            var embeddedProvider = new EmbeddedFileProvider(Assembly.GetEntryAssembly());
            var compositeProvider = new CompositeFileProvider(physicalProvider, embeddedProvider);
             string absolutePath = compositeProvider.GetFileInfo("/SetupFiles/MasterSetupData.xml").PhysicalPath;
            XmlToList.xmlFileType = absolutePath;

            services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
            services.AddTransient<UserResolverService>();    
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory logger)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
               app.UseApiExceptionHandler(logger);
            }
            else
            {
                // 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.UseApiExceptionHandler(logger); //use global exception handlers
            }
            app.UseSignalR(routes =>
            {
                routes.MapHub<VehicleHub>("/Utility/GetAllVehicles");
            });
            // global cors policy
            app.UseCors("CorsPolicy");

            app.UseAuthentication();
            app.UseHttpsRedirection();
            app.UseResponseWrapper();

            //app.UseAPIResponseWrapperMiddleware();
            app.UseOptions();
            app.UseMvc();
        }
    }
}

I also have tried the below code but nothing happen

services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy", builder => builder.WithOrigins("http://localhost:4200")
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials()
                    .SetIsOriginAllowed((host) => true));
            });

UtilityController.cs

[Route("api/[controller]")]
    [ApiController]
    [EnableCors("CorsPolicy")]
    public class UtilityController : ControllerBase
    {
        private UserModel _currentUser;
        private IHubContext<VehicleHub> _hub;
        public UtilityController(UserResolverService userService, IHubContext<VehicleHub> hub)// , IUserService userService
        {
            _hub = hub;
            _currentUser = userService.getUserInfo();
        }
 [HttpGet]
        [Route("GetAllVehicles")]
        public IActionResult GetAllVehicles()
        {
            try
            {
                _hub.Clients.All.SendAsync("transferchartdata", UtilityFuncation.GetVehicleAll());
                return Ok(new { Message = "Request Completed" });
            }
            catch (Exception exp)
            {
                return NotFound(CommonApiResponse.Create(HttpStatusCode.InternalServerError, "Error Date Not Fetch", exp.Message));
            }
        }
}

I have removed other actions/methods from controller for Stackoverflow

signal-r.service.ts

import { Injectable } from '@angular/core';
import * as signalR from "@aspnet/signalr";
import { HttpClient } from '@angular/common/http';
@Injectable({
  providedIn: 'root'
})

export class SignalRService {
  public data: VehicleModel[]
  private hubConnection: signalR.HubConnection
  options: signalR.IHttpConnectionOptions = {
    accessTokenFactory: () => {
     let token = localStorage.getItem("token")
      return `Bearer ${token}`;
    },
  };
  public startConnection = () => {
    this.hubConnection = new signalR.HubConnectionBuilder()
                            .withUrl('http://localhost:50915/Utility/GetAllVehicles', this.options)
                            .build();

    this.hubConnection
      .start()
      .then(() => console.log('Connection started'))
      .catch(err => console.log('Error while starting connection: ' + err))
  }

  public addTransferChartDataListener = () => {
    this.hubConnection.on('transferchartdata', (data) => {
      this.data = data;
      console.log(data);
    });
  }
  constructor() { }
}

export interface VehicleModel {
  id : any
  name : any
  vehicleType : any
  modelNo : any
  registrationNo : any
  lcsVehicleNo : any
  relationShipOfficerId : any
  driverId : any
  driverName : any
  relationShipOfficerName : any
  isActive : any
  createdOn : any
  createdBy : any
  modifiedOn : any
  modifyBy : any
  locationId : any
  createdById : any
  modifyById : any
}

App.component.ts

 ngOnInit() {
    this.signalRService.startConnection();
    this.signalRService.addTransferChartDataListener();   
    this.startHttpRequest();
}

I have removed other methods from App.component for Stackoverflow

nuget package of signalr

my nuget package for signalr

angular version of signar

my angular version for sinalr

I get this error in my browser console, but when i added the breakpoint on controller it perfectly hits the action for one time only (you can see the response in console)

error in browser console

below is network snapshot for GetAllVehicles that works for first time

network snapshot for GetAllVehicles that works

below is network snapshot for negotiate that have CORS issue

network snapshot for negotiate that have CORS issue I have also tried this url but got nothing.

Dexter
  • 11
  • 7

1 Answers1

1

You need to add CORS on your hub like:

On the configure method

app.UseCors(CorsPolicy);

On the AddAditionalServices

services.AddCors(options =>
{
    options.AddPolicy(CorsPolicy, builder => builder.WithOrigins("http://localhost:4200")
        .AllowAnyHeader()
        .AllowAnyMethod()
        .AllowCredentials()
        .SetIsOriginAllowed((host) => true));
});

Note that the order of the CORS methods is important!

Also you should not use the @aspnet/signalr package since it was abandoned and is outdated. You should use the new @microsoft/signalr package and it also provides you with AutomaticReconnect feature.

Kiril1512
  • 2,522
  • 2
  • 10
  • 30