I'm leaning SignalR. How can I write a simple app so user can see server-time in real-time using Hub. Every 1 second, server will send time from server to connected clients
you can do when you using thread.
Example Hub Class:
public class ServerTime : Hub
{
public void Start()
{
Thread thread = new Thread(Write);
thread.Start();
}
public void Write()
{
while (true)
{
Clients.settime(DateTime.Now.ToString());
Thread.Sleep(1000);
}
}
}
Example Script :
<script type="text/javascript">
$(document).ready(function () {
var time = $.connection.serverTime;
$("#btnTest").click(function () {
time.start();
});
time.settime = function (t) {
$("#Time").html(t);
};
$.connection.hub.start();
});
</script>
<div id="Time"></div>
<input id="btnTest" type="button" value="Test"/>
Thread will start working when you click btnTest.
Thread sends message to page everysecond.
Create a listener and RAISE AN EVENT when a NOTIFICATION is added :) Thus you would not have to continuously check the database :)
In Global.asax in the Application_Start(object sender, EventArgs e) method create a background thread and start it. In that thread you will need to do this to get access to your hub:
IConnectionManager connectionManager = AspNetHost.DependencyResolver
.Resolve<IConnectionManager>();
dynamic clients = connectionManager.GetClients<ServerTime>();
clients.settime(DateTime.UtcNow.ToString());
NB DateTime.UtcNow is nearly always preferable since it doesn't leap around twice a year.
Related
I had a web Application with master page and I need to show a alert to all connected users of my application. I had used the Owin startup class and mapped signal R
Then created a Hub like below
namespace ArtWebApp
{
[HubName("artHub")]
public class ArtWebHub : Hub
{
public void Hello()
{
Clients.All.hello();
}
public void SayMessage()
{
this.Clients.All.showmessage();
}
}
}
Then in the masterpage I added the Javascript as below
<script src="Scripts/jquery-1.6.4.js"></script>
<script src="Scripts/jquery.signalR-2.2.1.js"></script>
<script type="text/javascript">
$(function () {
debugger;
var connection = $.hubConnection("")
var hub = connection.createHubProxy('artHub');
hub.on('showmessage', function () {
alert('Hi');
});
connection.start().done();
//connection.start(function () {
// hub.invoke('SayMessage');
//});
});
</script>
This is working perfectly when the Hub method is invoked from the same page but when I tried to call the method from button click of a page its not working
protected void Button1_Click(object sender, EventArgs e)
{ var hubContext = GlobalHost.ConnectionManager.GetHubContext<ArtWebApp.ArtWebHub>();
hubContext.Clients.All.SayMessage();
}
Can somebody suggest me the issue
What i can see from your code is a mistake on the client side function you are calling.
Clients.All typically lets you invoke a function you have defined at the client side by calling Clients.All.functionName()
In the Button1_Click event please change
hubContext.Clients.All.SayMessage();
To
hubContext.Clients.All.showMessage();
This is because you are using the dynamic collection Clients
You are trying to invoke a client side function (which doesn't exist).
The method SayMessage you are trying to call is a member of the ArtWebHub class and cannot be invoked by calling hubContext.Clients.All.
You can invoke SayMessage from the client using hub.invoke('SayMessage') but to invoke the showmessage function defined in the client you'll have to invoke it differently from the server because SayMessage is not available to the hubContext
I'm trying to learn SignalR by writing a really simple application... it basically sends "Hello" periodically (like the Stock Ticker, but a lot simpler).
Here's my hub:
public class StockTickerHub : Hub
{
public void Hello()
{
var s = StockTicker.stockTicker;
Clients.All.hello();
}
}
...and here's the code that is supposed to periodically send the messages:
public class StockTicker
{
public static StockTicker stockTicker = new StockTicker();
private Thread thread;
public StockTicker()
{
var stockTickerHub = GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>();
this.thread = new Thread(() =>
{
while (true)
{
stockTickerHub.Clients.All().hello();
Thread.Sleep(1000);
}
}
);
this.thread.Start();
}
}
I'm getting a RuntimeBinderException at stockTickerHub.Clients.All().hello();. It says:
An unhandled exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll
Additional information: Cannot invoke a non-delegate type
What am I doing wrong?
Client-side JavaScript is below, just in case you need to replicate this.
<script type="text/javascript">
$(function () {
var chat = $.connection.stockTickerHub;
chat.client.hello = function () {
$("#log").append("Hello");
}
$.connection.hub.start().done(function () {
chat.server.hello();
});
});
</script>
Simply change:
stockTickerHub.Clients.All().hello();
to:
stockTickerHub.Clients.All.hello();
The debugger should have already tell you this error. I tried your code after the update. It is working.
A remark on the code design:
I wouldn't start a new sending thread in the hello event, that would start one every time this method is invoked by any client. I don't think that's what you want to do. As a smoother example you could start the ticker in Startup class. (If you want a ticker per connection override OnConnected, get the client's connection id and give them separate tickers...)
I'm using quartz in an asp.net site and I'm using it to fire off a longer background task. I want to be able to use a timer or jquery to call the job and get back status and progress info similar to how I was doing it before. Here is code that I was using:
protected void Timer1_Tick(object sender, EventArgs e)
{
if (MyTaskManager.Instance.IsTaskRunning)
{
if (MyTaskManager.Instance.TotalItems > 0) ProgressLabel.Text = string.Format(ProgressLabel.Text, MyTaskManager.Instance.TotalItems, MyTaskManager.Instance.ItemsProcessed);
else ProgressLabel.Text = string.Format("Records Processed: {0}", MyTaskManager.Instance.ItemsProcessed);
}
else
{
Timer1.Enabled = false;
}
}
Has anyone done this that could point me in the right direction?
It might not be what you're looking for but I've used SignalR with Quartz.Net and it works great.
I've published a simple application in my repository.
You have to create a custom Hub which you will use to interact with your ASP.NET page.
Your (quartz.net) job will interact your ASP.NET page through your Hub the same way.
Once you have installed ASP.NET SignalR:
Install-Package Microsoft.AspNet.SignalR
You can create a startup class to configure SignalR:
[assembly: OwinStartup(typeof(AspNetQuartSignalR.Startup))]
namespace AspNetQuartSignalR
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
You have to reference a couple of scripts in your page:
jquery-2.1.1.js
jquery.signalR-2.1.1.js
and the automatically generated /signalr/hubs
Now you can create your own Hub:
public class QuartzHub : Hub
{
...
}
with methods which will allow you to interact with the scripts in your ASP.NET page.
Let's say your Hub has a method CheckQuartzStatus which gives you the status of all the quartz.net triggers configured:
public void CheckQuartzStatus()
{
string message = string.Empty;
var allTriggerKeys = Global.Scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.AnyGroup());
foreach (var triggerKey in allTriggerKeys)
{
ITrigger trigger = Global.Scheduler.GetTrigger(triggerKey);
message += string.Format("{0} = {1}", trigger.Key, Global.Scheduler.GetTriggerState(trigger.Key)) + Environment.NewLine;
}
Clients.All.onCheckQuartzStatus(message);
}
Your jQuery script can interact with this method in a very simple way:
quartz.server.checkQuartzStatus();
As you can see your Hub method at some point fires an action: onCheckQuartzStatus.
That is a call to an event defined in your javascript defined in the page :
quartz.client.onCheckQuartzStatus = function (message) {
alert(message);
};
You can see how the interaction works looking at the script in the Default.aspx page.
You can read a lot more here.
You're going to have to build all of this functionality yourself. Quartz.Net jobs run in the threadpool and you don't have a way of referencing them from the scheduler. You could do this by having the job write its progress somewhere and then have your timer check that spot for progress.
Hope everyone is well.
I'm using MVC C# , AspNet.Identities and have a fully functional Account controller.
I recently introduced a basic SignalR Hub to the project, I want to log the user out once he disconnects from the Hub. My idea is to call the LogOff method from the Account Controller.
The Hub is really simple, infact I've taken this from a video by Scott Hanselman if I'm not mistaken. Just the hitCounter part...Now I'm trying to add in the logoff() functionality.
Here's what I've got so far.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
AuthenticationManager.SignOut();
return RedirectToAction("Welcome", "Home");
}//this is in my account controller
[Authorize]
[HubName("hitCounter")]
public class GameplayHub : Hub
{
private static int intCounter = 0;
public void RecordHit()
{
intCounter += 1;
this.Clients.All.onHitRecorded(intCounter);
}
public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
{
Final.Controllers.AccountController obj = new Final.Controllers.AccountController();
intCounter -= 1;
this.Clients.All.onHitRecorded(intCounter);
this.Clients.Caller.onHitRecorded(obj.LogOff());
obj.LogOff();
return base.OnDisconnected(stopCalled);
}
}//this is the hub
<div id="hitCount" style="font-size:50px;"></div>
<script src="~/Scripts/jquery-1.6.4.js"></script>
<script src="~/Scripts/jquery.signalR-2.1.1.js"></script>
<script src="/signalr/hubs"></script>
<script>
$(function() {
var con=$.hubConnection();
var hub=con.createHubProxy('hitCounter');
hub.on('onHitRecorded', function (i) {
$('#hitCount').text(i);
});
con.start(function() {
hub.invoke('recordHit');
});
})
</script>//My view...just shows how many people active at that point...
The amount of people active, shows correctly. What I'm trying to do in my app is, if a user in on 2 tabs, and he closes one, he must be logged off on both.
Any help will be appreciated! Thanks :)
Unfortuntelny it is not going to work. Logging off user is done by removing cookie which has to be done by browser. SignalR runs your disconnected handler after tab was already closed, so you can not tell browser to delete cookie.
The solution that could work is to force redirect to log off page on the second tab opened by user.
Pseudocode:
In SignalR hub:
Task OnDisconnected()
{
var otherTab = FindOtherTabWithUser();
otherTab.forceLogOff();
}
In JavaScript:
forceLogOff = function() { window.location.href = '/logoff'; }
I am trying out SignalR, and i don't quite understand how to call methods from my client in a way that it calls the same hub.
i have two methods in my hub:
private ctlDataManager myManager;
public void StartConnection()
{
myManager = new ctlDataManager("test");
myManager.UpdateItemEvent += myManager_UpdateItemEvent;
myManager.Connect();
}
public void StopConnection()
{
myManager.Disconnect();
}
And in my client i try to call them like this:
var notificationHub = $.connection.notificationHub;
$.connection.hub.start()
.done(function (state) {
$("#submit").click(function (e) {
e.preventDefault();
notificationHub.server.startConnection();
return false;
});
$("#stop").click(function (e) {
e.preventDefault();
notificationHub.server.stopConnection();
return false;
});
});
Now when i click on the start button it works fine it starts it and receives data too.
But when i click the stop button it throws an instance of an object error.
It appears that 'myManager' is null. It's almost as a new hub were open. Naturally i need it to be the same one as i need to close the connection.
How can i do that?
From my understanding, the server-side hub class is not persisted. Therefore, the myManager object is created with each method call from a client. My advice would be to declare myManager elsewhere in your application that you can assure 100% up-time, and have your server-side hub methods communicate with it that way.
One way for you to verify this is to debug the constructor of your hub class. You will notice that it is called for every client->server-side method call.