Unable to send message to group in SignalR - signalr

I am using SignalR library. I am running 3 instances of my application and then I add two users to a group named 'Test'. Now when i send message to 'Test' group, the message is not delivered at all.
public class ChatHub : Hub
{
public void send(string name, string message)
{
//This line of code is not working
Clients.Group("test").broadcastMessage(message);
//This is working
//Clients.All.broadcastMessage(name, message);
}
public void JoinGroup(string groupName)
{
Groups.Add(this.Context.ConnectionId, groupName);
}
public void RemoveGroup(string groupName)
{
Groups.Remove(this.Context.ConnectionId, groupName);
}
}
//Client side
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>SignalR Simple Chat</title>
<style type="text/css">
.container {
background-color: #99CCFF;
border: thick solid #808080;
padding: 20px;
margin: 20px;
}
</style>
</head>
<body>
<div class="container">
<input type="text" id="groupName" />
<input type="button" id="joinGroup" value="Join" />
<br />
<input type="text" id="message" />
<input type="button" id="sendmessage" value="Send" />
<input type="hidden" id="displayname" />
<ul id="discussion">
</ul>
</div>
<script type="text/javascript" src="Scripts/jquery-1.6.4.min.js"></script>
<script type="text/javascript" src="Scripts/j`enter code here`query.signalR-1.0.0-rc1.js"></script>
<script type="text/javascript" src="/signalr/hubs"></script>
</body>
<script type="text/javascript">
$(function () {
// Declare a proxy to reference the hub.
var chat = $.connection.chatHub;
// Create a function that the hub can call to broadcast messages.
chat.client.broadcastMessage = function (name, message) {
// Html encode display name and message.
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#discussion').append('<li><strong>' + encodedName
+ '</strong>: ' + encodedMsg + '</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();
});
$('#joinGroup').click(function () {
// Call the Send method on the hub.
chat.server.joinGroup($('#groupName').val());
});
});
});
</script>
</html>

Actually the 'broadcastMessage' on the client was expecting two parameter and i was passing only one parameter while calling 'broadcastMessage' using group.
Changing
'Clients.Group("test").broadcastMessage(message);'
to
'Clients.Group("test").broadcastMessage(name, message);' worked.

Related

SignalR not working : $.connection.client is null or undefined [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
After spending two days getting this working with no success, finally I am asking this question here.
Background: I am trying to use SignalR to send real-time data from my desktop application to all web pages.
What I have is, a console application (this just to get concept working then will move it to active project) that needs to send real time data to a webpage built in asp .net. Both are using .Net 4.
In IE9 it shows me error in debug mode at line "chat.client.broadcastMessage = " saying chat.client is null or undefined.
In firfox, it doesn't show me that error but it's not working/not doing anything and the problem is the same as it's not showing me alert('asking for name'); window so I guess it's not getting there and throwing error before that.
Here's my web page code. This is new separate web site project.
<!DOCTYPE html>
<html>
<head>
<title>SignalR Simple Chat</title>
<style type="text/css">
.container {
background-color: #99CCFF;
border: thick solid #808080;
padding: 20px;
margin: 20px;
}
</style>
</head>
<body>
<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>
<!--Script references. -->
<!--Reference the jQuery library. -->
<script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
<script src="Scripts/jquery.json-2.2.min.js" type="text/javascript"></script>
<script src="Scripts/json2.js" type="text/javascript"></script>
<!--Reference the SignalR library. -->
<script src="Scripts/jquery.signalR-1.0.1.min.js" type="text/javascript"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="signalr/hubs"></script>
<!--Add script to update the page and send messages.-->
<script type="text/javascript">
$(function () {
alert('starting scrip');
// Declare a proxy to reference the hub.
$.connection.hub.url = 'http://<ipaddressORlochost>:8080/chatroom';
alert($.connection.hub);
alert($.connection.hub.url);
var chat = $.connection.chatHub;
// Create a function that the hub can call to broadcast messages.
alert(chat);
chat.client.broadcastMessage = function (name, message) {
// Html encode display name and message.
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#discussion').append('<li><strong>' + encodedName
+ '</strong>: ' + encodedMsg + '</li>');
};
alert('asking for name');
// 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({ jsonp:true}).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();
});
});
});
</script>
</body>
</html>
-------------------------
I have tried removing below line and also adding "/signalr" at the end.
$.connection.hub.url = 'http://:8080/chatroom';
Here's my desktop application (server) code.
class Program
{
static void Main(string[] args)
{
using (WebApplication.Start<Startup>(#"http://<ipaddressORlochost>:8080/chatroom"))
{
while (true)
{
// GlobalHost.ConnectionManager.GetHubContext<ChatHub>().Clients.All.addMessage("dsf","asdfd");
Console.WriteLine("Tags sent :" + DateTime.Now.ToString("HH:mm:ss"));
Thread.Sleep(3000);
}
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HubConfiguration { EnableCrossDomain=true };
app.MapHubs(config);
}
}
public class ChatHub : Hub
{
public void Send(string b,string a)
{
try
{
Clients.All.broadcastMessage(b,a);
}
catch { }
}
}
ANY HELP WOULD BE REALLY APPRECIATED.
Thanks All in advance.
-------------- FOUND THE ANSWER ---------- HAVE EDIT THIS QUESTION AS CANNOT ANSWER MY OWN QUESTION WITHIN 8 HOURS
Hi ALL
Just in case if some one else having same problem. I have found answer/fixed.
THANKS TO Hatake Kakashi
Main issue was that $.connection is now changed to $.hubConnection
Here's what I had to change.
Script in my web page. I have left commented code to show what's been replaced with what.
<script type="text/javascript">
$(function () {
alert('starting scrip');
// Declare a proxy to reference the hub.
// $.connection.hub.url = 'http://localhost:8080/chatroom';
var conn = $.hubConnection('http://localhost:8080/chatroom');
alert($.connection.hub);
alert($.connection.hub.url);
var chat = conn.createHubProxy('chatHub'); //$.connection.chatHub;
// Create a function that the hub can call to broadcast messages.
alert(chat);
// chat.client.broadcastMessage = function (name, message) {
// // Html encode display name and message.
// var encodedName = $('<div />').text(name).html();
// var encodedMsg = $('<div />').text(message).html();
// // Add the message to the page.
// $('#discussion').append('<li><strong>' + encodedName
// + '</strong>: ' + encodedMsg + '</li>');
// };
chat.on('addMessage', function (a, message) {
$('#discussion').append('<li><strong>' + $('<div />').text(a).html()
+ '</strong>: ' + $('<div />').text(message).html() + '</li>');
});
alert('asking for name');
// 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.
conn.logging = true;
// Start the connection
conn.start().done(function () {
alert("Now connected!");
}).fail(function () {
alert("Could not Connect!");
});
// $.connection.hub.start({ jsonp: true }).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();
// });
// });
});
</script>
And on the server side (desktop application), because it's one way only I don't need to anything in my ChatHub
static void Main(string[] args)
{
using (WebApplication.Start<Startup>(#"http://localhost:8080/chatroom"))
{
while (true)
{
GlobalHost.ConnectionManager.GetHubContext<ChatHub>().Clients.All.addMessage("dsf", "Tags sent :" + DateTime.Now.ToString("HH:mm:ss"));
Console.WriteLine("Tags sent :" + DateTime.Now.ToString("HH:mm:ss"));
Thread.Sleep(500);
}
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HubConfiguration { EnableCrossDomain=true };
app.MapHubs(config);
}
}
public class ChatHub : Hub
{
/public void Send(string b, string a)
//{
// try
// {
// Clients.All.addMessage(b, a);
// }
// catch { }
//}
}
Hope this will help others.

asp.net Usercontrol + control value always returns true

I am trying to build a simple animated 'on' & 'off' switch control with an underlying checkbox to store the state whenever the 'switch block' shifts left and right (On and Off), when I import to control to the page which I need to use, the value I get is always True, please advice what am I doing wrong. Thanks.:
ASCX:
<html>
<head>
<title></title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"> </script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js"> </script>
</head>
<body>
<div class="switchcontainer">
<div id="on">On</div>
<div id="off">Off</div>
<div class="block"></div>
</div>
<asp:CheckBox ID="chkSwitch" runat="server" Style="display:none"/>
<script>
$(".block").click(function () {
var $button = $(".block");
if ($button.data("lastMove") == "+=46") {
$('#<%= chkSwitch.ClientID %>').removeAttr('checked'); // --> change check state
$button.animate({
left: '-=46'
});
$button.data("lastMove", '-=46');
} else {
$('#<%= chkSwitch.ClientID %>').attr('checked', 'checked'); // --> change check state
$button.animate({
left: '+=46'
});
$button.data("lastMove", '+=46');
}
});
</script>
</body>
</html>
ASCX.CS
public partial class BoolSwitch : System.Web.UI.UserControl
{
public bool On
{
get { return chkSwitch.Checked; }
}
}
Some page using the usercontrol:
<%# Register TagPrefix="BoolSwitch" TagName="BoolSwitch" Src="/UserControls/BoolSwitch.ascx" %>
<BoolSwitch:BoolSwitch runat="server" ID="boolSwitch_1" />
Code Behind:
protected void Page_Load(object sender, EventArgs e)
{
var x = boolSwitch_1.On; // --> This value is always true;
}

How to consume asp.net webapi with knockout

I am new to knockout and asp.net webapi, but I am trying to learn. I am missing something, as i cannot perform a get(or a post,put...)
here is my webapi method
public string GetAllData()
{
List<Task> llistTask = new List<Task>();
Task lobjTask = new Task();
lobjTask.title = "some title";
lobjTask.isDone = false;
llistTask.Add(lobjTask);
return Newtonsoft.Json.JsonConvert.SerializeObject(llistTask);
}
my knockout code
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="Scripts/knockout-2.2.0.js"></script>
<script src="Scripts/jquery-1.8.2.min.js"></script>
</head>
<body>
<h3>Tasks</h3>
<form data-bind="submit: addTask">
Add task: <input data-bind="value: newTaskText" placeholder="What needs to be done?" />
<button type="submit">Add</button>
</form>
<ul data-bind="foreach: tasks, visible: tasks().length > 0">
<li>
<input type="checkbox" data-bind="checked: isDone" />
<input data-bind="value: title" />
<%-- Delete--%>
</li>
</ul>
You have <b data-bind="text: incompleteTasks().length"> </b> incomplete task(s)
<span data-bind="visible: incompleteTasks().length == 0"> - it's beer time!</span>
<script type="text/javascript">
function Task(data) {
this.title = ko.observable(data.title);
this.isDone = ko.observable(data.isDone);
}
function TaskListViewModel() {
// Data
var self = this;
self.tasks = ko.observableArray([]);
self.newTaskText = ko.observable();
self.incompleteTasks = ko.computed(function () {
return ko.utils.arrayFilter(self.tasks(), function (task) { return !task.isDone() });
});
// Operations
self.addTask = function () {
self.tasks.push(new Task({ title: this.newTaskText() }));
self.newTaskText("");
};
self.removeTask = function (task) { self.tasks.remove(task) };
// Load initial state from server, convert it to Task instances, then populate self.tasks
$.getJSON("http://localhost:51958/api/tasks/GetAllData", function (allData) {
var mappedTasks = $.map(allData, function (item) { return new Task(item) });
self.tasks(mappedTasks);
});
}
ko.applyBindings(new TaskListViewModel());
</script>
</body>
</html>
The output is 39 rows of null data, which doesnt make sense to me. what am i missing?
The problem is in the handling results of the $.getJSON() function. It returns you a string, not a JSON object, and when you do $.map() later you're iterating 39 characters of your string, but not the objects you need.
To fix it you need to parse your string as a JSON:
$.getJSON("http://localhost:51958/api/tasks/GetAllData", function (allData) {
allData = $.parseJSON(allData);
var mappedTasks = $.map(allData, function (item) { return new Task(item) });
self.tasks(mappedTasks);
});
Update:
I was really interested, why do you get a string instead of a real object as you should get in case of $.getJSON() function. And the reason is your WebApi method. As far as it returns a string, WebAPI engine converts it additionally to a JSON string (it doesn't care that you've already done it). As a result you have twice JSONified object and jQuery can't parse it.
All you need to do is to return not a string but a List<Task> in your WebAPI method and not to JSON it:
public List<Task> GetAllData()
{
List<Task> llistTask = new List<Task>();
...
return llistTask;
}
And you can leave your JS code as you had it (no additional parseJSON), because now you'll get a real object.
Try using the ko.mapping plugin. It puts the individual objects in form knockout likes.
code would look like
// initial state from server, convert it to Task instances, then populate self.tasks
$.getJSON("http://localhost:51958/api/tasks/GetAllData", function (allData) {
self.tasks = ko.mapping.fromJSON(allData);
});

How to pass file content into [WebMethod] with jquery uploadify plugin

I would like to pass file content into [WebMethod] with jquery uploadfy plugin
But the Upload method can not be invoked.Can anyone help me out? Thanks in advance!
Index.aspx:
<head runat="server">
<title></title>
<link href="uplodify/uploadify.css" rel="stylesheet" type="text/css" />
<script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script src="uplodify/swfobject.js" type="text/javascript"></script>
<script src="uplodify/jquery.uploadify.v2.1.4.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#file_upload').uploadify({
'uploader': '/uplodify/uploadify.swf',
'script': '/Index.aspx/Upload',
'cancelImg': '/uplodify/cancel.png',
'buttonImg': '/uplodify/browse.jpg',
'sizeLimit': 262144,
'fileExt': '*.jpg',
'fileDesc': '*.jpg',
'folder': '/pic',
'onProgress': function (event, ID, fileObj, data) {
var bytes = Math.round(data.bytesLoaded / 1024);
$('#' + $(event.target).attr('id') + ID).find('.percentage').text(' - ' + bytes + 'KB ');
return false;
},
'onSelect': function (event, ID, fileObj) {
if (parseInt(fileObj.size) > 262144) {
window.alert fileObj.name");
return false;
}
},
'onComplete': fun
});
});
function checkImport() {
if ($.trim($('#file_uploadQueue').html()) == "") {
alert('please select pic!');
return false;
}
else {
jQuery('#file_upload').uploadifyUpload();
return true;
}
}
function fun(event, queueID, fileObj, response, data) {
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<img height="100" width="100" src="nopic.jpg" id="filesUploaded" runat="server" />
<input id="file_upload" name="file_upload" type="file" />
<input id="Button1" type="button" value="uploadfile" onclick="checkImport()" runat="server"
class="ui-corner-all" /><br />
</div>
</form>
</body>
Index.cs:
public partial class Index : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
[WebMethod]
public static string Upload(byte[] FileData)
{
return "";
}
}
In ASP.NET Page methods expect to be invoked using application/json content type. So you could use either a new WebForm or a generic handler to handle the file upload:
$(document).ready(function () {
$('#file_upload').uploadify({
'swf': '<%= ResolveUrl("~/uploadify/uploadify.swf") %>',
'uploader': '<%= ResolveUrl("~/upload.ashx") %>'
});
});
and the generic handler might look like this:
public class Upload : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
HttpPostedFile uploadedFile = context.Request.Files["FileData"];
// TODO: do something with the uploaded file. For example
// you could access its contents using uploadedFile.InputStream
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World");
}
public bool IsReusable
{
get { return true; }
}
}
Also to facilitate debugging use a tool such as Fiddler as it allows you to inspect the HTTP traffic between the client and the web server, showing you potential errors you might have. Also a javascript debugging tool such as FireBug or Chrome developer tools is a must-have.

Is it possible to filter the receivers in SignalR?

I hit the following problem. I'd like to do the following.
When a new client is being connected, group parameter is being sent to the SignalR server's side (in URL or another way).
Then I want to notify only clients from the specific group.
e.g.
I have 3 clients:
1) with group parameter = a
2) with group parameter = a
3) with group parameter = b
I want to notify only clients with group parameter == a.
If I use dynamic field Clients, it'll send a message for all the clients.
Is it possible to filter the receivers somehow?
If you want to send a message all group members, you need to add client in the group. you can define group name or you can let clients select. For example:
<script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
<script src="Scripts/jquery.signalR.js" type="text/javascript"></script>
<script src="signalr/hubs" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
var g = $.connection.groups;
g.send = function (t) {
$("#groups").append(t);
};
$("#btnJoin").click(function () {
g.addGroup($("#gr").val());
});
$("#btnSend").click(function () {
g.sendMessage("a"); //for example a group.
});
$.connection.hub.start();
});
</script>
<select id="gr">
<option value="a">a</option>
<option value="b">b</option>
<option value="c">c</option>
</select>
<div id="groups"></div>
<input id="btnJoin" type="button" value="Join"/>
<input id="btnSend" type="button" value="Send"/>
public class Groups : Hub
{
public void AddGroup(string groupName)
{
GroupManager.AddToGroup(Context.ClientId, groupName);
Clients.send(Context.ClientId + " join " + groupName + " group.<br />");
}
public void SendMessage(string groupName)
{
Clients[groupName].send(groupName + " group - Hello Everybody!");
}
}
The syntax hfor SignalR2 is now as follows
Working with Groups in SignalR
example:
public class ContosoChatHub : Hub
{
public Task JoinRoom(string roomName)
{
return Groups.Add(Context.ConnectionId, roomName);
}
public Task LeaveRoom(string roomName)
{
return Groups.Remove(Context.ConnectionId, roomName);
}
}

Resources