Blazor server hosted display alert if websockets not allowed - websocket

I would like to create a Blazor server hosted. Is there a way to display browser alert or redirect the user to another url, for example were Blazor Wasm is running, if SignalR cannot create a connection due to websockets not being allowed?
Can this be done using c# or Javascript?

You can do this with some Javascript implementing the following logic: Try to connect using Web Sockets, if fails, redirect.
Here is a my own working example in TypeScript:
public startConnection = () => {
this.hubConnection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Debug)
.withUrl('http://localhost:20000/yourHub', signalR.HttpTransportType.WebSockets)
.build();
this.hubConnection
.start()
.then(() => {
console.log('Connected!');
})
.catch(err => {
console.log('Error while starting connection: ' + err));
// do the redirect stuff here...
}
}
If you not familiar with Javascript you can start read the Microsoft Documentation for Javascript client.

Related

CORS issue with an ASP.NET Core Web API using app.UseEndpoints

I create a new project Microsoft Visual 2022 with the template ASP.NET Core 6.0 Web API with use of controllers.
The endpoint is https://localhost:7251/weatherforecast.
I set my program.cs:
string? origins = "_myAllowSpecificOrigins";
builder.Services.AddCors(options =>
{
options.AddPolicy(origins, builder => builder.WithOrigins("https://localhost:7041")
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
app.UseCors(origins);
Then I create a new project Microsoft Visual 2022 with the template Blazor Web Assembly App NET 6.0 without ASP.NET Core Hosted.
I write this basic call:
var client = new HttpClient();
var response = await client.GetFromJsonAsync<WeatherForecast[]>("https://localhost:7251/weatherforecast");
...and it works.
Now, for some project requirements, I have to replace in my API.program.cs
app.MapControllers();
with
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
Then I get an error
fetch is blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource
For info, if the web app is a Client/Server/Shared, there is no problem.
How can I set the communication web app not hosted/API using endpoints?
It turns out I just had to add in the Program.cs of the API
builder.Services.AddControllers();
Not using the default client/server template in my web app makes me skip some behaviors and requires this line.
Maybe it's could be related your response headers. Can you try add this;
app.Use(async (context, next) =>
{
context.Response.OnStarting(() =>
{
context.Response.Headers["Access-Control-Allow-Origin"] = "*";
context.Response.Headers["Access-Control-Allow-Credentials"] = "true";
return Task.CompletedTask;
});
await next();
});

socket.emit not executing inside function in sveltekit

I am having problems with SvelteKit and SocketIO. I'm connecting to a NestJS back-end with a default SocketIO gateway and connecting works fine, but executing a socket.emit inside a function fails to trigger entirely. Not sure if this is SocketIO or SvelteKit related, but executing an emit outside of a function works. Here is my code snippet.
<script>
import io from 'socket.io-client';
let socket = io('http://localhost:5000');
socket.on("connect", () => {
console.log(socket.id);
});
socket.on("messages", (arg) => {
console.log(arg);
});
socket.emit("messages", "executes at load", (err) => {
console.log(err);
});
function onSendMessage() {
console.log('executing function');
socket.emit("messages", "test", (err) => {
console.log(err);
});
}
</script>
<button on:click={onSendMessage}>
Send Message
</button>
In this situation ''executes at load'' is printed to the console because it is emitted and the server sends the response back which the socket.on catches. It also prints the ID of the connection through socket.on("connect"). but it never will print ''test'' if i press the button. Pressing the button does console log the ''executing function''. Tested all functionality on Postman as well and the server works. Executing the function manually directly in the script tag without the button onclick results in the same behaviour of the emit not executing. Anyone has an idea?
After a long time of agony I discovered the problem. I think it has to do with the fact that it was trying to establish an XHR Polling connection on the clientside but not on the SSR side of SvelteKit, and it seems that XHR Polling does not support CORS but websockets do.
All I had to do was specify the transport as ''websocket'' on both the frontend and backend and it works perfectly!

Svelte/Sveltekit and socket.io-client not working in dev (works in preview)

I'm trying to make socket.io-client work in a svelte front end app to talk to an existing API server that already uses socket.io. After a number of challenges, I managed to make this work but I can only get this to work with sveltekit's preview and not in dev mode. Wondered if someone with some knowledge of those could explain why or suggest what I need to do to get it connecting in dev?
svelte 3.34.0
sveltekit next-169
socket.io(-client) 4.2.0
basic code as follows, currently within a file $lib/db.js where I define a few stores that are pulled into the layout for general use..
import { io } from "socket.io-client";
import { browser } from '$app/env';
const initSocket = async () => {
console.log('creating socket...');
let socket = io('http://192.168.1.5:4000', { 'connect timeout': 5000 });
socket.on("connect", () => {
// always works in preview...
console.log('socket created with ID:', socket.id);
});
socket.on("connect_error", (error) => {
// permanently fired in dev...
console.error('Failed to connect', error);
});
socket.on("error", (error) => {
console.error('Error on socket', error);
});
socket.on("foo", data => {
// works in preview when server emits a message of type 'foo'..
console.log("FOO:", data);
});
};
if (browser) {
initSocket();
}
// stores setup and exports omitted..
with svelte-kit preview --host I see the socket creation log message with the socket ID and the same can be seen on the api server where it logs the same ID. The socket works and data is received as expected.
with svelte-kit dev --host however, the log message from socket.on("connect").. is never output and I just see an endless stream of error messages in the browser console from the socket.on("connect_error").. call..
Failed to connect Error: xhr poll error
at XHR.onError (transport.js:31)
at Request.<anonymous> (polling-xhr.js:93)
at Request.Emitter.emit (index.js:145)
at Request.onError (polling-xhr.js:242)
at polling-xhr.js:205
Importantly, there is no attempt to actually contact the server at all. The server never receives a connection request and wireshark/tcpdump confirm that no packet is ever transmitted to 192.168.1.5:4000
Obviously having to rebuild and re-run preview mode on each code change makes development pretty painful, does anyone have insight as to what the issue is here or suggestions on how to proceed?
I've had a similar problem, I solved it by adding this code to svelte.config.js:
const config = {
kit: {
vite: {
resolve: {
alias: {
"xmlhttprequest-ssl": "./node_modules/engine.io-client/lib/xmlhttprequest.js",
},
},
},
},
};
The solution was provided by this comment from the vite issues.

Connect to a sails.js instance via websockets

Is it possible to connect any external application to my sails.js application via WebSockets?
I can use the underlying socket.io embedded in sails.js to talk between the client and server, that's not a problem.
But, I would like to connect another, separate, application to the sails.js server via websockets, and have those two communicate with each other that way, and I am wondering if this is possible?
If so, how can we do this?
Thanks.
Based on SailsJS documentation, we have access to the io object of socket.io, via sails.io.
From that, I just adjusted boostrap.js:
module.exports.bootstrap = function (cb) {
sails.io.on('connection', function (socket) {
socket.on('helloFromClient', function (data) {
console.log('helloFromClient', data);
socket.emit('helloFromServer', {server: 'says hello'});
});
});
cb();
};
Then, in my other nodejs application, which could also be another SailsJS application and I will test that later on, I simply connected and sent a message:
var io = require('socket.io-client');
var socket = io.connect('http://localhost:3000');
socket.emit('helloFromClient', {client: 'says hello'});
socket.on('helloFromServer', function (data) {
console.log('helloFromServer', data);
});
And here are the outputs.
In SailsJS I see:
helloFromClient { client: 'says hello' }
In my client nodejs app I see:
helloFromServer { server: 'says hello' }
So, it seems to be working just fine.

How to use Passport-Facebook login without redirection?

I'm building a phonegap application which will have nodejs at the server side. I wanted to implement login using passport-facebook strategy but their callbacks specify two routes, /successcallback and /failurecallback. Having a single page application, this makes it very confusing to have users redirected to so and so page.
I don't want to serve static files (index.html, login.html) from the server but rather have them on the client and ask the client to make ajax calls. So far, I'm able to make /auth/facebook call as an AJAX request but I can't receive any response on the same request because the login strategy requires the user to be redirected. I'd rather want to send a user_id or name back to the user on successful login or show him the login form (which is also on the www directory in phonegap) on failure. But the redirection and CORS errors are preventing me from doing this. Is there any way I can implement this? I've looked for this since a few weeks now, but no success. I'd really appreciate your help!
PS: I'd rather avoid having to send all html and static content from the node server.
EDIT: Adding login code for better understanding:
app.get('/userpage', utility.isLoggedIn, function(req, res)
{
res.send('User:'+req.user);
});
app.get('/', utility.isLoggedIn, function(req, res)
{
res.redirect('/userpage');
});
app.get('/auth/facebook', passport.authenticate('facebook'));
app.get('/auth/facebook/callback',passport.authenticate('facebook',
{
successRedirect : '/',
failureRedirect : '/login'
}));
app.get('/logout', function(req, res)
{
req.logout();
res.redirect('/login');
});
utility.isLoggedIn:
function isLoggedIn(req, res, next)
{
if (req.isAuthenticated())
return next();
res.redirect('/login');
}
You can't do that with facebook oAuth, but Facebook provides another login solution where you can code your client app to request a token, that you can later validate on the server with passport-facebook-token.
This way you can use the advantages of passport for persistent sessions, without that annoying redirection.
Instead of using the standard redirections offered by passport, you can define your own function which will be executed instead of the redirection. Here's an example of what that code would look like
passport.authenticate('login', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.json({ status:"failed", "error": "Invalid credentials" }); }
// req / res held in closure
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.json({ "status":"success"});
})
})(req, res, next);

Resources