SignalR Multiple Hub Connection .NET Core - asp.net

I have 2 Hub classes,
SystemNotificationHub.cs
public class SystemNotificationHub : Hub { }
QuotationChatHub.cs
public class QuotationChatHub: Hub { }
SystemNotificationHub is defined in _Layout.cshtml so user is connected to hub continously,
and when user enters to QuotationChat.cshtml page, I want also same user to connect the QuotationChatHub, so in a simple manner I'd like the user to connect multiple hubs at the same time.
I cannot let user to connect more than 1 hub at the same time. How can I achive this?
StartUp endPoint Configurations
endpoints.MapHub<SystemNotificationHub>("/systemNotificationHub");
endpoints.MapHub<QuotationHub>("/quotationHub");
quotationChat.js
$(function () {
if (connection === null) {
connection = new signalR.HubConnectionBuilder()
.withUrl("/quotationHub")
.build();
connection.start().then(function () {
document.getElementById('sendButton').onclick = function () {
connection.invoke("BroadcastFromClient")
.catch(function (err) {
return console.error(err.toString());
});
};
});
}
});
notification.js
$(function () {
if (connection === null) {
connection = new signalR.HubConnectionBuilder()
.withUrl("/systemNotificationHub")
.build();
connection.on("Notify", function (response) {
});
connection.on("HubError", function (response) {
alert(response.error);
});
connection.start().then(function () {
connection.invoke("NotificationMethod")
.catch(function (err) {
return console.error(err.toString());
});
});
}
});

As far as I know, this issue is related with your if condition in your codes.
You have checked connection is null or not before creating the connection builder. But all two js use the same connection model.
To solve this issue, I suggest you could try to create a new connection for systemNotificationHub for example connection1 and then your code will work well.
More details, you could refer to below codes:
quotationChat.js not changed.
notification.js:
//Define a new connection1 as the new js object as connection
$(function () {
if (connection1 === null) {
connection1 = new signalR.HubConnectionBuilder()
.withUrl("/systemNotificationHub")
.build();
connection1.on("Notify", function (response) {
});
connection1.on("HubError", function (response) {
alert(response.error);
});
connection1.start().then(function () {
connection.invoke("NotificationMethod")
.catch(function (err) {
return console.error(err.toString());
});
});
}
});

Related

K6 trigger ASP.NET Core server function

I have an ASP.NET Core Web API project that is using SignalR, I have a hub there which I am connecting to it using k6 (I want to do some load testings) I manage to connect to my hub but I can not figure out how to call a function from my server, my code is
import ws from 'k6/ws';
import { check } from 'k6';
export default function () {
var token = "Bearer userAccessToken";
const url = 'wss://localhost:5001/session';
const params = { headers: { "Authorization": token } };
const res = ws.connect(url, params, function (socket) {
socket.on('open', () => {
console.log("opened");
socket.send(JSON.stringify({ UserId: "aUserId", GameId: "AGameId" }))
});
socket.on('close', () => console.log('disconnected'));
});
check(res, { 'status is 101': (r) => r && r.status === 101 });
}
My function is called joinGameSession and it takes two variables the user id and the gameId
public async Task<bool> JoinGameSession(JoinGameRequest request)
{
return true;
}
I have managed to trigger functions using Microsoft's SignalR client.
const signalR = require("#microsoft/signalr");
require('dotenv').config();
var token = process.env.token ?? "";
var questionIndex = 0;
let connection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:5000/session", { headers: { "Authorization": token } })
.withAutomaticReconnect()
.build();
connection.start().then(() => {
connection.invoke("JoinGameSession", { UserId: "a", GameId: "x" });
}).catch(e => {
console.log(e);
})
but I can not do it with k6, is there any other tools to achieve my goal?
Thank you.

SignalR restore connection

how do I restore connection without refreshing the client app browser if the backend server goes down, and comes back up in 5min or so...
const connection = new signalR.HubConnectionBuilder()
.withUrl(`/place/${props.match.params.id}`)
.withAutomaticReconnect()
.build();
connection.onreconnecting(function() {
setError('connection lost..');
var reconnectionInterval = setInterval(() => {
if (connection.state == signalR.HubConnectionState.Disconnected) {
connection.stop();
try {
console.log('try to reconnect');
connection.start();
} catch (e) {
//doesn't go here, how to handle if the server still down
console.log('failed to reconnect');
}
}
}, 5000);
});
This seems to work
if (connection.state == signalR.HubConnectionState.Disconnected) {
connection.start()
.then(x => {
clearInterval(reconnectionInterval);
setError(null);
})
.catch(ex => setError('still disconnected'));
}

Hub events not available

I am getting the following error when trying to subscribe to a SignalR hub event:
$.connection.hub.connectionSlow is not a function
My code:
var connection = $.hubConnection();
serviceRequestHubProxy = connection.createHubProxy('myHub');
connection.start()
.done(function () { alert('connected!'); });
$.connection.hub.connectionSlow(function () {
alert('connection slow!');
});
I am using SignalR 2.2. What am I doing wrong?
When you're not using generated proxy, $.connection will not be available. You should change to.
var connection = $.hubConnection();
serviceRequestHubProxy = connection.createHubProxy('myHub');
connection.start()
.done(function () { alert('connected!'); });
connection.connectionSlow(function () {
console.log('We are currently experiencing difficulties with the connection.')
});
Read more

Evothings and ddp

We are trying to connect our evothings app up to a meteor server.
To do this we are using a lib called asteroid. However we are unable to connect and run methods. We are absolutly sure this is not a server issue since we have some separate client code for testing that works flawlessly with it.
Evothings says it should work with websockets, and we aren't getting any error output, but all our method calls are returning nothing.
Here is the code:
var _asteroid = require('asteroid');
var Asteroid = (0, _asteroid.createClass)('password-login');
var asteroid = new Asteroid({ endpoint: 'wss://[url]/websocket' });
var currentLogin = null;
$('#login').submit(function(event) {
event.preventDefault();
login($('#login_username').val(), $('#login_password').val());
});
$('#create').submit(function(event) {
event.preventDefault();
newUser($('#create_username').val(), $('#create_password').val(), $('#create_id').val());
});
$('#occupy').click(function(event) {
setStatus(0);
});
$('#vacant').click(function(event) {
setStatus(1);
});
$('#refreash').click(function() {
getEmptyRooms();
});
window.newUser = function (username, password, roomId) {
$('#create_error').text('');
asteroid.call("accounts.newUser", username, password, roomId).then(function (result) {
console.log("Success");
login(username, password);
}).catch(function (error) {
console.log("Error");
console.error(error);
$('#create_error').text(error.message);
});
}
window.login = function (username, password) {
$('#login_error').text('');
asteroid.loginWithPassword({ username: username, password: password }).then(function (result) {
console.log(result);
currentLogin = result;
$('#current').html('Current User: ' + username);
}).catch(function (error) {
console.log("Error");
console.error(error);
$('#login_error').text(error.message);
});;
}
window.getEmptyRooms = function () {
asteroid.call("rooms.getAvailable").then(function (result) {
console.log(result);
$('#room_list').empty();
for(i = 0; i < result.length; i++) {
$('#room_list').append('<li>' + result[i] + '</li>');
}
}).catch(function (error) {
console.log("Error");
console.error(error);
});
}
window.setStatus = function (status) {
$('#status_error').text('');
if (currentLogin != null) {
asteroid.call("rooms.setStatus", status).then(function (result) {
console.log(result);
}).catch(function (error) {
console.log("Error");
console.error(error);
$('#status_error').text(error.message);
});
} else {
console.log('please login first');
$('#status_error').text('please login first');
}
}
As far as I know, the require() function works only in node.js, not in browser environment such as Evothings Viewer or Cordova, so you'll need some alternative means of loading the "asteroid" lib. Browserify?
How did you look for error output? The Evothings Tools window? If so, did you add this snippet to your index.html file?
<script>
// Redirect console.log to Evothings Workbench.
if (window.hyper && window.hyper.log) { console.log = hyper.log }
</script>
Perhaps this error isn't exclusive to the Evothings environment. Have you tested the app in a regular web browser?
Are you using proper certs?
Self signed will not work. The Evothings app is served via wss and since it runs "headless" so to speak (not a normal browser) it can't ask the user about allowing a self signed cert, so it will fail. Note that AFAIK ANY issue with the cert will make it fail.

Returning data from server method to client after server calls an HTTP API

I am trying to learn Meteor, starting by writing a simple application where the server calls an HTTP API based on user input, processes the information, then returns it to the client to display it.
I am not having much success. I can't seem to return the result from server to client:
if (Meteor.isServer) {
Meteor.methods({
checkTransit: function(method, url, options) {
this.unblock();
return Meteor.http.call(method, url, function(error, result) {
if (error) {
console.log('SERVER ERRR');
console.log(error);
} else {
console.log('SERVER RESULT');
console.log(result);
}
});
}
})
}
if (Meteor.isClient) {
Template.body.events({
"submit .new-task": function(event) {
// Prevent default browser form submit
event.preventDefault();
var text = event.target.text.value;
var method = 'GET';
var url = 'http://sometransitapi.com';
var options = {
headers: {
'accept': 'application/XML',
'content-type': 'application/XML'
}
}
Meteor.call('checkTransit', method, url, options, function (error, result) {
if (error) {
console.log('CLIENT ERRR');
console.log(error);
} else {
console.log('CLIENT RESULT');
var parser;
parser = new DOMParser();
var xmlDoc
xmlDoc = parser.parseFromString(result, "text/xml");
console.log(xmlDoc);
}
})
}
})
}
I can see the results being returned to the result variable at isServer, but I can not pass the result to the xmlDoc variable in isClient. What am I doing wrong? Is this the correct way to structure things for what I want to do in Meteor?
Meteor.http.call is being called asynchronously in your server code (you are passing a callback). The functions in your Meteor.methods object expect to return a value, so you should be calling Meteor.http.call synchronously. Changing your server code to below should do the trick.
if (Meteor.isServer) {
Meteor.methods({
checkTransit: function(method, url, options) {
this.unblock();
// This will throw an exception and return it as the error object
// in your Meteor.call if an error occurs, otherwise it will
// return an empty error object and the result object will be
// the return value from Meteor.http.call
return Meteor.http.call(method, url);
}
})
}
If you want to keep the logic on the server side then #Curtis' answer should help you.
Looking at what you have, I don't see much of a point of getting the server to do the work. The Http api is available everywhere in Meteor. You are just fetching data, which can be solely done on the front end. This would also technically make it faster. Taking your code and moving it around a bit you get the following.
if (Meteor.isClient) {
Template.body.events({
"submit .new-task": function(event) {
// Prevent default browser form submit
event.preventDefault();
var text = event.target.text.value;
var method = 'GET';
var url = 'http://sometransitapi.com';
var options = {
headers: {
'accept': 'application/XML',
'content-type': 'application/XML'
}
}
Http.call(method, url, options, function (error, result) {
if (error) {
console.log('CLIENT ERRR');
console.log(error);
} else {
console.log('CLIENT RESULT');
var parser;
parser = new DOMParser();
var xmlDoc
xmlDoc = parser.parseFromString(result, "text/xml");
console.log(xmlDoc);
}
});
}
});
}

Resources