how can i wait for javascript return before executing the second part of hub method with SignalR? - methods

I have a problem in my ASP.NET MVC 4 project.
I use SignalR to create a turn-based game and in a hub event method OnConnected(), I call two separate methods to refresh my aspx with javascript code.
Here is my code :
public override System.Threading.Tasks.Task OnConnected()
{
// Demande les infos du joueur
Send2();
string clientId = GetClientId();
string clientName = utilisateurlambda;
if (Users.IndexOf(clientId) == -1)
{
Users.Add(clientId);
UsersNames.Add(clientName);
}
// Send the current count of users
Send1(Users.Count);
return base.OnConnected();
}
So I want the Send2() method to finish refreshing my aspx page before the method Send1(Users.Count) is called.
Actually, Send1(Users.Count) is called before Send2 finish. Please help me !

Refreshing your aspx page will kill your SignalR connection assuming you are completely reloading the same page you are starting your SignalR connection from.
Secondly, the client will not receive any messages until OnConnected completes. Typically connection initialization logic, such as adding a client to a group, goes inside OnConnected, and you probably don't want to start processing messages until your connection is initialized.
If you don't want to call Send1 until your page is refreshed, you should not call Send1 in OnConnected. Instead, call Send1 in another Hub method that you call from the client after the page refreshes.

Related

Notifying clients from (boxed) Syncfusion Ajax call

I'm trying to integrate the schedule component from Syncfusion. The component has a URL adaptor to connect to the controller; GetData() and Batch() for Crud Operations. Batch has a payload indicating what actions to perform. At the end, the Batch method would requery the database and send data identical to GetData() back.
Unfortunately, there is no built-in method to notify clients of anything going wrong - whether there is an exception, server-side validation kicks in or similar.
What I'd like to do is to add a placeholder outside the compentent to receive and display server messages (be it a notification popup, a or whatever.
Since I can't influence the Ajax call itself, I was wondering if I had to get started with SignalR (still in beta for .Net Core 2 as far as I know), or if I may have missed something more obvious? I have read a lot about push notifications etc - but these are not quite what I'm after, it'd be slightly over the top I think.
To summarise, let's say I have
<div id="messages"></div>
<div id="component">HereGoesTheScheduleWhichICantDoMuchWith</div>
Now in the Batch() method, it would be great to call a SendMessage("Sorry,you can't do this") - the text of which would ideally then appear in the messages-div.
How would you go about this?
I have now solved this, using SignalR (currently 1.0.0-alpha2-final) and for a nice view on the Client, PNotify.
Presently, it only works if the client is authenticated, if it needs to work anonymously you'd need to figure out a way to track SignalR's connection id.
On the page with the Syncfusion Schedule component, I connect to SignalR.
let connection = new signalR.HubConnection("/signalr", { transport: signalR.TransportType.ServerSentEvents });
connection.on("Notify",
(title, message) => {
new PNotify({
title: title,
text: message
});
});
connection.start();
The Hub (SignalRHub : Hub) creates a notification group for the user connecting:
public override Task OnConnectedAsync()
{
Groups.AddAsync(Context.ConnectionId, Context.User.Identity.Name);
return base.OnConnectedAsync();
}
The associated controller gets IHubContext<SignalRHub> signalRHub injected.
Now in the Batch-Method for the Syncfusion component, which returns Json and can't itself carry messages or notifications, you can notify the user:
_signalRHub.Clients.Group(User.Identity.Name).InvokeAsync("Notify", "A title", "A message");
In my particular case, I'm sending over an object to control layout, animation and popup duration for PNotify (e.g. longer for an exception to allow copy/paste etc) - as you please. Returning an object could be done using:
_signalRHub.Clients.Group(User.Identity.Name).InvokeAsync("Notify", JsonConvert.SerializeObject(new { title = "Some Title", message = "notification", type = "notice"}););
Obviously, connection.on("Notify"... needs to be changed accordingly.
I hope this is clear enough and might help someone else.

Open Sockjs inside an application

I want to create an application where on page3 users start communicating via a sockjs websocket (they go through page1 and page2 to reach page 3). The code is working fine but I dont know why!
// Global scope
var sock;
// Inside a function page3, this is invoked when Page3 loads for the first time
function page3(){
// Local scope
sock= new SockJS("localhost:8080/messages);
sock.onopen= function(){
....
};
sock.onmessage= function(data){
....
};
}
My question is - when a message is sent from the server how is sock.onmessage accessed by program execution even though it is 'seen' only when Page3 is loaded the first time which is when function page3() is called?
Looks like sock is not imported (the error message is saying that it is whats undefined)
Perhaps if you could share more of the code we could see why
Found my own answer.
The question is actually related to visibility of event listeners on the client. And the answer to that is - all event listeners on the client, once activated (flow of program execution having "seen" them) remain active until they are removed.
So in the above case, even though function page3() was "seen" by program execution only once - when Page3 was loaded for the first time, sock.onmessage becomes activated as a (client) event listener during that page3() function call and continues to remain active until the socket is closed.
As such, there is no need for an explicit page3() function call to trigger sock.onmessage. It (sock.onmessage) will keep listening to socket events sent by the server.

How to prevent AJAX polling keeping Asp.Net sessions alive

We have a ASP.Net application that has been given a 20 minute sliding expiry for the session (and cookie).
However, we have some AJAX that is polling the server for new information. The downside of this of course is that the session will continue indefinitely, as it is being kept alive by the polling calls causing the expiry time to be refreshed. Is there a way of preventing this - i.e. to only allow the session to be refreshed on non-ajax calls?
Turning off sliding expiry is not really an option as this is an application that business users will be using for most of their day between telephone calls.
Other Stackoverflow discussions on this talk about maintaining 2 separate application (one for authenticated calls, one for unauthenticated. I'm not sure this will be an option as all calls need to be authenticated.
Any ideas?
As this question is old I am assuming it has been resolved or a workaround implemented. However, I wanted to mention that instead of AJAX polling the server to perform an operation we have utilized SignalR which allows both the client to communicate with the server via JQuery and/or the server to notify the client.
Check it out: Learn About ASP.NET SignalR
add below code to your controller action that you are reference for polling.Convert this into an attribute so it can be used everywhere. This line will not extend session timeout
[HttpPost]
public ActionResult Run()
{
Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
return Json("");
}
There is no way to stop the ajax from keeping the session and cookies alive!
However, there is a way to achieve what you want to do. That is if the process I will describe will be ok to you.
I think what you really want to achieve is first to refresh your page with ajax so that some processes will be active and running. Also to know when the user has stopped operating the program.
If that is what you want then there is a simple process to achieve this
You will have your ajax running for the things you want to run.
You will remove the session you want to check if user has stopped operation on the page and manage the session as a variable instead.
The variable can be a global variable or a class variable that will be set to initial value whenever the user clicks an element on the page.
(You will select the click event of an element and set the variable to initial value)
You will increment the variable every given time (say every time your ajax runs)
You will also have a function/method run to check the value of that variable if it is greater than the value you set as limit. This can run every time your ajax runs or every time you want it to run (timed event).
If the value of your variable is greater than the limit set it should invalidate or clear session/log user out.
This way if user stops operating (clicking elements) the system on any page that this is running will eventually log out the current user and stop running the program.
I have done this by creating a hidden page in an i-Frame. Then using JavaScript it posts back every 18 minutes to keep the session alive. This works really well.
This example is from a ASP.NET Forms project but could be tweaked for MVC.
Create a page called KeepSessionAlive page and add a meta refresh tag
meta id="MetaRefresh" http-equiv="refresh" content="21600;url=KeepSessionAlive.aspx"
In the code behind
protected string WindowStatusText = "";
protected void Page_Load(object sender, EventArgs e)
{
//string RefreshValue = Convert.ToString((Session.Timeout * 60) - 60);
string RefreshValue = Convert.ToString((Session.Timeout * 60) - 90);
// Refresh this page 60 seconds before session timeout, effectively resetting the session timeout counter.
MetaRefresh.Attributes["content"] = RefreshValue + ";url=KeepSessionAlive.aspx?q=" + DateTime.Now.Ticks;
WindowStatusText = "Last refresh " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString();
}
Add the hidden iFrame in a master page
iframe ID="KeepAliveFrame" src="KeepSessionAlive.aspx" frameBorder="0" width="0" height="0"
Download example

Laravel IoC and singleton pattern

I'm trying to use Laravel IoC by creating a singleton object. I'm following the pattern from tutorial as below. I have put a Log message into object (Foobar in this example) constructor and I can see that object is being created every time I refresh page in browser. How is the singleton pattern meant for Laravels IoC? I understood that its shared object for entire application but its obviously being created every time its requested by App:make(...) Can someone explain please. I thought I would use the singleton pattern for maintaining shared MongoDB connection.
App::singleton('foo', function()
{
return new FooBar;
});
What has been said in Laravel Doc
Sometimes, you may wish to bind something into the container that
should only be resolved once, and the same instance should be returned
on subsequent calls into the container:
This is how you can bind a singleton object and you did it right
App::singleton('foo', function()
{
return new FooBar;
});
But, the problem is, you are thinking about the whole process of the request and response in the wrong way. You mentioned that,
I can see that object is being created every time I refresh page in
browser.
Well, this is normal behaviour of HTTP request because every time you are refreshing the page means every time you are sending a new request and every time the application is booting up and processing the request you've sent and finally, once the application sends the response in your browser, it's job is finished, nothing is kept (session, cookie are persistent and different in this case) in the server.
Now, it has been said that the same instance should be returned on subsequent calls, in this case, the subsequent calls mean that, if you call App::make(...) several times on the same request, in the single life cycle of the application then it won't make new instances every time. For example, if you call twice, something like this
App::before(function($request)
{
App::singleton('myApp', function(){ ... });
});
In the same request, in your controller, you call at first
class HomeController {
public function showWelcome()
{
App::make('myApp'); // new instance will be returned
// ...
}
}
And again you call it in after filter second time
App::after(function($request, $response)
{
App::make('myApp'); // Application will check for an instance and if found, it'll be returned
});
In this case, both calls happened in the same request and because of being a singleton, the container makes only one instance at the first call and keeps the instance to use it later and returns the same instance on subsequent calls.
It is meant to be used multiple times throughout the applications instance. Each time you refresh the page, it's a new instance of the application.
Check this out for more info and practical usage: http://codehappy.daylerees.com/ioc-container
It's written for L3, but the same applies for L4.

How do I Invoke Ajax OnClick from Provider Web Part to Consumer Web Part

I am attempting to manage an ajax connection by calling a button onclick method on a separate web part in order to force the partial postback on the consumer.
Web part A (Provider) invokes the method on Web Part B (Consumer)
Web Part A
Type t = myButton.GetType();
object[] p = new object[1];
p[0] = EventArgs.Empty;
MethodInfo m = t.GetMethod("OnClick", BindingFlags.NonPublic | BindingFlags.Instance);
m.Invoke(myButton, p);
Web Part B
public void btnHidden_Click(object sender, EventArgs e)
{
Label1.Text = "Hidden Button: " + DateTime.Now.ToString();
}
When I use reflection, I get the correct information on the HiddenButton. However, I cannot invoke the "OnClick" event. The btnHidden_Click does not execute. It works fine when I invoke from WebPart B to WebPart B, but not from a different webpart.
There doesn't appear to be too much information regarding this behavior. Any suggestions?
Thanks.
Rob
Since Web Parts should be a loosely coupled as possible, I'd use the Web Part connections infrastructure and the Subscriber pattern to handle this.
Communication between connected parts is done through an interface. This interface could include Subscribe and Unsubscribe methods. When the connection is made, the consumer part could subscribe any UpdatePanel controls it needs to be updated when the selected item changes in the provider. Then when the selected item does change, the provider part can walk its subscribers and call the Update method on the UpdatePanel to force an async postback.
I haven't tried this myself but the only drawback I can see is that you may have to queue the calls to Update because any triggering of an async postback cancels any other async postbacks currently in progress.
I hope this helps.
This is so incredably easy to solve using JavaScript. I don't want to say that Web Parts is bad (in as much as I've never worked with them), but I will say that if you are able to program the tiniest bit of JS into the web parts, the code is:
document.getElementById('ElID').onclick();
Good luck!

Resources