Signalr persistent connection with query params. - javascript

I have a persistent connection which I would like to start with some seed info using query params. Here is the override in the connection.
protected override Task OnConnected(IRequest request, string connectionId)
{
//GET QUERY PARAMS HERE
return base.OnConnected(request, connectionId);
}
Now I have my route setup in global.asax file which looks like this.
RouteTable.Routes.MapConnection("myconnection",
"/myconnection");
And the client code looks like this
var connection = $.connection('/myconnection');
connection.start()
.done(() =>
{
});
Can someone tell me how I can pass query string params to this connecton so I can read them in the override as I seem to be hitting a brick wall on this.
Cheers hope someone can help,
Dave

HUBS
var connection = $.connection('/myconnection');
$.connection.hub.qs = "name=John"; //pass your query string
and to get it on the server
var myQS = Context.QueryString["name"];
To access your query string in javascript you could use something like
function getQueryStringValueByKey(key) {
var url = window.location.href;
var values = url.split(/[\?&]+/);
for (i = 0; i < values.length; i++) {
var value = values[i].split("=");
if (value[0] == key) {
return value[1];
}
}
}
Call it:
var name = getQueryStringValueByKey("name");
PERSISTENT CONNECTION
//pass your query string
var connection = $.connection('/myconnection', "name=John", true);
protected override Task OnConnected(IRequest request, string connectionId)
{
//get the name here
var name = request.QueryString["name"];
return base.OnConnected(request, connectionId);
}
Here is the source code where you can find out more: https://github.com/SignalR/SignalR/blob/master/src/Microsoft.AspNet.SignalR.Client.JS/jquery.signalR.core.js#L106

Related

Why I get only part of the URL from the HttpContext?

I use proxy to get recource from remote server.
Here is proxy class:
public class Proxy : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string url = context.Request["url"];
var request = (HttpWebRequest)WebRequest.Create(url);
request.UserAgent = context.Request.UserAgent;
request.ContentType = context.Request.ContentType;
request.Method = context.Request.HttpMethod;
request.ProtocolVersion = HttpVersion.Version11;
request.KeepAlive = false;
request.Timeout = 100000;
request.ReadWriteTimeout = 100000;
using (var response = request.GetResponse())
{
context.Response.ContentType = response.ContentType;
using (var responseStream = response.GetResponseStream())
{
if (responseStream == null) return;
responseStream.CopyTo(context.Response.OutputStream);
context.Response.OutputStream.Flush();
}
}
}
}
And here is my ajax call to remote service:
function wfs(layer) {
let dest_url = "https://www.mysited.com/geodata2055/service/mapagent.fcgi?SERVICE=WFS&MAXFEATURES=500&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=ns216630453:WW_MONITOR";
let proxy_url = "/localhost/Proxy.ashx?url=";
let url = proxy_url + dest_url;
var xhr = new XMLHttpRequest();
xhr.open('GET', url); // depricated-'/proxy.ashx?url='+
xhr.onload = function () {
if (xhr.status === 200) {
console.log("loader success");
} else {
console.log("loader fail");
}
},
xhr.send();
}
when wfs function is fired the ProcessRequest function in proxy class is triggered and value of the url variable is:
https://www.mysited.com/geodata2055/service/mapagent.fcgi?SERVICE=WFS
While I expect the value of url to be:
https://www.mysited.com/geodata2055/service/mapagent.fcgi?SERVICE=WFS&MAXFEATURES=500&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=ns216630453:WW_MONITOR
It seems that context.Request["url"] returns cuted value until first '&'.
Any idea why I get from context.Request["url"] only part of the url?
You need to encode your query param, because it doesn't contain characters that are safe for query parameters:
let url = "/localhost/Proxy.ashx?url=" + encodeURIComponent(dest_url);
To further explain, let's pretend we're a URL parser. Without the encoding, you'll see this string:
/localhost/Proxy.ashx?url=https://www.mysited.com/geodata2055/service/mapagent.fcgi?SERVICE=WFS&MAXFEATURES=500&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME=ns216630453:WW_MONITOR
The parser will go through these steps as it visits the characters:
URL path: /localhost/Proxy.ashx
Query params starting: ?
Param name: url
Starting param value: =
(some of these next chars aren't valid, but I'll try my best!)
Param value:
https://www.mysited.com/geodata2055/service/mapagent.fcgi?SERVICE=WFS
Starting next param: &
Param name: MAXFEATURES
Starting param value: =
Param value: 500
...etc
So because it's encountering the & while scanning your string, it thinks parameters like MAXFEATURES are query parameters for your proxy request, not part of the url parameter passed to the proxy request. Therefore, when your proxy code runs, it's seeing only things up to that &.
Encoding the URL parameter will give you:
/localhost/Proxy.ashx?url=https%3A%2F%2Fwww.mysited.com%2Fgeodata2055%2Fservice%2Fmapagent.fcgi%3FSERVICE%3DWFS%26MAXFEATURES%3D500%26VERSION%3D1.0.0%26REQUEST%3DGetFeature%26TYPENAME%3Dns216630453%3AWW_MONITOR
With this, the parser now only see a url parameter passed to the proxy handler. When the proxy handler now parses the url parameter, it will decode it, giving you back your original dest_url
As a general rule of thumb, never just use string concatenation to build URLs; URLs aren't made up of strings, they're made up of URL-encoded strings.

How to generate hash512 in pre-request from request that has {{variables}} in uri

So I m working on API when i need to set x-auth header for every request in PRE-REQUEST script.
I have variables in my request url i.e {{baseUrl}}{{basePath}}{{businessID}}/users?name={{userName}}......etc
I need to take whole address and add secretKey variable to the end of address, then get hash512 from it.
I was able to achieve that if i have no variables in my address i.e.: dummy.com/12321-e213-21-3e?name=John
I did this by :
var secret = "1234qwerHr2";
var url = request.url.slice(9); //sliced because I don't need to include baseUrl to hash
var hashedPayload = CryptoJS.enc.Hex.stringify(CryptoJS.SHA512(url+secret));
This will return the desired result.
Here is what I logged when trying the same code with variables
console.log(url); =>>>>>>> asePath}}{{businessID}}/users?name={{userName}}......etc
All variables defined , that`s for sure
Basically question is : how to get url with values of variables using var url = request.url; I need not {{businessID}}/users?name={{userName}} but 12321-e213-21-3e?name=John
I lost source where i found it. Somewhere on postman github issue thread
var secret = pm.globals.get("devSecretKey");
pm.myUtility = {
interpolateVariable: function (str) {
return str.replace(/\{\{([^}]+)\}\}/g, function (match, $1) {
// console.log(match)
let result = match; //default to return the exactly the same matchd variable string
if ($1) {
let realone = pm.variables.get($1);
if (realone) {
result = realone
}
}
return result;
});
},
getUrl: function () {
let url = pm.request.url.getRaw();
url = this.interpolateVariable(url)
let {
Url
} = require('postman-collection')
return new Url(url);
},
getUrlTest: function () {
let url = pm.request.url.getRaw();
url = this.interpolateVariable(url)
// let {
// Url
// } = require('postman-collection')
//return new Url(url);
return pm.request.url.parse(url);
}
}
var requestPath = pm.myUtility.getUrl().getPath();
var requestQuery =pm.myUtility.getUrl().getQueryString();
var hashedPayload = CryptoJS.enc.Hex.stringify(CryptoJS.SHA512(requestPath+"?"+requestQuery+secret)); //I added '?' because when you use getQueryString() i does not have '?' before query
pm.environment.set("tempAuthHash", hashedPayload);// use this in your header
This function he wrote is converting your {{variable}} to 'variableValue'
No need to change anything in his functions if you are not good with coding. Guy who created it has golden hands. Just place in your pre request

SignalR javascript client not picking up event from hub

I have a method on the hub however I am not getting any messages from this. I get the connection ID's from my user to connectionid mapping dictionary and loop through these connectionid's and then invoke a method on the client side called deviceDiscovered I can also confirm that the browser does connect to the hub
Here is my hub method
public async Task DetectDevice(dynamic message)
{
//We will be searching via the userid
var connectionId = Context.ConnectionId;
//now we get the connectionID from the table.
var connectionObj = ConnectionTable[connectionId];
//we now check whether this is a pathfinder or browser client
if (connectionObj.clientType == "pathfinder")
{
/*The pathfinder initiated the request and so this means the message should be forwarded to the browser client
that requested this resource*/
//Grab the data out of the dictionary.
PathfinderDetection deviceDiscoveredNotification = JsonConvert.DeserializeObject<PathfinderDetection>(message);
var userId = deviceDiscoveredNotification.userId;
var sysInfo = deviceDiscoveredNotification.sysInfo;
var found = deviceDiscoveredNotification.data;
if (found == "FOUND")
{
var deviceId = deviceDiscoveredNotification.deviceID;
var connections = ConnectionTable.Where(val => val.Value.id == connectionObj.id).Select(key => key.Key).ToList();
foreach (string connection in connections)
{
Clients.Client(connection).deviceDiscovered(deviceId);
}
}
else
{
//call a method on client side.
Clients.Group(userId.ToString()).noDevice("NOTFOUND");
}
I can see that the deviceID variable is populated and that the connection exists, however not getting anything back from the hub when looking at the client
here is my client side code:
<script>
$(document).ready(function(){
var connection = $.hubConnection("http://localhost:59016");
var contosoChatHubProxy = connection.createHubProxy('metrics');
contosoChatHubProxy.on('taskAdded', function(data){
console.log(data);
});
contosoChatHubProxy.on('deviceDiscovered', function(data) {
console.log(data);
});
contosoChatHubProxy.on('taskUpdate', function(data){
console.log(data);
});
contosoChatHubProxy.on('noDevice', function(found) {
console.log(found);
});
});
</script>

SignalR Client How to Set user when start connection?

Server side:
public override Task OnConnected()
{
var connectionId = Context.ConnectionId;
var user = Context.User.Identity.Name; // Context.User is NULL
return base.OnConnected();
}
Client side (in Console project):
IHubProxy _hub;
string url = #"http://localhost:8080/";
var connection = new HubConnection(url);
_hub = connection.CreateHubProxy("TestHub");
connection.Start().Wait();
When the client connect to the server, I want to know the map between userName and connectionId, But Context.User is NULL. How do I set this value in the client side?
try this with queryString in asp.netcore 2.1:
Client (javascript)
set query string after url like follow:
var connection = new signalR.HubConnectionBuilder().withUrl("http://localhost:10499/chathub?username=xxxx").build();
connection.start().then(function ()
{
// do some thing here ...
}).catch(function (err)
{
console.error(err.toString());
});
.
.
.
Server
public override Task OnConnectedAsync()
{
var username = Context.GetHttpContext().Request.Query["username"];
// username = xxxx
return base.OnConnectedAsync();
}
Pass your username using query string.
Client
First set query string
string url = #"http://localhost:8080/";
var connection = new HubConnection(url);
_hub = connection.CreateHubProxy("TestHub");
connection.qs = { 'username' : 'anik' };
connection.Start().Wait();
Server
public override Task OnConnected()
{
var username= Context.QueryString['username'];
return base.OnConnected();
}
Client
var connection = new HubConnection(<YOUR_URL>);
connection.Headers.Add("username", "maria");
var myHub = connection.CreateHubProxy("MyHub");
Server
string username = Context.Headers.Get("username");
Console.WriteLine("New client connection - " + username);
If your using basic authentication create a new System.Net.NetworkCredential
string url = #"http://localhost:8080/";
var connection = new HubConnection(url);
NetworkCredential myCredentials = new NetworkCredential("","","");
myCredentials.Domain = "domain";
myCredentials.UserName = "username";
myCredentials.Password = "passwd";
connection.Credentials = myCredentials;
_hub = connection.CreateHubProxy("TestHub");
connection.Start().Wait();
See: https://learn.microsoft.com/en-us/dotnet/api/system.net.networkcredential.username?view=net-6.0
try this
Client (C#)
//Enter query string
var querystringData = new Dictionary<string, string>();
querystringData.Add("username", "naveed");
IHubProxy _hub;
string url = #"http://localhost:8080/";
var connection = new HubConnection(url);
_hub = connection.CreateHubProxy("TestHub");
connection.Start().Wait();
connection.Start().Wait();
Server
public override Task OnConnected()
{
var connectionId = Context.ConnectionId;
var username= Context.QueryString["username"]; //here you will receive naveed as username
return base.OnConnected();
}

Socket.io: How to uniquely identify a connection on client and server?

My app supports multiple socket.io clients from the same host (IP address). For diagnostics, I need to be able correlate client and server logs to identify which client the server is talking to. Does socket.io provide a way to uniquely identify a connection?
What I do is that within /routes/socket.js, I have these added to my requires:
var thisApp = require('../app');
var cookieSig = require('express/node_modules/cookie-signature');
var cookie = require('cookie');
var connect = require('express/node_modules/connect')
, parseSignedCookie = connect.utils.parseSignedCookie;
This answer assumes you have a session store of some kind that you can access via thisApp.thisStore. In my case, in the main app.js, I set up a session store using kcbanner's connect-mongo (available via npm and github.com) using a MongoDB back-end hosted on MongoLab for mine. In the session store, for each session, you can have a unique username, or some other identifier that goes along with that session. Really, you can tack any data you want to that session. That's how you'd tell them apart.
The code I use looks like this:
module.exports = function (socket) {
socket.on('taste:cookie', function (data, callback) {
console.log("taste:cookie function running");
//get the session ID
var sid = data.sid;
sid = parseSignedCookie(sid['connect.sid'], "mySecret");
console.log("sid: ",sid);
//get the handshake cookie
var hssid = cookie.parse(socket.handshake.headers.cookie);
hssid = parseSignedCookie(hssid['connect.sid'], "mySecret");
console.log("hssid: %s",hssid);
if(sid) {
if(sid['connect.sid']) {
sid = sid['connect.sid'].slice(2);
console.log("sliced the sid: %s",sid);
sid = cookieSig.unsign(sid, "mySecret");
hssid = sid;
}
if(hssid != sid) {
console.log("browser cookie not set right; rectifying...");
data.sid = hssid;
sid = hssid;
}
else console.log("browser cookie was set right");
}
thisApp.thisStore.get(sid, function(err, gotsession) {
if(err || !gotsession) {
//handle error
return;
} else {
if(gotsession.username) {
callback(0, {username:gotsession.username});
}
else callback(1, {username:""});
}
});
});
Maybe there's a more elegant way to do this, but this does work.
You can use session+cookies: Here's a library that you can use or learn from: session-socket.io.
You'll find plenty of examples on their README page.

Categories

Resources