Error 204 when trying to connect to SignalR - javascript

I'm not able to connect to my SignalR Hub in a ASP.NET Core 2.0.3 application running under Windows 7.
I'm using SignalR 1.0.0-alpha1-final from NuGet as server and the signalr-client-1.0.0-alpha2-final.min.js as JavaScript client.
Here is my hub:
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
namespace MyProject
{
public class MyHub: Hub
{
public override async Task OnConnectedAsync()
{
await Clients.All.InvokeAsync("Send", $"{Context.ConnectionId} joined");
}
public Task Send(string message)
{
return Clients.All.InvokeAsync("Send", $"{Context.ConnectionId}: {message}");
}
}
}
Configure in startup.cs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseHangfireDashboard();
app.UseHangfireServer();
app.UseSignalR(routes =>
{
routes.MapHub<MyHub>("hubs");
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
}
and in a test page:
let transportType = signalR.TransportType[getParameterByName('transport')] || signalR.TransportType.WebSockets;
let http = new signalR.HttpConnection(`http://${document.location.host}/hubs`, { transport: transportType });
var connection = new signalR.HubConnection(http);
but when this code executes I get an error 204 from the server.
UPDATE
Based upon the answer of #Gabriel Luci, here the working code:
let transportType = signalR.TransportType.LongPolling;
let http = new signalR.HttpConnection(`http://${document.location.host}/hubs`, { transport: transportType });
let connection = new signalR.HubConnection(http);
connection.start();
connection.on('Send', (message) => {
console.log(message);
});
...
connection.invoke('Echo', "Hello ");

There was an issue raised in GitHub for that: https://github.com/aspnet/SignalR/issues/1028
Apparently WebSockets doesn't work in IIS and IIS Express. You need to use long-polling. There's a snippet of sample code in that issue:
let connection = new HubConnection("someurl", { transport: signalR.TransportType.LongPolling });
connection.start().then(() => {});

In my case i have to remove allow any origin and replace it with WithOrigins and AllowCredentials
options.AddPolicy("policy",
builder =>
{
builder.WithOrigins("http://localhost:8081");
builder.AllowAnyMethod();
builder.AllowAnyHeader();
builder.AllowCredentials();
});

Related

client.on not getting data on single connect

I am using net module to connect client with my server. And here is my code.
const Net = require('net');
client = Net.connect(parseInt(port), host, function() {
console.log('server connected')
})
console.log("ooooooooooooooooooooooooooooo")
client.on('data', function(chunk) {
let data = chunk.toString()
console.log(data)
});
client.on('error', function(error) {
console.error('error', error);
});
The issue is when I connect it with single client it doesn't give me data inside client.on('data' but when I connect it will two or more clients it gets connected and I am getting my data. Someone pls help.
If there any other module I can use ?
I have three Java TCP servers each running on their own thread, this particular one handles localhost connections from the NodeJS server which is mainly TEXT or JSON objects. It will read a command and respond.
The NodeJS server then sends that data back to the client browser using socket.io.
/*
* Handle the nodejs interaction on localhost port 2000
*/
public class DeviceServer3 extends Thread {
private static DeviceServer dev_server = null;
private boolean quit = false;
private final int port = 2000;
public DeviceServer3(DeviceServer server) {
dev_server = server; // store original server
}
public void quitSignal() { // safely shutdown thread
System.out.println("WLMedia Node Java Server exiting...");
quit = true;
while (dev_server.thread_count.get() != 0) {
try { Thread.sleep(5);
} catch (InterruptedException ex) {}
}
}
#Override
public void run() { // main thread
ServerSocket listen_socket = null;
while (!quit) {
try {
listen_socket = new ServerSocket(port);
//listen_socket.setSoTimeout(5000);
listen_socket.setReuseAddress(true);
while (!quit) {
Socket connection = listen_socket.accept();
checkSocket(connection);
}
} catch (IOException e) {
System.out.println("Node Server catch: " + e.getLocalizedMessage());
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
}
} finally {
try {
if (listen_socket != null) {
listen_socket.close();
}
} catch (IOException e) {
System.out.println("server finally: " + e.getMessage());
}
}
}
}
private void checkSocket(Socket socket) {
// Only allow 'localhost' connections
if (socket.getInetAddress().isLoopbackAddress()) {
handleSocket(socket); // TODO change to a thread
} else {
System.out.println("WARNING: Outside connection attempt from: "
+ socket.getInetAddress().toString());
}
try {
socket.close();
System.out.println("Port 2000 socket disconnected");
} catch (IOException e) {
e.printStackTrace();
}
}
private BufferedReader getBufferedReader(Socket socket)
throws IOException {
InputStreamReader is = new InputStreamReader(socket.getInputStream());
return new BufferedReader(is);
}
private BufferedWriter getBufferedWriter(Socket socket)
throws IOException {
OutputStreamWriter os = new OutputStreamWriter(socket.getOutputStream());
return new BufferedWriter(os);
}
// Safely here to handle the socket connection
private void handleSocket(Socket socket) {
System.out.println("Port 2000 socket connected");
try {
BufferedReader br = getBufferedReader(socket);
BufferedWriter bw = getBufferedWriter(socket);
String command = br.readLine();
switch (command) {
/* Media Manager */
case "media_areas":
System.out.println("NodeJS media_areas");
get_media_areas(br, bw);
break;
case "media_categories":
System.out.println("NodeJS media_categories");
get_media_categories(br, bw);
break;
/* Device manager */
case "devices_get":
System.out.println("NodeJS get_devices");
get_devices(br, bw);
break;
default:
System.out.println("NodeJS command not recognised: " + command);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* Handle commands
*/
// Command: media_areas
private void get_media_areas(BufferedReader br, BufferedWriter bw)
throws IOException {
JSONArray area_list = new JSONArray(); // create JSON array
System.out.println("Getting Area list");
synchronized (dev_server.library.media_lock) {
for (Area area : dev_server.library.media) {
area_list.put(area.name);
System.out.println("Area: " + area.name);
}
}
bw.write(area_list.toString()); // send JSON array back to NodeJS server
bw.flush(); // ensure a flush before the socket is closed
}
// ...
The issue I had was the data not being sent to the Node server, which using the flush() fixed that issue before the socket was closed.
This is a snipped from the Node server which connects to the Java TCP server and then sends the JSON data back to the clients browser.
const global = require("../global/global.js");
const login = require("../login/login");
const node_port = 2000;
const host = "localhost";
function m_get_media_areas(socket) {
// check user logged in (return to login page)
if (!login.check_logged_in(socket)) { return; }
client = new global.net.Socket(); // connect to Java TCP server
client.connect({port: node_port, host: host}, () =>
{ client.write("media_areas\n"); });
// send the JSON string to clients browser over socket.io
client.on("data", (data) => { socket.emit("media_areas", data); });
client.on("end", () => {});
client.on("error", () => { console.log("ERROR: getting areas"); });
}
module.exports = {
get_media_areas : m_get_media_areas,
// ...
}
On the clients browser side I just use socket.io to emit the command and then just listent for the event so that I can use the data.
// get area list
socket.emit("media_areas");
// media variables
media_area = "";
media_category = "";
media_videos = {}; // a JSON array of JSON objects
socket.on("media_areas", (res) => {
json = JSON.parse(new TextDecoder().decode(res));
$("#list_media_area").empty();
$("#list_media_category").empty();
$("#list_media_videos").empty();
json.forEach(area => {
if (area !== null && area !== "")
$("#list_media_area").append("<li>" + area);
});
media_area = "";
$("#list_media_area li").click(function() {
$(this).addClass("li_selected").siblings().removeClass("li_selected");
media_area = $(this).text();
console.log("Media Area Selected: " + media_area);
$("#accordion_video_category").click();
socket.emit("media_categories", {"area": media_area});
});
});
That's how I've managed to get around it and it works for me great.
The Java JSON library I used is:
https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.json%22%20AND%20a%3A%22json%22
Without more information on your server implementation it is difficult to answer this question directly. Here is a general example that should be helpful for you.
server.js
const net = require('net');
net.createServer(function(socket) {
// listen for data from the client
socket.on('data', function(data) {
console.log('data from client: ', String(data));
});
// write data to the client
socket.write('hello from the server\n');
}).listen('3000', function() {
console.log('server listening on 3000');
});
client.js
const net = require('net');
const socket = net.connect(3000, 'localhost')
// listen for data from the server
socket.on('data', function(data) {
console.log('data from server: ', String(data));
});
// write data to the server
socket.write('hello from the client\n');
First run node server.js then from a separate tab run node client.js. You should see the communication between the server and client. Another tool that may be helpful for you is telnet, which provides a simple tcp interface. You can test your server by using telnet localhost 3000

WebSocket stomp client subscribe for some devices are not working

I am trying to implement a spring boot chat application using WebSocket stomp client. If I send messages from one device to 4,5 devices then some are getting the messages and some are not. Some can send messages but don't receive any message and some are working completely fine. My application is running on wildfly server and the URL is over https.
Here is my js file. From my JSP page I am calling sendMsg with all parameter and through render method I am attaching the response with JSP using Handlebars.
if (!window.location.origin) {
window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
}
const url = window.location.origin+contextPath;
let stompClient;
let selectedUser;
let newMessages = new Map();
function connectToChat(userName, topicName) {
console.log("connecting to chat...")
let socket = new SockJS(url + '/chat');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log("connected to: " + frame);
stompClient.subscribe("/topic/decision-log", function (response) {
let data = JSON.parse(response.body);
var msg = data.message;
var fromlogin = data.message;
render(data.username, msg, fromlogin);
});
});
}
connectToChat("1", "decision-log");
function sendMsg(from, text, username) {
stompClient.send("/app/chat/" + from, {}, JSON.stringify({
fromLogin: from,
message: text,
topicName: topicName,
username: username
}));
}
function render(username, message, projectId) {
var templateResponse = Handlebars.compile($("#message-response-template").html());
var contextResponse = {
username: username,
response: message,
date: date,
projectId: projectId
};
setTimeout(function () {
$chatHistoryList.append(templateResponse(contextResponse));
scrollToBottom();
}.bind(this), 1500);
}
Here is my WebSocket configuration file:
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketConfiguration implements WebSocketMessageBrokerConfigurer{
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app").enableSimpleBroker("/topic");
}
}
This is the controller. I always save all messages on the database that are coming through WebSocket that's why I can be sure that all devices can send messages as they have been saved on the database.
#Controller
#AllArgsConstructor
public class MessageController {
#Autowired
private SimpMessagingTemplate simpMessagingTemplate;
private final DecisionLogService decisionLogService;
#MessageMapping("/chat/{to}")
public void sendMessage(#DestinationVariable String to, MessageModel message, Authentication authentication ) {
simpMessagingTemplate.convertAndSend("/topic/decision-log", message);
AuthResponse userDetails = (AuthResponse) authentication.getDetails();
DecisionLogCreateRequest decisionLogCreateRequest = new DecisionLogCreateRequest();
decisionLogCreateRequest.setDecision(message.getMessage());
decisionLogCreateRequest.setProjectId(to);
ServiceResponseExtended<Boolean> response = decisionLogService.addDecisionLog(userDetails.getAccessToken(), decisionLogCreateRequest);
}
}
I can not find anything similar this issue. Please help me with right information and suggestion, and if anyone faced same kind of problem please share with me.
The problem was solved after configuring RabbitMQ Stomp Broker as a message broker instead of SimpleBroker.
Current WebSocket configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketConfiguration implements WebSocketMessageBrokerConfigurer{
#Value("${stomp-broker-relay-host}")
private String RELAY_HOST;
#Value("${stomp-broker-relay-port}")
private String RELAY_PORT;
#Value("${stomp-broker-login-user}")
private String USER;
#Value("${stomp-broker-login-pass}")
private String PASS;
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableStompBrokerRelay("/topic").setRelayHost(RELAY_HOST).setRelayPort(Integer.parseInt(RELAY_PORT)).setClientLogin(USER)
.setClientPasscode(PASS);
}
}
Reference:
https://medium.com/#rameez.s.shaikh/build-a-chat-application-using-spring-boot-websocket-rabbitmq-2b82c142f85a
https://www.javainuse.com/misc/rabbitmq-hello-world

Failed to complete negotiation with the server - Angular + SignalR

I'm unable to establish a connection using Angular + Azure Functions using Nodejs. I know that the backend works because I created it using the following documentation and tested it with the client URL provided in docs. Messaging was working across multiple clients.
So now I'm trying to get Angular working. I've created a service for signalr in Angular to establish the connection, but I'm getting the errors
and on the network tab
I also tried replacing this code in service
private buildConnection = () => {
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:7070") //use your api adress here and make sure you use right hub name.
.build();
};
with this code
private buildConnection = () => {
this.hubConnection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Debug)
.withUrl("http://localhost:7070/api", {
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets
})
.build();
per the recommended answer from this post but then it just returns
I've never used SignalR before so I'm trying to piece this together from looking at several tutorials. I appreciate any help!
signalr service
import { Injectable, EventEmitter } from "#angular/core";
import * as signalR from "#aspnet/signalr";
import { SignalViewModel } from "./signal-view-model";
#Injectable({
providedIn: "root"
})
export class SignalRService {
private hubConnection: signalR.HubConnection;
signalReceived = new EventEmitter<SignalViewModel>();
constructor() {
this.buildConnection();
this.startConnection();
}
private buildConnection = () => {
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:7070/api") //c
.build();
};
private startConnection = () => {
this.hubConnection
.start()
.then(() => {
console.log("Connection Started...");
this.registerSignalEvents();
})
.catch(err => {
console.log("Error while starting connection: " + err);
//if you get error try to start connection again after 3 seconds.
setTimeout(function () {
this.startConnection();
}, 3000);
});
};
private registerSignalEvents() {
this.hubConnection.on("SignalMessageReceived", (data: SignalViewModel) => {
this.signalReceived.emit(data);
});
}
}
just like from Reference Docs link above, this is what my azure functions looks like
messages
module.exports = async function (context, req) {
return {
"target": "newMessage",
"arguments": [ req.body ]
};
};
negotiate
module.exports = async function (context, req, connectionInfo) {
context.res.json(connectionInfo);
};
host.json
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
},
"Host": {
"LocalHttpPort": 7070,
"CORS": "http://localhost:4200",
"CORSCredentials": true
}
}
Ok, you can't connect your Angular with the SignalR function because de CORS polity.
You forgot to configure the CORS on your function.
Try with this configuration.

It is possible to send a message to a specific user using SignalR?

I am new to SignalR, recently I am examining and learning how the following code works.
Link: https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/tutorial-getting-started-with-signalr
I would like to know what is the easiest way to send a message to a specific user using the code in the previous link. Has anyone had experience or tried to do the same? I just need ideas since I don't know all the functionalities and methods that SignalR offers.
In my web application users have a unique username and I need to use that data for the connection. I have seen that there is a way to create groups and send the message in that way but I do not understand completely, a very simple example would help me a lot.
Can you help me or give me some advice? Thank you
I'm already write a blog here
So basically you need to
First define a hub method like this
public async Task Send(string userId)
{
var message = $"Send message to you with user id {userId}";
await Clients.Client(userId).SendAsync("ReceiveMessage", message);
}
Add to startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.Configure(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddSignalR();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseSignalR(routes =>
{
routes.MapHub<ConnectionHub>("/connectionHub");
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
Then finally
(function () {
var connection = new signalR.HubConnectionBuilder().withUrl("/connectionHub").build();
connection.start().then(function () {
console.log("connected");
connection.invoke('getConnectionId')
.then(function (connectionId) {
sessionStorage.setItem('conectionId', connectionId);
// Send the connectionId to controller
}).catch(err => console.error(err.toString()));;
});
$("#sendmessage").click(function () {
var connectionId = sessionStorage.getItem('conectionId');
connection.invoke("Send", connectionId);
});
connection.on("ReceiveMessage", function (message) {
console.log(message);
});
})();
First I will need to make connection with the server using
new signalR.HubConnectionBuilder().withUrl(“/connectionHub”).build()
Then when the connection start I will invoke getConnectionId to get user connection id in the server and store into session storage because when we do refresh the browser signalR server will give you new connection id
Next when I click on the button I will invoke Send method in the server and I will listen
on “ReceiveMessage”
using connection.on(“ReceiveMessage”);
public class MyHub : Hub
{
public void Send(string userId, string message)
{
Clients.User(userId).send(message);
}
}
https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/mapping-users-to-connections

SignalR js client wrong Server port

I'm starting with signalr but got some trouble, my test server run at http://localhost:22660/ and my web run at
http://localhost:61963/.I got this error when connect from client to server:
GET http://localhost:61963/signalr/negotiate?clientProtocol=1.4&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&_=1496809403215 404 (Not Found)
I already config: $.connection.hub.url = 'http://localhost:22660/signalr'; but not work, this my js code:
var connection = $.hubConnection();
$.connection.hub.url = 'http://localhost:22660/signalr';
var chatHub = connection.createHubProxy('ChatHub');
connection.start()
.done(function () { console.log('Now connected, connection ID=' + connection.id); })
.fail(function () { console.log('Could not connect'); });
Server:
namespace test
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableJSONP = true
};
map.RunSignalR(hubConfiguration);
});
}
}
}
namespace SignalRChat
{
public class ChatHub : Hub
{
public void Send(string name, string message)
{
// Call the addNewMessageToPage method to update clients.
Clients.All.addNewMessageToPage(name, message);
}
}
}
I dont sure, but i think because i using different version of signalr (2.1.2 and 2.2.0). Using same version solved my problem.

Categories

Resources