I am interested in using SignalR to provide a better user experience for some long-running processes in my application and have just created my first test SignalR project. I created an empty web project and then used NuGet to install the SignalR.Sample package. The StockTicker.html page example works perfectly. I then created my own Hub and test page.
using System.Threading;
using Microsoft.AspNet.SignalR.Hubs;
namespace SignalR.Test
{
[HubName("testHub")]
public class TestHub : Hub
{
public void LongRunningProcess()
{
Thread.Sleep(1000);
this.Clients.Caller.updateStatus("25% Completed");
Thread.Sleep(1000);
this.Clients.Caller.updateStatus("50% Completed");
Thread.Sleep(1000);
this.Clients.Caller.updateStatus("75% Completed");
Thread.Sleep(1000);
this.Clients.Caller.updateStatus("Done");
}
}
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>SignalR - Long Running Process</title>
</head>
<body>
<h1>Long Running Process</h1>
<p>Status:</p>
<ul id="status">
<li>Loading hub...</li>
</ul>
<script src="/bundles/jquery"></script>
<script src="/Scripts/jquery.signalR-1.0.0-alpha2.js"></script>
<script src="/signalr/hubs"></script>
<script type="text/javascript">
$(function () {
var hub = $.connection.testHub;
hub.updateStatus = function (message) {
$("#status").append("<li>" + message + "</li>");
};
$.connection.hub.start().done(function () {
$("#status").children().first().text("Hub loaded.");
hub.longRunningProcess();
})
.fail(function() {
$("#status").children().first().text("Hub failed");
});
})
</script>
</body>
</html>
When I run the page, I get the following (Firebug) error:
TypeError: hub.longRunningProcess is not a function
hub.longRunningProcess();
If I look in /signalr/hubs I see the following script towards the end of the file:
signalR.testHub = signalR.hub.createHubProxy('testHub');
signalR.testHub.client = { };
signalR.testHub.server = {
longRunningProcess: function () {
return signalR.testHub.invoke.apply(signalR.testHub, $.merge(["LongRunningProcess"], $.makeArray(arguments)));
}
};
Any advice/pointers on where I'm going wrong would be much appreciated.
I found the problem. The client script should looks as follows:
$(function () {
var hub = $.connection.testHub;
hub.client.updateStatus = function (message) {
$("#status").append("<li>" + message + "</li>");
};
$.connection.hub.start().done(function () {
$("#status").children().first().text("Hub loaded.");
hub.server.longRunningProcess();
})
.fail(function() {
$("#status").children().first().text("Hub failed");
});
})
Notice the addition of the .client and .server properties to the hub method declarations, e.g. hub.client.updateStatus() and hub.server.longRunningProcess()
Related
I am very new to the term SignalR . I was try to configure the signalR into my empty website and Added following code.
In App_Code
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(Super.App_Code.Startup))]
namespace Super.App_Code
{
public class Startup
{
public static void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
and the hub class Inside App_Code
namespace Super.App_Code
{
[HubName("toastHub")]
public class ToastHub : Hub
{
public void BroadcastToast(string type ,string msg)
{
Clients.All.sendToast(type , msg);
}
}
}
and in Default.aspx
<head runat="server">
<title></title>
<link rel="stylesheet" href="content/toastr.min.css" />
<script src="Scripts/jquery-1.6.4.js" type="text/javascript"></script>
<script src="Scripts/jquery.signalR-2.4.1.js" type="text/javascript"></script>
<script src="Scripts/toastr.min.js" type="text/javascript"></script>
<script src="signalr/hubs" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#SuccessLink").click(function () {
console.log("Success Click");
$.connection.toastHub.client.broadcastToast('success', 'you have done');
});
$("#ErrorLink").click(function () {
console.log("Error Click");
$.connection.toastHub.client.broadcastToast("error", "you have not done");
});
$.connection.hub.start().done(function () {
console.log('SignalR connected');
})
.fail(function (data) {
console.log('SignalR failed to connect: ' + data);
});
$.connection.toastHub.client.sendToast = function (type, msg) {
console.log("sendToast Called");
toastr[type](msg);
};
});
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<a id="SuccessLink" style="color: lightgreen">Success Toast</a><br />
<a id="ErrorLink" style="color: red">Error Toast</a>
</div>
</form>
</body>
</html>
but when i run my website the javascript console says this when click on one of the tag
SignalR connected
Default.aspx:20 Success Click
Default.aspx:21 Uncaught TypeError: $.connection.toastHub.client.broadcastToast is not a function
at HTMLAnchorElement.<anonymous> (Default.aspx:21)
at HTMLAnchorElement.handle (jquery-1.6.4.js:3001)
at HTMLAnchorElement.eventHandle (jquery-1.6.4.js:2635)
Am i doing anything wrong please help me any help would be greatful .i am totally new to SignalR .
signalr/hub
if (typeof ($.signalR) !== "function") {
throw new Error("SignalR: SignalR is not loaded. Please ensure jquery.signalR-x.js is referenced before ~/signalr/js.");
}
var signalR = $.signalR;
function makeProxyCallback(hub, callback) {
return function () {
// Call the client hub method
callback.apply(hub, $.makeArray(arguments));
};
}
function registerHubProxies(instance, shouldSubscribe) {
var key, hub, memberKey, memberValue, subscriptionMethod;
for (key in instance) {
if (instance.hasOwnProperty(key)) {
hub = instance[key];
if (!(hub.hubName)) {
// Not a client hub
continue;
}
if (shouldSubscribe) {
// We want to subscribe to the hub events
subscriptionMethod = hub.on;
} else {
// We want to unsubscribe from the hub events
subscriptionMethod = hub.off;
}
// Loop through all members on the hub and find client hub functions to subscribe/unsubscribe
for (memberKey in hub.client) {
if (hub.client.hasOwnProperty(memberKey)) {
memberValue = hub.client[memberKey];
if (!$.isFunction(memberValue)) {
// Not a client hub function
continue;
}
// Use the actual user-provided callback as the "identity" value for the registration.
subscriptionMethod.call(hub, memberKey, makeProxyCallback(hub, memberValue), memberValue);
}
}
}
}
}
$.hubConnection.prototype.createHubProxies = function () {
var proxies = {};
this.starting(function () {
// Register the hub proxies as subscribed
// (instance, shouldSubscribe)
registerHubProxies(proxies, true);
this._registerSubscribedHubs();
}).disconnected(function () {
// Unsubscribe all hub proxies when we "disconnect". This is to ensure that we do not re-add functional call backs.
// (instance, shouldSubscribe)
registerHubProxies(proxies, false);
});
proxies['toastHub'] = this.createHubProxy('toastHub');
proxies['toastHub'].client = { };
proxies['toastHub'].server = {
};
return proxies;
};
signalR.hub = $.hubConnection("/signalr", { useDefaultPath: false });
$.extend(signalR, signalR.hub.createHubProxies());
}(window.jQuery, window));
Something is not correctly initialized with your SignalR project, I guess accessing a hubContext should have a Dependency Injector in your startup.cs. But doing context injection with DI for SignalR is an advanced level problem.
However, please try this minimal sample, if it's working for you: https://github.com/bezzad/MVC-SignalR-2
Looks to me like you need to just change the calls to broadcastToast from client to server. As that method is in the Hub and so requires the server instead.
$.connection.toastHub.client.broadcastToast
To
$.connection.toastHub.server.broadcastToast
I'm trying to implement a websocket-server with Progress OpenEdge. I still didn't get it working.
I've successfully created a socket-server with the example i-sktsv1.p from here.
When I run my html-page, which looks like:
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8" />
<title>WebSocket Client</title>
<script language="javascript" type="text/javascript">
var wsUri = "ws://localhost:3333/";
var output;
function init() {
output = document.getElementById("output");
testWebSocket();
}
function testWebSocket() {
websocket = new WebSocket(wsUri);
websocket.onopen = function(evt) { onOpen(evt) };
// websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) };
}
function onOpen(evt) {
writeToScreen("CONNECTED");
doSend("WebSocket rocks");
}
function onClose(evt) {
writeToScreen("DISCONNECTED");
}
function onMessage(evt) {
writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data+'</span>');
websocket.close();
}
function onError(evt) {
writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
}
function doSend(message) {
writeToScreen("SENT: " + message);
websocket.send(message);
}
function writeToScreen(message) {
var pre = document.createElement("p");
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
output.appendChild(pre);
}
window.addEventListener("load", init, false);
</script>
<body>
<h2>WebSocket Test</h2>
<div id="output"></div>
</body>
</html>
I getting a error that the websocket connection could not be established.
The problem is (I think) that Progress offers a socket, not a websocket. Do you know how to get this working?
I am using ASP.NET with angular.
In the scripts folder i have 2 files - MoviesAngular.js and ListController.js
MoviesAngular.js
(function ()
{
var app = angular.module("MoviesAngular", []);
}
)
ListController.js
(function () {
var app = angular.module("MoviesAngular",[])
var ListController = function ($scope) {
$scope.message = "Hello World";
};
app.controller("ListController", ListController);
}()
);
In the Index.html i have the following code:
#section scripts {
<script src="~/Scripts/angular.min.js"></script>
<script src="~/Client/Scripts/MoviesAngular.js"></script>
<script src="~/Client/Scripts/ListController.js"></script>
}
<div ng-app="MoviesAngular">
<div ng-controller="ListController">
{{message}}
</div>
</div>
However when i run the application i am not getting the text displayed as "Hello World" Where am i going wrong here.
Edited to include the other scenario where controller and app was defined seperately:(I was getting the error - Error: $injector:nomod
Module Unavailable). Then i modified the code as above.
MoviesAngular.js
(function () {
var app = angular.module("MoviesAngular", []);
}()
);
ListController.js
(function (app) {
var ListController = function ($scope) {
$scope.message = "Hello World";
};
app.controller("ListController", ListController);
}(angular.module("MoviesAngular"))
);
This code works fine: I have tested this
ww.js
(function () {
var app = angular.module("MoviesAngular",[])
var ListController = function ($scope) {
$scope.message = "Hello World";
};
app.controller("ListController", ListController);
}()
);
The view is:
<html>
<head>
<script src="angular.min.js"></script>
<script src="ww.js"></script></head>
<body>
<div ng-app="MoviesAngular">
<div ng-controller="ListController">
{{message}}
</div>
</div>
</body>
</html>
Hope it will help.
I do not find any error in your code. I am just changing the syntax of code. Try this.
(function () {
var app = angular.module("MoviesAngular",[])
app.controller("ListController", function ($scope) {
var ListController = function () {
$scope.message = "Hello World";
};
ListController();
});
}()
);
The IIFE in the MoviesAngular.js file not invoked in your example
(function() {
var app = angular.module("MoviesAngular", []);
}()); // invoke function expression
angular.module with specified second parameter creates new module. In the ListController.js file you need to get already created module, thus remove second parameter from angular.module
(function() {
var app = angular.module("MoviesAngular")
var ListController = function($scope) {
$scope.message = "Hello World";
};
app.controller("ListController", ListController);
}());
I was pointed to this GITHub sample code by David Fowler himself to track SignalR users and states. I have implemented all of it and it works great except I can't figure out the displaying of Hub connection state changes. I have this which doesn't seem to work. Does anyone know why?
!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<style>
#state {
width: 20px;
height: 50px;
}
</style>
</head>
<body>
<h3 id="msg"></h3>
<div id="state"></div>
<script src="../Scripts/jquery-1.10.2.min.js"></script>
<script src="../Scripts/jquery.signalR-2.0.2.min.js"></script>
<script src="signalr/hubs"></script>
<script>
$(function () {
var userTracking = $.connection.alphaHub;
// Need at least one callback for events to be raised on the hub
userTracking.client.void = function () { };
$.connection.logging = true;
$.connection.hub.stateChanged(function (change) {
if (change.newState === $.signalR.connectionState.connected) {
$('#state').css('background-color', 'green');
} else if (change.newState === $.signalR.connectionState.reconnecting) {
$('#state').css('background-color', 'yellow');
} else if (change.newState === $.signalR.connectionState.disconnected) {
$('#state').css('background-color', 'red');
}
});
$.connection.hub.disconnected(function () {
setTimeout(function () {
$.connection.hub.start();
}, 1000);
});
});
</script>
</body>
</html>
My Hub is shown partially here:
public class AlphaHub : Hub
{
public override async Task OnConnected()
{
try
{
var name = Context.User.Identity.Name;
using (savitasEntities2 entities = new savitasEntities2())
{
var user = entities.SUsers
.Include(u => u.SConnections)
.SingleOrDefault(u => u.UserName == name);
if (user == null)
{
user = new SUser
{
UserName = name,
SConnections = new List<SConnection>()
};
entities.SUsers.Add(user);
}
user.SConnections.Add(new SConnection
{
ConnectionID = Context.ConnectionId,
UserAgent = Context.Request.Headers["User-Agent"],
LastActivity = DateTimeOffset.UtcNow
});
// entities.SaveChanges();
await entities.SaveChangesAsync();
}
}
public override async Task OnDisconnected()
{
try
{
using (savitasEntities2 db = new savitasEntities2())
{
var connection = await db.SConnections.FindAsync(Context.ConnectionId);
db.SConnections.Remove(connection);
await db.SaveChangesAsync();
}
}
catch (Exception ex)
{
c.LogError(ex.Message, "AlphaHub.cs" + " - " + this.GetType().FullName + "." + System.Reflection.MethodBase.GetCurrentMethod().Name);
}
}
Looks like your hubs can't be found.
Change:
<script src="signalr/hubs"></script>
to:
<script src="~/signalr/hubs"></script>
bonsai docs “Communication” section (http://docs.bonsaijs.org/overview/Communication.html) has the following example which runs everywhere, except IE9:
<script src="http://cdnjs.cloudflare.com/ajax/libs/bonsai/0.4/bonsai.min.js"></script>
<div id="movie"></div>
<script>
var movie = bonsai.run(
document.getElementById('movie'),
{
code: function() {
// receive data from the other side
var text = new Text().addTo(stage);
stage.on('message:externalData', function(data) {
text.attr('text', data.nodeData);
});
stage.on('message', function(data) {
if (data.bonsai === 'tree') {
text.attr('textFillColor', 'red');
}
});
stage.sendMessage('ready', {});
}
}
);
// emitted before code gets executed
movie.on('load', function() {
// receive event from the runner context
movie.on('message:ready', function() {
// send a categorized message to the runner context
movie.sendMessage('externalData', {
nodeData: document.getElementById('movie').innerHTML
});
// send just a message to the runner context
movie.sendMessage({
bonsai: 'tree'
});
});
});
</script>
The fist question is: why the following code modification:
<script src="http://cdnjs.cloudflare.com/ajax/libs/bonsai/0.4/bonsai.min.js"></script>
<div id="movie"></div>
<script>
var movie = bonsai.run(document.getElementById('movie'), 'movie.js');
// emitted before code gets executed
movie.on('load', function() {
// receive event from the runner context
movie.on('message:ready', function() {
// send a categorized message to the runner context
movie.sendMessage('externalData', {
nodeData: document.getElementById('movie').innerHTML
});
// send just a message to the runner context
movie.sendMessage({
bonsai: 'tree'
});
});
});
</script>
where movie.js is:
document.getElementById('movie'),
{
code: function() {
// receive data from the other side
var text = new Text().addTo(stage);
stage.on('message:externalData', function(data) {
text.attr('text', data.nodeData);
});
stage.on('message', function(data) {
if (data.bonsai === 'tree') {
text.attr('textFillColor', 'red');
}
});
stage.sendMessage('ready', {});
}
}
throws “WORKER undefined”
Why original code does not work in IE9?