Cross domain from SignalR2 to phantomjs - javascript

this project work right on SignalR v1.1.4, client is phantomjs with cors:
webpage = require "webpage"
websocket = webpage.create()
serverUrl = "http://www.domain.com"
websocket.injectJs './jquery-2.1.0.min.js'
websocket.injectJs './jquery.signalR-1.1.4.min.js'
websocket.includeJs serverUrl + '/signalr/hubs', ->
websocket.evaluate (serverUrl)->
$.support.cors = false
$.connection.hub.url = serverUrl + '/signalr'
taskHub = $.connection.taskHub
$.connection.hub.start().done ->
taskHub.server.registerAgent "xxx"
#……
taskHub.client.castTesk = (task) ->
#……
, serverUrl
until upgrade SignalR to v2.0.2.
i remove RouteTable.Routes.MapHubs(new HubConfiguration() { EnableCrossDomain = true }) on Application_Start() and add Startup.cs:
[assembly: OwinStartup(typeof(SpiderMan.Startup))]
namespace ProjectNamespace {
public partial class Startup {
public void Configuration(IAppBuilder app) {
app.Map("/signalr", map => {
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration {
EnableJSONP = true
};
map.RunSignalR(hubConfiguration);
});
}
}
}
then $.connection.hub.start() work right always, but taskHub.client.castTesk() could not be triggered, without any error message.
update:
v1.2.1 is work fail also like v2.0.2.
And, Microsoft.AspNet.SignalR Package with any version on server could not affect this issus. client work right with jquery.signalR-1.1.4.min.js, fail with jquery.signalR-1.2.1.min.js always, for any server signalR version.

You should define your castTesk method before you start your connection. This issue is discussed in the "Connection started before subscriptions are added" section of the SignalR Troubleshooting Guide.
#……
taskHub.client.castTesk = (task) ->
#……
$.connection.hub.start().done ->
taskHub.server.registerAgent "xxx"
#……
The problem is that if you call $.connection.hub.start() before you define taskHub.client.castTesk, SignalR will not subscribe the client to the TaskHub.
You will still be able to invoke server-side methods belonging to the TaskHub such as RegisterAgent, but the server will be unable to invoke client methods such as castTesk.
I would also suggest removing the $.support.cors = false line. This will cause SignalR to always use JSONP instead of CORS even if the browser supports CORS.

Related

SignalR unable to connect from client to server with any available transport

I'm trying to connect to a websocket established with SignalR on my server (.NET).
My client (JavaScript) starts the negotiation, gets a response with the connectionId, connectionToken, etc., but afterwards is not able to connect with any of the available transport methods.
The last debug-trace I get is this:
[2022-11-17T10:21:02.093Z] Debug: HubConnection failed to start successfully because of error 'Error: Unable to connect to the server with any of the available transports. WebSockets failed: Error: There was an error with the transport. ServerSentEvents failed: Error: Error occurred LongPolling failed: Error'.
My server code:
Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace Sample
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options => options.EnableEndpointRouting = false).SetCompatibilityVersion(CompatibilityVersion.Version_3_0).AddNewtonsoftJson();
services.AddSignalR().AddNewtonsoftJsonProtocol(opt => {
opt.PayloadSerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
{
builder.WithOrigins("http://localhost:8080", "http://127.0.0.1:8080")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
}));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseFileServer();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseCors("MyPolicy");
app.UseMvc();
app.UseRouting();
app.UseEndpoints(routes =>
{
routes.MapHub<Controllers.DesignAutomationHub>("/api/signalr/designautomation");
});
}
}
}
Controller:
using Autodesk.Forge;
using Autodesk.Forge.DesignAutomation;
using Autodesk.Forge.DesignAutomation.Model;
using Autodesk.Forge.Model;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Sample.Controllers
{
[ApiController]
public class ServiceController : Controller
{
// Design Automation v3 API
DesignAutomationClient _designAutomation;
// Used to access the application folder (temp location for files & bundles)
private IWebHostEnvironment _env;
// used to access the SignalR Hub
private IHubContext<DesignAutomationHub> _hubContext;
public ServiceController(IWebHostEnvironment env, IHubContext<DesignAutomationHub> hubContext, DesignAutomationClient api)
{
_designAutomation = api;
_env = env;
_hubContext = hubContext;
}
}
/// <summary>
/// Class uses for SignalR
/// </summary>
public class DesignAutomationHub : Microsoft.AspNetCore.SignalR.Hub
{
public string GetConnectionId() { return Context.ConnectionId; }
}
}
Client:
var connection;
var connectionId;
function startConnection(onReady) {
if (connection && connection.connectionState) {
if (onReady) onReady();
return;
}
connection = new signalR.HubConnectionBuilder()
.withUrl(
"http://<SERVERADRESS>/api/signalr/designautomation"
)
.configureLogging(signalR.LogLevel.Trace)
.build();
connection.start().then(function () {
connection.invoke("getConnectionId").then(function (id) {
connectionId = id;
if (onReady) onReady();
});
});
connection.on("downloadResult", function (url) {
console.log('Download result file here');
});
connection.on("onComplete", function (message) {
console.log(message);
});
}
I tested it locally with server and client on one machine, and all is working fine. But since the deployment test, I get the errors. (Websockets are activated on the server.)
Also Postman can establish a connection to the websocket, just my client fails.
I would appreciate any kind of help. Thanks in advance!
EDIT:
I also tried connecting to SignalR via the (here) described alternative to the SignalR client-side.
async function connectToWebsocket(negotiations) {
let token = encodeURIComponent(negotiations.connectionToken);
let wssPath = `ws://<SERVERADRESS>/api/signalr/designautomation?id=${token}`;
let ws = new WebSocket(wssPath);
console.log(ws);
}
async function connectToSignalR() {
$.ajax({
url: "<SERVERADRESS>/api/signalr/designautomation/negotiate?negotiateVersion=1",
contentType: "application/json",
dataType: "json",
headers: { "Access-Control-Allow-Origin": "*" },
type: "POST",
success: function (res) {
console.log(res);
connectToWebsocket(res);
},
error: function (error) {
console.log(error);
},
});
}
Still with the same outcome. I get the response from the negotiation but cant connect to the websocket.
As an additional Information. My "server" is an iis-express on a Azure-VM with a via ngrok forwarded adress.
ANOTHER EDIT:
My whole case about the use of SignalR is to get a websocket connection running, which the autodesk-forge servers can callback, when they finished my submitted task, to let them know what the next tasks are.
I added the Tag, maybe someone from this direction encountered same problems and could give a hint.
AND ANOTHER EDIT:
I now also tried the connection to the remote server with the simplest example I could find, the chatapp example from microsoft.
Still the same problems. I added the whole console output here:
Also I'm curious if theres maybe something wrong with my CORS.
But it's defined as stated in every working example...
The problem resulted from ngrok and probably CORS (as stated in the console output).
After a push in the right direction, I tried another tool (Conveyor - VS Extension) forwarding localhost to the net. There was absolutely no issue with connecting to the websocket or any other transport method from a remote client.
So for anybody with the same problem, trying to debug websocket connections forwarded with ngrok in iis-express and getting CORS errors, use Conveyor instead.
As long as you don't know how to configure ngroks CORS handling ("http --host-header=rewrite" wasn't doing the trick).
If you know how to configure ngroks CORS handling, I would be glad to read it in the comments.

SignalR callback does not trigger in JQuery UI widget

I am trying to create a JQuery UI widget that receives realtime updates from a server using SignalR (2.2.0). Invoking a method on the server works just fine, however invoking a client callback from the server does not trigger on the client.
I have enabled logging on the client as is suggested here: SignalR Troubleshooting and I can see in the console that the connection is setup just fine but the client method is never invoked. There is no error message of any kind. I have also defined the client method on the hub proxy before starting the connection like so:
_bindClientCallbacks: function () {
theHub.client.broadCastToClient = function (message) {
twr.log(message);
};
}
and afterwards I start the hub connection like so:
_startSignalRClient: function () {
$.connection.hub.logging = true;
$.connection.hub.start()
.done(function () {
twr.log("Connected to SignalR hub, id=" + $.connection.hub.id);
})
.fail(function () {
});
}
These methods are called in the '_create()' function in the JQuery widget like so:
_create: function () {
theHub = $.connection.DataImportHub;
this._bindClientCallbacks();
this._startSignalRClient();
}
This works fine and I can get a valid connection with an id. I can also call a server method from the client. But when I try to invoke the broadCastToClient method on the client from the server like so:
public void BroadCastToClient(string userId, string message)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<DataImportHub>();
foreach (var connectionId in _connections.GetConnections(userId))
{
hubContext.Clients.Client(connectionId).broadCastToClient(message);
}
}
Nothing happens on the client.. even though the server does find a valid connection that corresponds to the connection id I got on the client.
What am I missing here?
Just found out the solution by reading this post. Apparently having a custom SignalR dependency resolver setup in the Owin startup class breaks javascript callbacks. Moving the dependency resolver setup code to Application_Start in Global.asax does the trick. Why this happens really is beyond me...
Bad DI setup in Startup.cs
app.Map("/signalr", map =>
{
var hubConfiguration = new HubConfiguration
{
Resolver = new NinjectSignalRDependencyResolver(new StandardKernel())
};
map.RunSignalR(hubConfiguration);
});
Good DI setup in Global.asax
protected void Application_Start()
{
GlobalHost.DependencyResolver = new NinjectSignalRDependencyResolver(new StandardKernel());
}

signalr - with different clients

I am trying to setup a signalR system.
I have the sample code working, using two browsers and the same hub. messages are sent and received.
Now, when I created a different page, and try to send messages to the hub, it appears to be kinda working, meaning it doesn't blow up, but nothing gets transmitted to the other clients.
I thought I was accessing the same message hub, from all the clients, but maybe I am missing something.
Is it possible to connect different web sites to the same message hub?
Begin Edit
As requested.... here is the code i am using on my second client...
var connection = $.hubConnection('http://xxxxxxxxx.azurewebsites.net/');
var contosoChatHubProxy = connection.createHubProxy('MessagePump');
// contosoChatHubProxy.on('Send', function (name, message) {console.log(name + ' ' + message);});
$.connection.hub.start()
.done(function () {
console.log('Now connected, connection ID=' + $.connection.hub.id); // returns an ID
// $.connection.hub.send('testing', 'this is a test from the client');
// contosoChatHubProxy.send("testing");
// contosoChatHubProxy.invoke('testing', 'this is a test for the client 1');
// contosoChatHubProxy.invoke('say', 'this is a test for the client 2');
// contosoChatHubProxy.invoke('Send', 'This is a test for client 3');
// $.connection.hub.send('testing', 'this is a test from the client 4');
contosoChatHubProxy.invoke('messagePump', 'user', 'this is a test message for 5');
})
.fail(function(){ console.log('Could not Connect!'); });
This is what i am seeing in firebug
From what i can make of the code, the proxy appears to be loading locally, and not even seeing the remote system hub...
My console application(s) that only connect to the remote system hub are able to send and receive messages.
btw - i have tried upper can lower case (MessagePump, messagePump)
but it has not changed the result.
var connection = $.hubConnection('http://xxxxxxxxx.azurewebsites.net/');
You are trying to connect a different website. This http://xxxxxxxxx.azurewebsites.net/ should let cross domain requests.Otherwise you can't connect. If you can manage http://xxxxxxxxx.azurewebsites.net/, you should configure signalr like:
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Branch the pipeline here for requests that start with "/signalr"
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);
});
}
}

AuthorizedHandler Blocked wrong request! url: /socket.io/

I'm using mrniko/netty-socketio (Java) to start a websocket server like this:
config = new Configuration();
config.setHostname("localhost");
config.setPort(8001);
server = new SocketIOServer(config);
server.addListeners(serviceClass);
server.start();
Then I'm using (the recommended) socketio/socket.io-client (JavaScript) to try to connect to the websocket server like this (all on the same server):
var socket = io("http://localhost:8001");
The connection is "blocked" at the server with the server printing:
8239 [nioEventLoopGroup-5-1] WARN com.corundumstudio.socketio.handler.AuthorizeHandler - Blocked wrong request! url: /socket.io/, ip: /127.0.0.1:48915
28889 [nioEventLoopGroup-5-2] WARN com.corundumstudio.socketio.handler.AuthorizeHandler - Blocked wrong request! url: /socket.io/, ip: /127.0.0.1:48916
Which occurs endlessly, as the client continues to retry the connection.
I can't seem to get the server to accept the connection. I've tried:
var socket = io("ws://localhost:8001");
But that gives the same outcome. I've also tried putting a trailing slash after the URL for both cases - makes no difference. I've also tried all combinations of using "localhost" or "127.0.0.1" at both the server and client, and so on.
The JavaScript page itself is being served up from a http server on localhost:8000. This does not appear to be a cross site issue as that gives an entirely different error at the browser.
Does anyone know what is going wrong and how to fix it?
In my case network monitoring accesses that port every 10 seconds. I had temporarily changed log4j.properties to ERROR level logging, but wanted to provide networking a path to use that would not cause excessive warn logging. Not sure if this was the best approach, but this is what I ended up doing.
config.setAllowCustomRequests(true);
By allowing custom requests the piece of code displaying the warning was bypassed in Authorizehandler.
I created a custom pipeline, that allowed me to switch out the wrongUrlHandler with a custom one to allow a safe path to use for monitoring.
public class CustomSocketIOChannelInitializer extends SocketIOChannelInitializer {
CustomWrongUrlHandler customWrongUrlHandler = null;
public CustomSocketIOChannelInitializer(Configuration configuration) {
customWrongUrlHandler = new CustomWrongUrlHandler(configuration);
}
protected void initChannel(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
addSslHandler(pipeline);
addSocketioHandlers(pipeline);
// Replace wrong url handler with our custom one to allow network monitoring without logging warnings.
pipeline.replace(SocketIOChannelInitializer.WRONG_URL_HANDLER, "CUSTOM_WRONG_URL_HANDLER", customWrongUrlHandler);
}
This is my custom handler:
#Sharable
public class CustomWrongUrlHandler extends ChannelInboundHandlerAdapter {
private final Logger log = LoggerFactory.getLogger(getClass());
Configuration configuration = null;
/**
* #param configuration
*/
public CustomWrongUrlHandler(Configuration configuration) {
this.configuration = configuration;
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof FullHttpRequest) {
FullHttpRequest req = (FullHttpRequest) msg;
Channel channel = ctx.channel();
QueryStringDecoder queryDecoder = new QueryStringDecoder(req.getUri());
// Don't log when port is pinged for monitoring. Must use context that starts with /ping.
if (configuration.isAllowCustomRequests() && queryDecoder.path().startsWith("/ping")) {
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.BAD_REQUEST);
channel.writeAndFlush(res).addListener(ChannelFutureListener.CLOSE);
req.release();
//log.info("Blocked wrong request! url: {}, ip: {}", queryDecoder.path(), channel.remoteAddress());
return;
}
// This is the last channel handler in the pipe so if it is not ping then log warning.
HttpResponse res = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.BAD_REQUEST);
ChannelFuture f = channel.writeAndFlush(res);
f.addListener(ChannelFutureListener.CLOSE);
req.release();
log.warn("Blocked wrong socket.io-context request! url: {}, params: {}, ip: {}", channel.remoteAddress() + " " + queryDecoder.path(), queryDecoder.parameters());
}
}
}
CustomSocketIOChannelInitializer customSocketIOChannelInitializer = new CustomSocketIOChannelInitializer(config);
server.setPipelineFactory(customSocketIOChannelInitializer);

Listening websocket in MVC

I'm using MVC 4. I have a js code that needs to communicate with the server with the help of Websockets. I'm using Fleck at the server. I'm creating the socket server in Application_Start event. But when I try the connection from browser console, I get errors like Connection refused.
Here is my global.asax code.
protected void Application_Start()
{
IPAddress ip = null;
if (GetResolvedConnecionIPAddress(out ip)) // Get host ip
{
string Domain = "wss" + System.Uri.SchemeDelimiter + ip + ":" + "8092";
FleckLog.Level = Fleck.LogLevel.Debug;
try
{
if (GetResolvedConnecionIPAddress(out ip))
{
var server = new WebSocketServer(Domain);
server.Start(socket =>
{
LogWriter.Logger.Info("WS: Inside socket server");
socket.OnOpen = () =>
{
LogWriter.Logger.Info("WS: OnOpen socket");
};
socket.OnClose = () =>
{
LogWriter.Logger.Info("WS: OnClose socket");
};
socket.OnMessage = message =>
{
LogWriter.Logger.Info("WS: OnMsg socket");
};
});
}
}
catch (Exception e)
{
throw;
}
}
}
It looks like as soon as the Application_Start method ends, that WebSocketServer is going to get out of scope and eventually garbage collected.
You could, set that object as member in the Global class, and dispose it on the Application_End event for example.
UPDATE:
You are also using the wss schema but not providing any certificate configuration. Please note that IIS and Fleck are two different things, that runs in different ports, and not because you create Fleck into the ASP.NET app means that Fleck is going to infer the SSL/TLS configuration or any configuration at all. Try to set the schema to ws instead and open the page without HTTPS and see if it works.

Categories

Resources