SignalR echo/negotiate not found? - asp.net-mvc

Index.cshtml
#{
ViewBag.Title = "Index";
}
<script src="~/Scripts/jquery.signalR-2.0.0.min.js"></script>
<script>
$(function () {
var connection = $.connection('/echo');
connection.received(function (data) {
$('#messages').append('<li>' + data + '</li>');
});
connection.start().done(function () {
$("#broadcast").click(function () {
connection.send($('#msg').val());
});
});
});
</script>
<input type="text" id="msg" />
<input type="button" id="broadcast" value="broadcast" />
<ul id="messages">
</ul>
startup.cs
using Microsoft.Owin;
using Owin;
using UI;
namespace UI
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
MyConnection.cs
public class MyConnection : PersistentConnection
{
protected override Task OnConnected(IRequest request, string connectionId)
{
return Connection.Send(connectionId, "Welcome!");
}
protected override Task OnReceived(IRequest request, string connectionId, string data)
{
return Connection.Broadcast(data);
}
}
I m new to signalR. When I start the project I get following error:
http://localhost:49820/echo/negotiate?clientProtocol=1.3&_=1383403303981 404 (Not Found)
What is the reason of this and how can I fix it? I cant find any solution about this problem. (.net framework 4.5 and signalR 2.0)

I can not debug your code at the moment, but I think you should consider two possible problems.
1) You missed "$.connection.hub" in your start hub function. And when you call received method from server side to client side, you need to add 'connection.client.received'. It should be like below:
$(function () {
var connection = $.connection('/echo');
connection.client.received(function (data) {
$('#messages').append('<li>' + data + '</li>');
});
$.connection.hub.start().done(function () {
$("#broadcast").click(function () {
connection.send($('#msg').val());
});
});
});
2) You need to map your persistent connection. I believe in signalR 1.x should be something like:
RouteTable.Routes.MapConnection<MyConnection>("echo", "/echo");
But in SignalR 2.0 you need to do the following in your hub Startup class. Below is just an example.
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR<MyConnection>("/echo");
}

Related

Signalr Client Generate error in Cross Domain

Access to XMLHttpRequest at 'https://domainname.com/signalr/negotiate?clientProtocol=2.1&connectionData=%5B%7B%22name%22%3A%22notificationhub%22%7D%5D&_=1654470068390' from origin 'https://domainname.com' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
this is my Hub Api server startup code
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableJavaScriptProxies = true
};
map.RunSignalR(hubConfiguration);
});
this is my hub code
public class NotificationHub : Hub
{
public void Hello(string msg)
{
Clients.All.hello(msg);
}
public void JoinToArea(string name)
{
}
public override Task OnConnected()
{
var id = Context.ConnectionId;
return base.OnConnected();
}
}
this is my client code
<script src="~/Scripts/jquery.signalR-2.4.3.js"></script>
<script src="https://localhost:44312/signalr/hubs"></script>
<script>
$(document).ready(function () {
Connect();
});
var stockTickerHubProxy;
function Connect() {
$.connection.hub.url = 'https://localhost:44312/signalr';
stockTickerHubProxy = $.connection.notificationHub;
stockTickerHubProxy.client.foo = function () { };
stockTickerHubProxy.client.hello = function (msg) {
alert(msg);
}
if (stockTickerHubProxy) {
$.connection.hub.start().done(function () {
console.log("Connected...");
connectionId = $.connection.hub.id;
console.log(connectionId)
stockTickerHubProxy.server.joinToArea("OK");
stockTickerHubProxy.client.hello = function (msg) {
alert(msg);
}
})
.fail(function () {
alert("Can't connect");
})
;
$.connection.hub.disconnected(function () {
console.log("Server disconnected.");
});
$.connection.hub.reconnecting(function () {
console.log("Server reconnecting...");
});
$.connection.hub.reconnected(function () {
console.log("Server reconnected...");
Connect();
});
$.connection.hub.error(function (error) {
console.log('SignalR error: ' + error)
});
}
}
</script>
this work fine on localhost when i give hub api server host domain URL its generate this error. how can i fix this issue .

How to websocket in grails5

I want a grails application in which server sends some message at a fixed interval.
I have tried using spring-websocket plugin in grails, server and client are able to connect but that doesn't fullfill my requirement. i.e., I want, server sends some message at a fixed interval.
This is the server-side code :
package test
import org.springframework.messaging.handler.annotation.MessageMapping
import org.springframework.messaging.handler.annotation.SendTo
class ExampleController {
def index() { }
// server
#MessageMapping("/hello")
#SendTo("/topic/hello")
protected String hello(String world) {
List<String> list = new ArrayList<>();
BufferedReader file = new BufferedReader(new FileReader("src/main/resources/dummyLog.txt"));
file.eachLine {line ->
list.add(line)
}
int idx = (int)(Math.random() * list.size());
println idx;
return list.get(idx);
}
}
And this is the client-side code :
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', () => {
var socket = new SockJS("${createLink(uri: '/stomp')}");
var client = webstomp.over(socket);
client.connect({}, function() {
client.subscribe("/topic/hello", (message) => {
document.getElementById('helloDiv').append(message.body);
});
});
document.getElementById('helloButton').addEventListener('click', () => {
client.send("/app/hello", JSON.stringify("world"));
});
});
</script>
Thanks.

mvc signalr how to display all connected users

I need to build a chat using signalr and I am new in this.
So far I got only the chat by reading some others codes and tutorials and this is what I got:
on my ChatApp.Hubs I got the following code
public static class UserHandler
{
public static HashSet<string> ConnectedIds = new HashSet<string>();
}
public class ChatHub : Hub
{
public void Send(string name, string message)
{
// Call the addNewMessageToPage method to update clients.
Clients.All.addNewMessageToPage(name, message);
}
public override Task OnConnected()
{
UserHandler.ConnectedIds.Add(Context.ConnectionId);
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
UserHandler.ConnectedIds.Remove(Context.ConnectionId);
return base.OnDisconnected(stopCalled);
}
}
and my view I copy past from a tutorial
#{
ViewBag.Title = "Chat";
}
<h2>Chat</h2>
<div class="container">
<input type="text" id="message" />
<input type="button" id="sendmessage" value="Send" />
<input type="hidden" id="displayname" />
<ul id="discussion">
</ul>
</div>
#section scripts {
<!--Script references. -->
<!--The jQuery library is required and is referenced by default in _Layout.cshtml. -->
<!--Reference the SignalR library. -->
<script src="~/Scripts/jquery.signalR-2.1.0.min.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="~/signalr/hubs"></script>
<!--SignalR script to update the chat page and send messages.-->
<script>
$(function () {
// Reference the auto-generated proxy for the hub.
var chat = $.connection.chatHub;
// Create a function that the hub can call back to display messages.
chat.client.addNewMessageToPage = function (name, message) {
// Add the message to the page.
$('#discussion').append('<li><strong>' + htmlEncode(name)
+ '</strong>: ' + htmlEncode(message) + '</li>');
};
// Get the user name and store it to prepend to messages.
$('#displayname').val(prompt('Enter your name:', ''));
// Set initial focus to message input box.
$('#message').focus();
// Start the connection.
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
// Call the Send method on the hub.
chat.server.send($('#displayname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
});
});
// This optional function html-encodes messages for display in the page.
function htmlEncode(value) {
var encodedValue = $('<div />').text(value).html();
return encodedValue;
}
</script>
}
what I need now is to display all the connected users in the view
Appriciate your help
Thanks in advance
So, you pretty much either want to just store all 'Active' connections in some kind of database/storage or a static hashset/dictionary.
You save the ConnectionIds when the user connects and remove them when they disconnect :
Hub
public class ChatHub : Hub
{
static HashSet<string> CurrentConnections = new HashSet<string>();
public override Task OnConnected()
{
var id = Context.ConnectionId;
CurrentConnections.Add(id);
return base.OnConnected();
}
public override System.Threading.Tasks.Task OnDisconnected()
{
var connection = CurrentConnections.FirstOrDefault(x => x == Context.ConnectionId);
if (connection != null)
{
CurrentConnections.Remove(connection);
}
return base.OnDisconnected();
}
//return list of all active connections
public List<string> GetAllActiveConnections()
{
return CurrentConnections.ToList();
}
}
Client
I added a button and an unordered list.
HTML
<button id="show-all-connections">Show Connections</button>
<ul id="user-list">
</ul>
And added this javascript (using jQuery)
$("#show-all-connections").on("click", function () {
debugger;
chatHub.server.getAllActiveConnections().done(function (connections) {
$.map(connections, function (item) {
$("#user-list").append("<li>Connection ID : " + item + "</li>");
});
});
});
Hope this helps.
Update
In your scenario, I don't see any hooks into using a custom UserId Provider or anything, so you're going to have to ask the User for a User Name and save the Connection ID with that.
HTML
JavaScript
$("#add-connection").click(function () {
var name = $("#user-name").val();
if (name.length > 0) {
chatHub.server.connect(name);
}
else {
alert("Please enter your user name");
}
});
Hub
static List<Users> SignalRUsers = new List<Users>();
public void Connect(string userName)
{
var id = Context.ConnectionId;
if (SignalRUsers .Count(x => x.ConnectionId == id) == 0)
{
SignalRUsers .Add(new Users{ ConnectionId = id, UserName = userName });
}
}
public override System.Threading.Tasks.Task OnDisconnected()
{
var item = SignalRUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);
if (item != null)
{
SignalRUsers.Remove(item);
}
return base.OnDisconnected();
}
Users.cs
public class Users
{
public string ConnectionId { get; set; }
public string UserName { get; set; }
}
This is psuedo code since I am not able to run this code at the moment. Hope it helps and gives you a clear enough direction.

grails javax.websocket issues

Grails 2.3.7 - Java 1.7
I have seen the following example used in core java and working as a demo, trying to achieve the same in Grails, I know there are a few plugins around websockets but I was trying to figure this out on my own :
Controller 1
package chat
class TestController {
def index() { }
}
index.gsp
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main">
<g:set var="entityName" value="${message(code: 'admin.label', default: 'Admin')}" />
<title><g:message code="default.create.label" args="[entityName,BAH,BAH]" /></title>
</head>
<body>
<form>
<input id="textMessage" type="text">
<input type="button" value="send" onClick="sendMessage();">
</form>
<br>
<textarea id="messagesTextarea" rows="10" cols="50">
</textarea>
<script type="text/javascript">
var webSocket=new WebSocket("ws://localhost:8080/chat/testing");
var messagesTextarea=document.getElementById("messagesTextarea");
var textMessage=document.getElementById("textMessage");
webSocket.onopen=function(message) {processOpen(message);};
webSocket.onmessage=function(message) {processMessage(message);};
webSocket.onclose=function(message) {processClose(message);};
webSocket.onerror=function(message) {processError(message);};
function processOpen(message) {
messagesTextarea.value +=" Server Connect.... "+"\n";
}
function processMessage(message) {
messagesTextarea.value +=" Receive from Server ===> "+ message.data +"\n";
}
function sendMessage() {
if (textMssage.value!="close") {
webSocket.send(textMessage.value);
messagesTextarea.value +=" Send to Server ===> "+ textMessage.value +"\n";
textMessage.value="";
}else {
websocket.close();
}
}
function processClose(message) {
webSocket.send("Client disconnected......");
messagesTextarea.value +="Server Disconnected... "+"\n";
}
function processError(message) {
messagesTextarea.value +=" Error.... \n";
}
</script>
</body>
</html>
Controller 2:
package chat
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/testing")
class TestingController {
#OnOpen
public void handleOpen() {
System.out.println("Client is now connected.");
}
#OnMessage
public String handleMessage(String message) {
System.out.println("Client sent: " + message);
String replyMessage = "echo "+message;
System.out.println("Send to Client: " + replyMessage);
return replyMessage;
}
#OnClose
public void handeClose() {
System.out.println("Client is now disconnected.");
}
#OnError
public void handleError(Throwable t) {
t.printStackTrace();
}
}
With this as is when I run app
I get the following error in chrome:
WebSocket connection to 'ws://localhost:8080/chat/testing' failed: Error during WebSocket handshake: Unexpected response code: 404 index:37
WebSocket is already in CLOSING or CLOSED state.
and in textArea
Error....
Server Disconnected...
on ggts console I see:
Client sent: null
Send to Client: echo null
Initially I attempted controller this way:
package chat
class TestingController extends TestingEndpoint {
}
and in src/java/chat
package chat;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/testing")
class TestingEndpoint {
#OnOpen
public void handleOpen() {
System.out.println("Client is now connected.");
}
#OnMessage
public String handleMessage(String message) {
System.out.println("Client sent: " + message);
String replyMessage = "echo "+message;
System.out.println("Send to Client: " + replyMessage);
return replyMessage;
}
#OnClose
public void handeClose() {
System.out.println("Client is now disconnected.");
}
#OnError
public void handleError(Throwable t) {
t.printStackTrace();
}
}
This method produced same result except nothing in ggts console
Wondering if anyone has got javax.websocket to work in Grails..
ok got it working - was not that bad after all
here is the fix:
a few typos in the gsp :
index.gsp
<!DOCTYPE html>
<html>
<head>
<meta name="layout" content="main">
<g:set var="entityName" value="${message(code: 'admin.label', default: 'Admin')}" />
<title><g:message code="default.create.label" args="[entityName,BAH,BAH]" /></title>
</head>
<body>
<form>
<input id="textMessage" type="text">
<input type="button" value="send" onClick="sendMessage();">
</form>
<br>
<textarea id="messagesTextarea" rows="10" cols="50">
</textarea>
<script type="text/javascript">
var webSocket=new WebSocket("ws://localhost:8080/chat/annotated");
var messagesTextarea=document.getElementById("messagesTextarea");
webSocket.onopen=function(message) {processOpen(message);};
webSocket.onmessage=function(message) {processMessage(message);};
webSocket.onclose=function(message) {processClose(message);};
webSocket.onerror=function(message) {processError(message);};
function processOpen(message) {
messagesTextarea.value +=" Server Connect.... "+"\n";
}
function processMessage(message) {
messagesTextarea.value +=" Receive from Server ===> "+ message.data +"\n";
}
function sendMessage() {
if (textMessage.value!="close") {
webSocket.send(textMessage.value);
messagesTextarea.value +=" Send to Server ===> "+ textMessage.value +"\n";
textMessage.value="";
}else {
websocket.close();
}
}
function processClose(message) {
webSocket.send("Client disconnected......");
messagesTextarea.value +="Server Disconnected... "+"\n";
}
function processError(message) {
messagesTextarea.value +=" Error.... \n";
}
</script>
</body>
</html>
Now the actual fix for the end point, I stumbled across it from here:
https://tyrus.java.net/documentation/1.7/index/deployment.html
Example 3.2. Deployment of Annotated Endpoint Using ServerContainer
So the fix was to add a src/java/MyServletContextListenerAnnotated.java
package chat;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.websocket.DeploymentException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpoint;
#WebListener
#ServerEndpoint("/annotated")
public class MyServletContextListenerAnnotated implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
final ServerContainer serverContainer = (ServerContainer) servletContextEvent.getServletContext()
.getAttribute("javax.websocket.server.ServerContainer");
try {
serverContainer.addEndpoint(MyServletContextListenerAnnotated.class);
} catch (DeploymentException e) {
e.printStackTrace();
}
}
/* #OnMessage
public String onMessage(String message) {
return message;
}
*/
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
}
#OnOpen
public void handleOpen() {
System.out.println("Client is now connected.");
}
#OnMessage
public String handleMessage(String message) {
System.out.println("Client sent: " + message);
String replyMessage = "echo "+message;
System.out.println("Send to Client: " + replyMessage);
return replyMessage;
}
#OnClose
public void handeClose() {
System.out.println("Client is now disconnected.");
}
#OnError
public void handleError(Throwable t) {
t.printStackTrace();
}
}
Since the endpoint in gsp already updated to use new endpoint the final touch was to add _Events.groovy to scripts:
import groovy.xml.StreamingMarkupBuilder
eventWebXmlEnd = {String tmpfile ->
def root = new XmlSlurper().parse(webXmlFile)
root.appendNode {
'listener' {
'listener-class' (
'chat.MyServletContextListenerAnnotated'
)
}
}
webXmlFile.text = new StreamingMarkupBuilder().bind {
mkp.declareNamespace(
"": "http://java.sun.com/xml/ns/javaee")
mkp.yield(root)
}
}
and booom there it is - server connected client send blah

signalr client 400 bad request

I used signalr self hosting with MVC and need to call it from client on another machine so I wrote code like that:
$(function () {
jQuery.support.cors = true;
$.connection.hub.url = "http://[server external Ip]:3031/signalr";
var chat = $.connection.CustomHub;
chat.client.addMessage = function (data, IMEI) {
//SomeCode
}
}
Everything going well but I have this error in Firefox Firebug:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http:// [server external IP]/signalr/negotiate?connectionData=%5B%7B%22name%22%3A%22customhub%22%7D%5D&clientProtocol=1.3&_=1400692033406. This can be fixed by moving the resource to the same domain or enabling CORS.
You have to enable Cross-Domain on the server application by installing Microsoft.Owin.Cors package and the calling UseCors() when starting up SignalR (assuming you are using SignalR 2.x). You do NOT need to specify jQuery.support.cors = true; in SignalR 2.0, actually you should remove it AFAIK.
It seems that the error refer to the network connection, we have already used signalR and the identification of the Url to hub is not mandatory.
Below an implementation of SignalR for Sales object:
1- Enable the service broker on the Database SQL Server:
ALTER DATABASE BlogDemos SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE ;
2- Install signalR from nuget
Install-Package Microsoft.AspNet.SignalR
3- Add reference to signalr javascript library if not added via nuget
<script src="/Scripts/jquery.signalR-2.2.1.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="/signalr/hubs"></script>
4- Add Javascript to call the Hub
$(function () {
// Declare a proxy to reference the hub.
var salesNotificationsHub = $.connection.salesHub;
// Create a function that the hub can call to broadcast messages.
salesNotificationsHub.client.updateClientsales = function () {
Search();
//alert('des nouveaux sales');
};
// Start the connection.
$.connection.hub.start().done(function () {
alert('successful connection');
}).fail(function (e) {
alert(e);
});
});
5- Add the Search function created in step 4
function Search() {
grid.reload({ searchString: searchfields });
}
6- Creation of the code to load the Grid from GetList function in the
Controller
grid = $("#grid").grid({
dataKey: "Codsales",
uiLibrary: "bootstrap",
dataSource:"/sales/GetList",
autoLoad: true,
columns: [
{ field: "Codsales", title: "Code Demande", width: 200, sortable: true },
{ field: "Libelsales", title: "Libellé Demande", width: 200, sortable: true },
],
pager: { enable: true, limit: 10, sizes: [10, 20, 30, 40] }
});
7- Creation GetList function in the controller
public JsonResult GetList()
{
List<salesData> objsalesList = GetList().ToList();
return Json(objGridData, JsonRequestBehavior.AllowGet);
}
8- Create Function GetList Where will be attached the SqlDependency Object
public static List<salesData> GetList()
{
SqlDependency dependency = new SqlDependency();
using (SqlConnection cn = new SqlConnection(connectionString))
{
using (var command = new SqlCommand(#"SELECT Codsales, Libelsales, Datsales,DatDetailledsales FROM [dbo].sales ", cn))
{
command.Notification = null;
dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (cn.State == ConnectionState.Closed)
cn.Open();
command.ExecuteNonQuery();
}
}
List<salesData> objList = new List<salesData>();
objList=Fetchsales(filterExpression, sortExpression, pageIndex, pageSize, out total);
rowsCount = total;
return objList;
}
private static void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
salesHub.Updatesales();
}
}
9- Create Hub class
public class salesHub : Hub
{
[HubMethodName("updatesales")]
public static void Updatesales()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<salesHub>();
context.Clients.All.updateClientsales();
}
}
10- Configuration of the Sqldependency in Global.asax file
protected void Application_Start()
{ //Start SqlDependency with application initialization
string connString= ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
SqlDependency.Start(connString);
}
protected void Application_End()
{
//Stop SQL dependency
string connString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
SqlDependency.Stop(connString);
}
Cordially

Resources