I created a server with SignalR and SQLTableDependency. After that, I created a project with Vue and SignalR Javascript Client and everything works, the notification subscription in the server execute a SignalR method to send the object to all the Clients
private void Changed(object sender, RecordChangedEventArgs<Todo> eventArgs)
{
if(eventArgs.ChangeType != TableDependency.SqlClient.Base.Enums.ChangeType.None)
{
var changedEntity = eventArgs.Entity;
var mensaje = TipoCambios(eventArgs);
_hubContext.Clients.All.SendAsync("RegistrarTarea", changedEntity);
}
}
In JavaScript Client I made this:
coneccionTodo.on("RegistrarTarea", todos => {
this.$refs.alerta.Abrir(todos.cambio, "info", "Alerta");
console.log(todos);
});
coneccionTodo
.start()
.then(response => {
this.sinConexion = false;
})
.catch(error => {
console.log("Error Todo SignalR", error.toString());
});
The result of that is this:
And finally my C# Client made with .Net Core 2.1. This is not working
public static async Task Ejecutar() {
connection.On<List<dynamic>>("RegistrarTarea", (objects) => {
Console.WriteLine(objects);
});
try
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"Conexión exitosa a {url}");
await connection.StartAsync();
//await connection.InvokeAsync("RegistrarTarea", "Consola", true);
}
catch (Exception ex)
{
SignalR_Exception(ex);
}
}
In void main Console app I call the Ejecutar method:
connection = new HubConnectionBuilder().WithUrl(url).Build();
connection.Closed += async (error) => {
await Task.Delay(new Random().Next(0, 5) * 1000);
await connection.StartAsync();
};
Task.Run(() => Ejecutar());
Console.ReadLine();
NOTE: In the server, the CORS are activated to allow anything.
Are you using Direct mode ? The direct mode does not function with this. Turn the Direct mode off.
Ok, in connection.on I use a List, but instead of that, I used a Class with the properties like the server send. So now, it's working:
connection.On<Result>("RegistrarTarea", (result) => {
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine(result.Cambio);
});
Related
In Spring Boot, when we try to send a Server Sent Event, it only sends an error event containing data: {"timeout":-1} when we try to connect, and the connection closes. The Spring Boot class is as follows
#RestController
#CrossOrigin(origins = "*")
public class SsePushNotificationRestController {
private static final Logger log = LoggerFactory.getLogger(SsePushNotificationRestController.class);
private SseEmitter emitter;
#GetMapping("/test")
public String getString(){
try {
emitter.send("User connected");
log.info("User connected");
emitter.complete();
} catch (Exception e) {
log.info("Error while sending message to client: " + e.getMessage());
}
return "placeholder";
}
#GetMapping("/emitter")
public SseEmitter eventEmitter(#RequestParam String userId) {
emitter = new SseEmitter(-1L);
return emitter;
}
}
And our client code is as follows:
const eventSource = new EventSource('http://localhost:8080/emitter?userId=testUser');
eventSource.addEventListener("message", (event) => {
console.log(event);
});
eventSource.addEventListener("open", (event) => {
console.log("connection opened");
});
eventSource.addEventListener("error", (e) => {
if (e.readyState === EventSource.CLOSED) {
console.log('closed');
}
else {
console.log(e);
}
e.target.close();
});
document.getElementById("btn").onclick = e => {
fetch('http://localhost:8080/test').then( data => console.log(data)).catch(data => console.log(data));
};
Immediately, an error is created before we can click the button to generate an event.
What could be wrong?
What does your Spring boot terminal say? I think I need that information to address your program's error. By the way allowing cross origin resources sharing for requests from any sources (using wildcard) is a very very bad practice.
One possible reason of error is something's wrong when you create an instance of SSEemitter. (new SSeEmitter(-1L))
SSeEmitter(Long timeout) is creating server side event with set timeout it says. So if timeout is -1, I guess it would immediately be timed out and return timeout response. So it wouldn't be error, just working as written
I'm adding the claim to a user's profile that he or she paid for something, though, after the payment this attribute isn't visible. I'm running the functions on an emulator on a local host.
This is the code I'm using:
If the paypal function has been handled succesfully through paypalHandleOrder, then the function addPaidClaim is invoked.
onApprove: (data, actions) => {
paypalHandleOrder({ orderId: data.orderID }).then(
addPaidClaim(currentUser).then(
alert("THANKS FOR ORDERING!"),
// currentUser.getIdTokenResult().then(idTokenResult => {
// console.log(idTokenResult.claims)
// })
)
.catch((err) => {
return err;
})
);}
addPaidClaim is a firebase cloud function, which goes as follows:
exports.addPaidClaim = functions.https.onCall((data, context) => {
// get user and add custom claim (paid)
return admin.auth().setCustomUserClaims(data.uid, {
paid: true,
}).then(() => {
return {
message: `Success! ${data.email} has paid the course`,
};
}).catch((err) => {
return err;
});
});
I've refreshed the page and checked the user attributes afterwards through console.log on the user to see if the attribute had been added, but this is not the case. I can't find attribute paid inside the idTokenResult object. What should I do? I also find it hard to make sense of what's happening inside the function addPaidClaim. It's not returning an error when I look at the logs on my firebase console, and not much information is given, besides that the function has been invoked.
Okay, I know this question is pretty old. But I found a way just yesterday after 3 days searching over the solution. After we set up a new claim for a new user using, we need to refresh the client's getIdTokenResult(true) in the app. These are the ways I did it in Flutter Dart until a new user with updated claim managed to use it:
FirebaseAuth auth = FirebaseAuth.instance;
Future<Map<String, dynamic>> signInWithGoogle() async {
Map<String, dynamic> output = {};
final googleUser = await googleSignIn.signIn();
if (googleUser == null) {
log("Firebase => Gmail account doesn't exist");
} else {
final googleAuth = await googleUser.authentication;
final credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken,
accessToken: googleAuth.accessToken,
);
await auth.signInWithCredential(credential).then((values) async {
await userAuth(credential).then((value) =>
value.addAll(output));
});
}
return output;
}
Future<Map<String, dynamic> userAuth (OAuthCredential credential) async {
Map<String, dynamic> output = {};
await auth.currentUser!.reauthenticateWithCredential(credential);
await auth.currentUser!.reload();
await auth.currentUser!.getIdTokenResult().then((result) => {
if(result.claims!.isNotEmpty){
//check your claim here
} else {
//assign log here
}
});
return output;
}
This is my controller
public IActionResult Privacy(int? id)
{
if(id.HasValue)
throw new Exception("privacy page exception");
return View(); ///working- redirected to Error view
}
[HttpGet]
public async Task<IActionResult> SearchCustomerPartial([FromQuery] CustomerSearch searchModel)
{
try {
var result = await _customerapiService.SearchCustomer(searchModel);
return PartialView("_CustomerList", result.Data);
}
catch ( Exception e)
{
return RedirectToAction("Index", "Error"); ---Not working it remains in same controller
}
}
Global exception handler
public static void UseGlobalExceptionHandler(this IApplicationBuilder app
, ILogger logger
, string errorPagePath
, bool respondWithJsonErrorDetails = false)
{
app.UseExceptionHandler(appBuilder =>
{
appBuilder.Run(async context =>
{
//============================================================
//Log Exception
//============================================================
var exception = context.Features.Get<IExceptionHandlerFeature>().Error;
string errorDetails = $#"{exception.Message}
{Environment.NewLine}
{exception.StackTrace}";
int statusCode = (int)HttpStatusCode.InternalServerError;
context.Response.StatusCode = statusCode;
//Check status code, if different redirect error page
context.Response.Redirect(errorPagePath); --- Redirect code
await Task.CompletedTask;
});
});
}
Problem:
I have 2 Methods Privacy() and SearchCustomerPartial() in controller.
My global exception handler working fine for Privacy it redirect to Error view when error.
But not not working for SearchCustomerPartial() (returns partial view)
if any exceptions in the SearchCustomerPartial() not redirected to Error view and showing Error in same page and overlap.
Below is the Error page
How to redirect to Error page in the partial view returns in the controller .. Am using Asp.net core 3.1
Kindly suggest..
EDIT:
My javascript Code
fetch(url + "?" + o)
.then(response => response.text())
.then(html => {
debugger
// console.log(html);
document.getElementById('partialresult').innerHTML = html;
})
.catch(err => {
debugger
console.log("Can’t access " + url + " response. Blocked by browser?" + err)
document.getElementById('partialresult').innerHTML = "";
});
Server returns 500 But it not coming under Catch in javscript..Kindly suggest
if Bad Request come from server how to handle in javascript
if any exceptions in the SearchCustomerPartial() not redirected to Error view and showing Error in same page and overlap.
Based on your code and requirement, you can try to modify the code like below.
fetch(url + "?" + o)
.then(function (response) {
//check if it is redirected to custom error page
if (response.redirected && response.url.indexOf("/Home/Error1")>0) {
response.text().then(function (html) {
document.write(html);
});
} else {
response.text().then(function (html) {
document.getElementById('partialresult').innerHTML = html;
});
}
})
I am trying to open url using using this package. It works locally, but if I try to use the same thing on my deployed app, it is not working, it just skip that part, or it looks like that because it returns a message, but it is not opening url. Is there something that should be configured on server for this?
For example, I am trying to do this
const authorizeUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
});
try {
opn(authorizeUrl, { wait: true }).then(cp => {
console.log('cp', cp)
const server = http
.createServer(async (req, res) => {
try {
if (req.url.indexOf('/callback') > -1) {
const qs = new url.URL(req.url, `${process.env.SERVER_API_URL}`)
.searchParams;
res.end(
'Authentication successful! Please return to the console.'
);
server.destroy();
const { tokens } = await oauth2Client.getToken(qs.get('code'));
oauth2Client.credentials = tokens;
resolve(oAuth2Client);
}
} catch (e) {
reject(e);
}
})
});
return res.send({ msg: 'okay' })
and it works locally, but on deployed app it just returns 'ok'. If I use callback or something else to return message, it just block and causes timeout.
I've started learning Golang after writing in Node.js for a long time and I'm a bit curious as to how am I to implement a handler - I've opted to use Gorilla Websocket since I understood it's the most reliable package out there.
In socket.io for example you have the simple socket.on function that allows me to call a function based on the "name" parameter passed in JSON.
Gorilla websocket doesn't implement such a thing, so my question is am I to sort of implement the logic behind socket.io in order to achieve what I want ?
As in do a certain procedure based on the value transferred in the websocket ?
If so - I need to implement it both client (I'm using AngularJS on the front-end) and server side separately by my own - make a switch case statement based on a value I get in JSON both in AngularJS for the front-end and in Go for the back-end, and also - is that the most efficient way ?
Thanks !
If you've been using Javascript for a while it is really easy to implement your own version of socket.on and socket.emit here is one I made for my own projects but you can have it if you need,
// e.g.
// let socket = new Socket("ws://w/e");
// socket.on('connected', () => { console.log('Connected'); });
// socket.emit('lobby join', { data: { username: 'Boo' } });
// Using ES2015 with Babel
import {EventEmitter} from 'events';
class Socket {
constructor(wsurl, ee = new EventEmitter()) {
let ws = new WebSocket(wsurl);
this.ee = ee;
this.ws = ws;
ws.onmessage = this.message.bind(this);
ws.onopen = this.open.bind(this);
ws.onclose = this.close.bind(this);
}
on(name, fn) {
this.ee.on(name, fn);
}
off(name, fn) {
this.ee.removeListener(name, fn);
}
emit(name, data) {
const message = JSON.stringify({name, data});
this.ws.send(message);
}
message(e) {
try {
const msgData = JSON.parse(e.data);
this.ee.emit(msgData.name, msgData.data);
}
catch(err) {
let error = {
message: err
}
console.log(err)
this.ee.emit(error.message)
}
}
open() {
this.ee.emit('connected');
}
close() {
this.ee.emit('disconnected');
}
}
export default Socket
This will let you use your common socket.on('event', fn); and what not
As for handling it on the servers end:
For receiving messages, I personally just make a switch statement that will match an incoming string to a function, e.g.:
// readPump pumps messages from the websocket connection to the hub.
func (c *connection) readPump() {
defer c.ws.Close()
for {
_, message, err := c.ws.ReadMessage()
if err != nil {
break
}
var incMessage interface{}
err = json.Unmarshal(message, &incMessage)
if err != nil {
log.Println(err)
}
incMessageMap := incMessage.(map[string]interface{})
switch incMessageMap["name"] {
case "lobby join":
// Do something to handle joining
case "lobby leave":
// Do something to handle leaving
}
}
}
For sending them I have a send channel on my connections that is stored in a map and when I need to emit I have a simple struct that takes a message name, and data, e.g.:
type wsMsg struct {
Name string `json:"name"`
Data map[string]interface{} `json:"data"`
}
c.send <- wsMsg{
"user joined",
map[string]interface{}{
"username": "Booh",
},
}
Then on the client side it would come as
socket.on('user joined', (msg) => {
console.log(msg) // { username: "Booh" }
});
I suggest looking at the examples on gorillas git: https://github.com/gorilla/websocket/tree/master/examples/chat
Here is an working example of golang websocket to stream video
https://github.com/interviewparrot/OpenAVStream
Let me know if it is good enough