2
votes

Trying to write Hub in my server to broadcast notifications to clients

In my Server: 1 - Installed the nuget. 2 - Created Startup.cs with app.MapSignalR(); 3 - Created hub:

[HubName("NotificationHub")]
public class NotificationHub : Hub
{
    // required to let the Hub to be called from other server-side classes/controllers, using static methods
    private static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();

    // Send the data to all clients (may be called from client JS)
    public void GetNotifications()
    {
        Clients.All.GetNotifications();
    }

    // Send the data to all clients (may be called from server C#)
    public static void GetNotificationsStatic()
    {
        hubContext.Clients.All.GetNotifications();
    }
}

4 - Created controller with Get and Add notifications.

In my client: followed this guide: https://medium.com/@ghanshyamshukla/implementation-of-signalr-in-angular-5-app-with-asp-net-web-api-2-0-f09672817d4d (in my angular.json instead of '../node_modules..' I've fixed to './node_modules..'

and this is my connection function:

connectToSignalRHub() {
const signalRServerEndPoint = environment.baseURL;
this.connection = $.hubConnection(signalRServerEndPoint);
this.proxy = this.connection.createHubProxy('notificationHub');

this.proxy.on('messageReceived', () => {
  console.log('new notifications');
});
this.connection.start().done((data: any) => {
  console.log('Connected to Notification Hub');
}).catch((error: any) => {
  console.log('Notification Hub error -> ' + error);
});

}

Then when I run my app,

when trying to connect with this.connection.start()

I get to the error section with error:

Error: Error during negotiation request. at Object.error (jquery.signalR.min.js:9)

and I see in my console this error:

Access to XMLHttpRequest at 'https://localhost:44328/signalr/negotiate?clientProtocol=2.1&connectionData=%5B%7B%22name%22%3A%22notificationhub%22%7D%5D&_=1563949114481' from origin 'http://localhost:8083' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Needless to say I've enabled CORS for my app

3
what is your CORS setup? (show your code)vasily.sib
Also it will be helpfull if you send OPTIONS request to 'https://localhost:44328/signalr/negotiate?clientProtocol=2.1&connectionData=%5B%7B%22name%22%3A%22notificationhub%22%7D%5D&_=1563949114481 and show us response headersvasily.sib
Also, when you finally discover that you are not turning on CORS properly - read this linkvasily.sib
@vasily.sib I've added the CORS in my WebApiConfig at register (I will edit my question). Upon reading your answer and article, I've learned that I should do CORS also for the OWIN Startup, which wasn't mentioned anywhere in my guide, Thank you it works now.Erez Konforti
Possible duplicate hereJoel Balmer

3 Answers

1
votes

this is working for me:

I use AspNetCore 2.1 (important version) in server side.

in startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddCors(options => options.AddPolicy("CorsPolicy",
    builder =>
    {
        builder.AllowAnyMethod()
        .AllowAnyHeader()
        .AllowAnyOrigin()
        .AllowCredentials();
    }));


    services.AddSignalR();
}

The ordering of services is also important.

Configure method:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseCors("CorsPolicy");
            app.UseStaticFiles();

            app.UseSignalR(route =>
            {
                route.MapHub<NotificationHub>("/notificationHub"); // name of js file
            });

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    enter code here

and in Hub class:

[HubName("NotificationHub")]
public class NotificationHub: Hub
    {
        public Task SendMessage(string user, string message)
        {
            return Clients.All.SendAsync("ReceiveMessage", user, message); // ReceiveMessage => name of method in client
        }
    }
0
votes

So the problem was that I've enabled CORS in my WebApiConfig:

config.EnableCors();
var corsAttr = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(corsAttr);

Thanks to vasily.sib in the comment section, and this link he's refered me to: CORS Article

I've changed my Startup.cs Configuration method to:

app.Map("/signalr", map =>
        {
            // Setup the CORS middleware to run before SignalR.
            // By default this will allow all origins. You can 
            // configure the set of origins and/or http verbs by
            // providing a cors options with a different policy.
            map.UseCors(CorsOptions.AllowAll);
            var hubConfiguration = new HubConfiguration
            {
                // You can enable JSONP by uncommenting line below.
                // JSONP requests are insecure but some older browsers (and some
                // versions of IE) require JSONP to work cross domain
                // EnableJSONP = true
            };
            // Run the SignalR pipeline. We're not using MapSignalR
            // since this branch already runs under the "/signalr"
            // path.
            map.RunSignalR(hubConfiguration);
        });

And now it works.

0
votes

Took me several head-scratching hours, but I finally got it working with a combination of http and https, together with removing the trailing / after the port number!

In ConfigureServices method in startup.cs

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

services.AddSignalR();

In the Configure method in startup.cs

app.UseCors("CorsPolicy");
app.UseSignalR(routes => routes.MapHub<NotifyHub>("/notify"));

Client js:

const connection = new signalR.HubConnectionBuilder()
  .withUrl('https://localhost:44394/notify')
  .configureLogging(signalR.LogLevel.Debug)
  .build();

connection.start().then(() => {
  console.log('Connected!');
}).catch((err) => {
  return console.error(err.toString());
});

There may be other combinations that are successful, but it feels like I tried every single one and I’m not ready to keep trying when it’s finally working…