SignalR methods in WebApi controller not called in specific setup - javascript

Well, I have a signalR hub:
public class ReportHub : Hub
{
private static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<ReportHub>();
public void SendMessage(string text)
{
Clients.All.sendMessage(text);
}
public static void ServerSendMessage(string text)
{
hubContext.Clients.All.sendMessage(text);
}
}
Also I have the client code in js, on some view
report.client.sendMessage = message => {
alert('message from server: '+ message);
}
And I have webapi action, like this:
[HttpGet]
[Route("api/Report/test")]
public int GetTest()
{
ReportHub.ServerSendMessage("message");
return 42;
}
When I open the view with signalR-catching js code in one browser, and in another browser window requesting the webapi action, by typing http://../api/report/test - all working, and alert is appearing
But when I calling webapi action via postman, or any other rest client, no effect at all, report.client.sendMessage = message => {
alert('message from server: '+ message);
} - not working
Can anyone help?

ReportHub.ServerSendMessage("message");
It is wrong.
You should return ReportHubContext for the connection before pushing the data to clients;
[HttpGet]
[Route("api/Report/test")]
public int GetTest()
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<ReportHub>();
hubContext.ServerSendMessage("message");
return 42;
}

Related

WebSockets fails to connect because of lost connection

I'm using spring boot in my backend and vuejs in my front-end . I've defined everything in the guide yet I still don't get my project to work.
FrontEnd
connectToWS() {
this.socket = new Sock("http://localhost:8754/stomp-endpoint");
this.stompClient = Stomp.over(this.socket);
this.stompClient.connect(
{},
frame => {
this.connected = true;
console.log(frame);
this.stompClient.subscribe("/topic/greetings", tick => {
console.log(tick);
this.received_messages.push(JSON.parse(tick.body).content);
});
},
error => {
console.log(error);
this.connected = false;
}
);
},
Backend
WebSocketConfiguration Class :
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketConfiguration implements
WebSocketMessageBrokerConfigurer
{
#Override
public void registerStompEndpoints(StompEndpointRegistry registry)
{
// with sockjs
registry.addEndpoint("/stomp-endpoint")
.setAllowedOrigins("http://localhost:8081")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes("/app")
.enableSimpleBroker("/topic");
}
}
WebSecurityConfigClass :
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/api/v*/registration/**").permitAll()
.antMatchers("/topic**").permitAll()
.antMatchers("/stomp-endpoint").permitAll()
UPDATE :
The error is actually coming out from the browser . It actually changes the route of the api because it has sockjs integrated into it. I couldn't figure out why the API always gets a /info?t=RandomNumber after it. I need the route to remain the same as I typed it in the front-end.
How can I stop the browser from updating my path. Thanks for helping !

CORS error with Spring boot, javascript and web socket

I'm working on a little test project with a simple html page (using javascript) as Frontend and a Spring Boot application for my apis as Backend. I use websocket with stomp and sockJS to keep alive my connection between front and back. My problem is the following : when I test my connection with Postman i have no problems but when I call the api from my javascript I have the following error :
I tried every solutions I've found on internet and now i'm just stuck
Here is my Spring boot App_controller :
#RestController
#CrossOrigin(origins = "*")
public class App_Controller {
int id = 0;
ArrayList<Player> players = new ArrayList<Player>();
public void addTab(Player p){
players.add(p);
}
#MessageMapping("/batch-socket")
#SendTo("/topic/messages")
public String send(String message) throws Exception {
String time = new SimpleDateFormat("HH:mm").format(new Date());
return (message + " : " + time);
}
#RequestMapping (value = "/error", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public String error(){
return "erreur";
}
}
Here is my corsConfiguration :
#Configuration
public class CorsConfig {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry){
registry.addMapping("/**")
.allowCredentials(true)
.allowedOrigins("*")
.allowedHeaders("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.maxAge(3600);
}
};
}
}
Here is my WebSocketConfiguration :
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes("/topic")
.enableSimpleBroker("/app");
}
#Override public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/batch-socket");
registry.addEndpoint("/batch-socket")
.setAllowedOrigins("*")
.withSockJS();
}
}
And finally here is my function to connect to this WebSocket :
function connect(){
var socket = new SockJS("http://localhost:8080/batch-socket");
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame){
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/messages', function(msgOutput){
console.log(msgOutput);
})
})
}
I tried to just add the #CrossOrigin(origins="*") and #CrossOrigins(origins="http://localhost:63342") and I test multiple possibilities with my CorsConfig.
Thank you for your help in advance
(sorry for my english)
You didn't say how your HTML page with JS is loaded. Is it the same localhost:8080 or maybe local file?
For testing you can tell Chrome to ignore cors restrictions:
chrome --disable-web-security --user-data-dir={some dir}
In your code you are doing registry.addEndpoint() twice, remove one and replace "*" with "http://localhost:63342". Remove all other CORS related code.
I think that you don’t need to create the #bean WebMvcConfigurer corsConfigurer, if it is for a simple test. Could you please do a test removing the registration of that bean and change the order of the annotations?
#CrossOrigin(origins = "http://localhost:63342")
#RestController

Events not being sent to JavaScript

I am using react-native to develop an android app. I am using native code to run a service in the foreground. This service consists of collections the accelerometer sensor readings of the phone.
Starting the service returns a successful promise but I do not receive no events. The following is the implementation of the service class:
public class PhonePositionService extends Service {
public static final String FOREGROUND = "com.testnative.position.FOREGROUND";
...
//Event listener for sensors -start
SensorEventListener sensorEventListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent event) {
PhonePositionService.this.sendMessage(event);
}
...
};
//Event Listener - end
#Override
#TargetApi(Build.VERSION_CODES.M)
public void onCreate() {
sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE); //get services provided by sensor manager
mAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); //specifiy sensor
sensorManager.registerListener(sensorEventListener, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); //register it
}
private void sendMessage(SensorEvent event) {
try {
float[] values = event.values;
Intent intent = new Intent("PhonePosUpdate");
intent.putExtra("message", values);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
...
The thing is not even a notification appears, I'm afraid the service didnt start at all.
The Following is my Module which uses this service:
public class PhonePositionModule extends ReactContextBaseJavaModule {
public PhonePositionModule(ReactApplicationContext reactContext) {
super(reactContext);
BroadcastReceiver phonePositionReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
float[] message = intent.getFloatArrayExtra("message");
PhonePositionModule.this.sendEvent(message);
}
};
LocalBroadcastManager.getInstance(getReactApplicationContext()).registerReceiver(phonePositionReceiver, new IntentFilter("PhonePosUpdate"));
}
...
#ReactMethod
public void startService(Promise promise) {
String result = "Success";
try {
Intent intent = new Intent(PhonePositionService.FOREGROUND); ///////
intent.setClass(this.getReactApplicationContext(), PhonePositionService.class);
getReactApplicationContext().startService(intent);
} catch (Exception e) {
promise.reject(e);
return;
}
promise.resolve(result);
}
...
private void sendEvent(float[] message) {
WritableMap map = Arguments.createMap();
map.putDouble("x", message[0]);
map.putDouble("y", message[1]);
map.putDouble("z", message[2]);
getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("updatePosition", map);
}
}
When I call startService() from JavaScript, I get a success. However no notification appears and
DeviceEventEmitter.addListener('updatePosition', (Data) => {
console.log(Data);
in App.js shows nothing.
Thus:
1) The Notification does not appear
2) Given that the notification does not appear, the service did not start (even though the promise did not return an error).
I tried debugging the native code on Android Studio but logcat isn't working for me.

Notify registered clients using Websockets with AngularJS (angular-websocket-service) and Spring Boot

I am new in AngularJS as well as FullStack development. The architecture of my current app is already set up and should not change preferably (for security reasons). So far, I can emit messages to the server using angular-websocket-service. Here is the code snippet of the service from the front-end:
proxiMiamApp.service('WebSocketService', function ($websocket) {
var wsEndpoint = {};
this.openWsEndpoint = function () {
wsEndpoint = $websocket.connect("ws://localhost:9000/proximiamHandler");
console.log(wsEndpoint);
return wsEndpoint;
}
this.sendMessage = function(){
if($.isEmptyObject(this.wsEndpoint)){
this.openWsEndpoint();
}
eventUser = {
idEvent : '1',
idUser : '49'
};
wsEndpoint.register('/eventUser', function(){
console.log('Register OK!');
});
console.log('Ready!');
wsEndpoint.emit('/eventUser',eventUser);
}});
As for the back-end, I am using an implementation of the WebSocketHandler interface:
#Controller
public class ProximiamHandler implements WebSocketHandler {
#Override
public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {
System.out.println("afterConntectionEstablished called");
}
#Override
public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
System.out.println("handleMessage called");
// My code here...
}
#Override
public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
System.out.println("handleTransportError called");
}
#Override
public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
System.out.println("afterConnectionClosed called");
}
#Override
public boolean supportsPartialMessages() {
return true;
}}
The Implementation of the WebSocketHandler is called via Spring WebSocketConfigurer
#Configuration
#EnableWebSocket
#Controller
public class WebSocketConfig implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/proximiamHandler").setAllowedOrigins("*");
}
#Bean
public WebSocketHandler myHandler() {
return new ProximiamHandler();
}}
My questions are:
Can I notify subscribed clients using this architecture?
If yes, how can I do it?
Is there a way to return something to subscribed clients from the server? (an Object or a String for instance)
Thanks in advance for your help
Can I notify subscribed clients using this architecture?
=> Yes.
If yes, how can I do it?
=> Based on the Spring web socket APIs, you have to retain the ' WebSocketSession' passed to you via "afterConnectionEstablished" callback.
Use the sendMessage() API of Web socket session to send notifications to client.
Is there a way to return something to subscribed clients from the server? (an Object or a String for instance)
=> You can format your data in either JSON or XML & wrap it using "WebSocketMessage" and pass it to client.
I never worked on spring, however, I am answering this based on my knowledge on web socket. See if it helps.

SignalR Get Clients outside of Hub not working

I am trying to call signalR from a controller, but it doesnt work.
Controller:
public ActionResult Index(){
var hub = GlobalHost.ConnectionManager.GetHubContext<ClientControl>();
hub.Clients.All.sendMessage("ahahhaaa");
//... return and staff
}
Hub
[Authorize]
[HubName("userTracking")]
public class ClientControl : Hub
{
public void RegisterConnection(String controller, String action)
{
}
public override Task OnConnected()
{
}
public override Task OnDisconnected()
{
return base.OnDisconnected();
}
}
Frontend:
$(document).ready(function () {
var trackhub = $.connection.userTracking;
trackhub.client.sendMessage = function (msg) {
alert(msg);
}
$.connection.hub.logging = true;
$.connection.hub.start();
});
In the controller it doesnt throw an error. When I debug and pause it, hub object exists, but when I perform it, it sends no message to the frontend. If I call the same method from the hub - works as a charm.
Any idea, what can be the root cause of the problem? If needed - write in the comments I will provide more info.
Server
public class ChatHub : Hub
{
public int TryAddNewUser(string userName)
{
//some logic...
Clients.All.AddUserToUserList(id, userName);
return id;
}
public void AddNewMessageToPage(int id, string message)
{
//some logic...
Clients.All.addNewMessageToPage(u.Login, message);
}
}
Client
$(document).ready(function () {
//first need register client methods
var chat = $.connection.chatHub;
chat.client.addUserToUserList = function (id, login) {
//client logic for add new user
}
chat.client.addNewMessageToPage = function (login, message) {
//client logic for add new message from user
}
//second need start chat
$.connection.hub.start().done(function () {
chat.server.tryAddNewUser(login).done(function (id) {
alert("Added " + id)
});
});
});
Controller
public class ChatController : Controller
{
private IMyDataService _service;
public ChatController(IMyDataService s)
{
_service = s;
}
public ActionResult Index()
{
return View(new MyDataViewModel(_service));
}
}
Note, dynamic js file must be added with the same path
<script type="text/javascript" src="~/signalr/hubs"></script>
And i add following code to Startup.cs
using Owin;
using Microsoft.Owin;
[assembly: OwinStartup(typeof(ChatRoom.Startup))]
namespace ChatRoom
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Any connection or hub wire up and configuration should go here
app.MapSignalR();
}
}
}
About this see link
Please change the hub name in controller to work
Use
var hub = GlobalHost.ConnectionManager.GetHubContext<UserTracking>();
hub.Clients.All.sendMessage("ahahhaaa");
Instead of
var hub = GlobalHost.ConnectionManager.GetHubContext<ClientControl>();
hub.Clients.All.sendMessage("ahahhaaa");
Please note the change in Hub Class Name in GetHubContext<>.
Hope this helps.

Categories

Resources