I have developed a project in Angular6. There is a requirement to develop section for live chat. For that I am using SignalR in my asp.net core Web Apiproject. Now I want to use this Web Api reference in my Angular project.
I am using this link.
But while providing the Web Api url in App.Component.ts, I am getting below error :
Constructor of class 'HubConnection' is private and only accessible
within the class declaration.
App Component.ts :
import { HubConnection } from '#aspnet/signalr';
import { Message } from 'primeng/api';
export class AppComponent implements OnInit {
public _hubConnection: HubConnection;
msgs: Message[] = [];
constructor() {
}
ngOnInit() {
this._hubConnection = new HubConnection('http://localhost:1874/notify'); // getting error on this line.
Edit : tried below code :-
Modified App.Component.ts :
import { HubConnection } from '#aspnet/signalr';
import * as signalR from '#aspnet/signalr';
import { Message } from 'primeng/api';
export class AppComponent implements OnInit {
public _hubConnection: HubConnection;
msgs: Message[] = [];
constructor() {
}
ngOnInit() {
this._hubConnection = new signalR.HubConnectionBuilder()
.withUrl('http://localhost:1874/notify')
.configureLogging(signalR.LogLevel.Information)
.build();
Error :
Failed to load
http://localhost:1874/notify/negotiate: Response to preflight request
doesn't pass access control check: The value of the
'Access-Control-Allow-Credentials' header in the response is '' which
must be 'true' when the request's credentials mode is 'include'.
Origin 'http://localhost:4200' is therefore not allowed access. The
credentials mode of requests initiated by the XMLHttpRequest is
controlled by the withCredentials attribute.
They changed the constructors for SignalR Client HubConnection to no longer allow you to pass the route in the client constructor and made the HubConnection constructor private to enforce the change. Instead, you need to use the HubConnectionBuilder as follows:
new HubConnectionBuilder().withUrl("/YOURROUTEHERE").build();
You will want to import the HubConnectionBuilder in your header as follows:
import { HubConnection, HubConnectionBuilder } from '#aspnet/signalr';
In case it helps, I also just posted an update to my RxSignalR samples for #aspnet/signalr 1.0.2, RxJs 5.5.6 and Angular 6. Check out the ReactiveChat component for an example.
In your server code, are you using CORS?
public void ConfigureServices(IServiceCollection services)
{
...
services.AddCors(options => options.AddPolicy("CorsPolicy", builder =>
{
builder.AllowAnyMethod()
.AllowAnyHeader()
.WithOrigins("http://localhost:4200")
.AllowCredentials();
}));
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseCors("CorsPolicy");
app.UseSignalR(routes =>
{
// your routes
});
...
}
Try like this,
private hubConnection: signalr.HubConnection;
message: string;
ngOnInit() {
this.hubConnection = new signalr.HubConnection('');
this.hubConnection
.start()
.then(() => {
console.log('Connection started!');
this.hubConnection.on('ReceiveMessage', (message) => {
alert(message);
});
})
.catch(err => console.log('Error while establishing connection :('));
}
Related
I am trying to find a way to monitor a SignalR connection continuously like say every minute or every 3 minutes.
Trying to find a way to check the connection state. Do I need to set up an observable that can be subscribed to. But then that would have to be in a Component or do I do that in the app.Module or app.component ?
Is it connection.OnClose();
the Angular Code in my SignalR Service class is:
Injectable({
providedIn: 'root'
})
export class SignalrService {
connection: signalR.HubConnection;
constructor() {
this.connection = new signalR.HubConnectionBuilder()
.withUrl(environment.hubAddress)
.build();
this.connect();
}
public connect() {
if (this.connection.state === signalR.HubConnectionState.Disconnected) {
this.connection.start().catch(err => console.log(err));
}
}
public getMessage(next) {
this.connection.on('SendMessage', (message) => {
next(message);
});
}
public disconnect() {
this.connection.stop();
}
}
I was able to solve this by checking connection reconnecting(), reconnected() and onClose()events:
constructor() {
this.connection = new signalR.HubConnectionBuilder()
.withUrl(environment.hubAddress)
.build();
this.connection.reconnecting() => {}
this.connection.reconnected() => {}
this.connection.onClose() => {}
this.connect();
}
I'm trying to develop a simple proof of concept for an ionic app sending and receiving signalr messages. I have a very simple signalr web app built in .net 4.5 that is succesfully sending and receiving messages from connected clients within the app host.
I am now trying to connect to this from an ionic app but I get the message
Access to XMLHttpRequest at 'http://localhost:59621/signalr/negotiate'
from origin 'http://localhost:8100' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: The
value of the 'Access-Control-Allow-Origin' header in the response must
not be the wildcard '*' when the request's credentials mode is
'include'.
when attempting to establish a connection to the signalr hub.
Any assistance is much appreciated.
.Net Code
Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Any connection or hub wire up and configuration should go here
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableDetailedErrors = true,
};
map.RunSignalR(hubConfiguration);
});
}
}
ChatHub.cs
[HubName("ChatHub")]
public class ChatHub : Hub
{
public void Send(string name, string message)
{
// Call the addNewMessageToPage method to update clients.
Clients.All.addNewMessageToPage(name, message);
}
}
Ionic Code
import { Component } from '#angular/core';
import { NavController, DateTime, AlertController } from 'ionic-angular';
import { HubConnection, HubConnectionBuilder } from '#aspnet/signalr';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
hubConnection: HubConnection;
name: string;
message: string;
messages: string[] = [];
constructor(public navCtrl: NavController, public alertCtrl: AlertController) {
}
ionViewDidLoad() {
}
ionViewWillEnter() {
let alert = this.alertCtrl.create({
title: 'Demo',
message: 'What is your name?',
inputs: [
{
name: 'Name',
placeholder: 'Name'
}
],
buttons: [
{
text: 'Enter',
handler: data => {
this.name = data.Name;
}
}
]
});
alert.present();
this.hubConnection = new HubConnectionBuilder().withUrl('http://localhost:59621/signalr').build();
this.hubConnection
.start()
.then(() => console.log('Connection started!'))
.catch(err => {
debugger;
console.log('Error while establishing connection :(')
});
this.hubConnection.on('addNewMessageToPage', (name: string, receivedMessage: string) => {
const text = `${name}: ${receivedMessage}`;
this.messages.push(text);
});
}
sendMessage() {
this.hubConnection
.invoke('send', this.name, this.message)
.then(() => this.message = '')
.catch(err => console.error(err));
}
}
Ionic Info
Ionic:
ionic (Ionic CLI) : 4.0.6
Ionic Framework : ionic-angular 3.9.3
#ionic/app-scripts : 3.2.1
Cordova:
cordova (Cordova CLI) : 8.1.0
Cordova Platforms : none
System:
NodeJS : v8.11.0 (C:\Program Files\nodejs\node.exe)
npm : 5.6.0
OS : Windows 10
Environment:
ANDROID_HOME : not set
The problem was that the signalr plugin for ionic required a .Net Core backend. I had been attempting to use a .Net Framework backend.
Your code is fine. issue of CORS related. So You should run as below steps
Create shortcut chrome on desktop and rename no-cors (Whatever name)
Right click on icon and goes to property
Next change target to "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="D:/Chrome" and save.
Then run on this breowser definitely it works. thanks
Following Google's official Angular 4.3.2 doc here, I was able to do a simple get request from a local json file. I wanted to practice hitting a real endpoint from JSON placeholder site, but I'm having trouble figuring out what to put in the .subscribe() operator. I made an IUser interface to capture the fields of the payload, but the line with .subscribe(data => {this.users = data}) throws the error Type 'Object' is not assignable to type 'IUser[]'. What's the proper way to handle this? Seems pretty basic but I'm a noob.
My code is below:
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { IUsers } from './users';
#Component({
selector: 'pm-http',
templateUrl: './http.component.html',
styleUrls: ['./http.component.css']
})
export class HttpComponent implements OnInit {
productUrl = 'https://jsonplaceholder.typicode.com/users';
users: IUsers[];
constructor(private _http: HttpClient) { }
ngOnInit(): void {
this._http.get(this.productUrl).subscribe(data => {this.users = data});
}
}
You actually have a few options here, but use generics to cast it to the type you're expecting.
// Notice the Generic of IUsers[] casting the Type for resulting "data"
this.http.get<IUsers[]>(this.productUrl).subscribe(data => ...
// or in the subscribe
.subscribe((data: IUsers[]) => ...
Also I'd recommend using async pipes in your template that auto subscribe / unsubscribe, especially if you don't need any fancy logic, and you're just mapping the value.
users: Observable<IUsers[]>; // different type now
this.users = this.http.get<IUsers[]>(this.productUrl);
// template:
*ngFor="let user of users | async"
I'm on the Angular doc team and one open todo item is to change these docs to show the "best practice" way to access Http ... which is through a service.
Here is an example:
import { Injectable } from '#angular/core';
import { HttpClient, HttpErrorResponse } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import { IProduct } from './product';
#Injectable()
export class ProductService {
private _productUrl = './api/products/products.json';
constructor(private _http: HttpClient) { }
getProducts(): Observable<IProduct[]> {
return this._http.get<IProduct[]>(this._productUrl)
.do(data => console.log('All: ' + JSON.stringify(data)))
.catch(this.handleError);
}
private handleError(err: HttpErrorResponse) {
// in a real world app, we may send the server to some remote logging infrastructure
// instead of just logging it to the console
let errorMessage = '';
if (err.error instanceof Error) {
// A client-side or network error occurred. Handle it accordingly.
errorMessage = `An error occurred: ${err.error.message}`;
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
errorMessage = `Server returned code: ${err.status}, error message is: ${err.message}`;
}
console.error(errorMessage);
return Observable.throw(errorMessage);
}
}
The component would then look like this:
ngOnInit(): void {
this._productService.getProducts()
.subscribe(products => this.products = products,
error => this.errorMessage = <any>error);
}
I have multiple Angular components that are subscribing to a SignalR hub connection. I have wrapped the SignalR hub connection object to an angular service, hubconnection.service.ts:
import { Injectable } from '#angular/core';
import { HubConnectionBuilder, HubConnection } from '#aspnet/signalr';
#Injectable()
export class HubConnectionService {
public MyHubConnection: HubConnection;
constructor() {
this.MyHubConnection = new HubConnectionBuilder()
.withUrl('/sensorHub')
.build();
this.MyHubConnection
.start()
.then(() => console.log('[HubConnectionService] Connection started'))
.catch(err => console.log('[HubConnectionService] Error while starting connection: ' + err));
}
}
Now I have a component from where I want to subscribe to the data received through the SignalR hub, to do this I import my SignalR wrapper, and in the constructor I call the .on() method. To unsubscribe from that event I call the .off() method in the destructor:
export class RawdataComponent implements OnInit {
constructor(private hubConnectionService: HubConnectionService) { }
ngOnDestroy() {
this.hubConnectionService.MyHubConnection.off('Broadcast');
}
ngOnInit() {
this.hubConnectionService.MyHubConnection.on('Broadcast',
function(sender, message) {
console.log('New message received: ' + message);
});
}
}
When I initially access the page that is described by this component, everything works as expected (console.log() is logging for every message I receive).
When I leave the page, MyHubConnection.off('Broadcast'); is called. Then after I access the previous page again, the constructor is called and another subscription is made, but the previous one is not closed, and I get two console.log() calls.
Where's the mistake I'm making? Shouldn't MyHubConnection.off('Broadcast'); close the current subscription when I leave the page?
I am actually creating a chat with angular 5 and signalR on an ASP.NET Framework API. I followed the documentation but it's still not work. Here is my hub:
public class ChatHub : Hub
{
public void Hello()
{
Clients.All.hello();
}
}
Here is my startup class:
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
{
EnableJSONP = true
};
// Run the SignalR pipeline. We're not using MapSignalR
// since this branch already runs under the "/signalr"
// path.
map.RunSignalR(hubConfiguration);
});
and here is my angular part which create the hubconnection:
ngOnInit() {
this._hubConnection = new HubConnection('http://localhost:58525/signalr/hubs');
this._hubConnection
.start()
.then(() => console.log('Connection started!'))
.catch(err => console.log('Error while establishing connection :( : ' + err));
this._hubConnection.on('send', data => {
console.log(data);
});
}
I get this error:
If your ASP.NET page runs on another server, then your URL looks not correct.
https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-javascript-client#crossdomain
You have to connect to:
this._hubConnection = new HubConnection('http://localhost:58525/signalr');