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('<a href="' + url + '">Download result file here</a>');
});
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...