ASP.NET MVC - Timer - asp.net-mvc

I am trying to implement something in ASP.NET MVC where I can make each user perform an action once every n minutes.
I have come across controls such as Timer but, not quite sure what to use. I would like it so that when the user performs the action, a timer begins to count down from, for example, 3 minutes to 0:00. Once the 3 minutes have lapsed, the user will be able to perform the action again.
Any ideas how I can achieve this? Would I need a Timer Control?

There is a perfect solution here: Best way to implement request throttling in ASP.NET MVC? created by SO team.
Basically the idea is to store page hits for each user in the cache and then respond to a request based on your logic.

You could use jquery-timer http://code.google.com/p/jquery-timer/
Basic use would be disable button, invoke timer and then re-enable button when it completes.
However, if you want to post back in the interim this would not work.

The easiest way to do this would be to save the time of the last action in the session and on subsequent requests check whether it has been more than 3 minutes. For example:
public ActionResult DoSomething(){
if (Session["LastAction"] == null || (DateTime.Now - (DateTime)(Session["LastAction"])).Minutes > 3){
// do action
Session["LastAction"] = DateTime.Now;
return View("OK. action executed");
}
else{
return View("Please wait");
}
}

The most elegant way to achieve this is implementing a job scheduler like Quartz.NET and defining proper job (what has to be done) and proper trigger (when/how often has to be done). With Quartz you can also implement much more complex conditions ("do it every Monday" etc).
Hope it will help.

Related

Get session creation time in Grails + Apache Shiro

There's this text Last seen: field in my application that shows for how long the current user is logged on the system (e.g. 5 seconds ago, 4 hours ago, 3 days ago, etc.). Now for me to do this, I need to determine either:
the time Apache Shiro performs the login; or
the time the current Grails Session has been created.
Then subtract it to the current time. But how can I access the creation time of either of the two? Or are there any better ways to achieve this not using the mentioned above?
In your controller action you can write like this:
class MyController {
// Considering this action is secured for logged in user only
def foo() {
long currentMillis = new Date().getTime()
long sessionCreationMillis = session.getCreationTime()
long loggedInFor = currentMillis - sessionCreationMillis
println "User has been logged in for $loggedInFor miliseconds"
}
}
Now, you got how long the user has been logged in (in milliseconds). Further, you can use the TimeUnit library to convert your milliseconds to other values.
Or, you can also use any Javascript library like this if you are planning to do it on client side.
I have no idea about Apache Shiro but I can tell you how to get the session creation time.
It's pretty simple actually, there is a method called getCreationTime() in HttpSession. Here is the doc
You can invoke this method on the session attribute available in controllers. This will return the time in milliseconds as long.

How to use AsyncController or Task or Thread during time consuming operation in MVC?

I have a simple yet time consuming operation:
when the user clicks a button, it performs a database intensive operation, processing records from an import table into multiple other tables, one import record at a time.
I have a View with a button that triggers the operation and at the end of the operation a report is displayed.
I am looking at ways to notify the user that the operation is being processed.Here is a solution that I liked.
I have been reading up online about Asynchronous operations in MVC. I have found a numbers of links saying that if your process is CPU bound stick to using synchronous operations. Is database related process considered CPU bound or not?
Also if I got the Asynchronous operation route should I use AsyncController as described here or just use Task as in the example I mentioned and also here . or are they all the same?
The first thing you need to know is that async doesn't change the HTTP protocol. As I describe on my blog, the HTTP protocol gives you one response for each request. So you can't return once saying it's "in progress" and return again later saying it's "completed".
The easy solution is to only return when it's completed, and just use AJAX to toss up some "in progress..." notification on the client side, updating the page when the request completes. If you want to get more complex, you can use something like SignalR to have the server notify the client when the request is completed.
In particular, an async MVC action does not return "early"; ASP.NET will wait until all the asynchronous actions are complete, and then send the response. async code on the server side is all about scalability, not responsiveness.
That said, I do usually recommend asynchronous code on the server side. The one exception is if you only have a single DB backend (discussed well in this blog post). If your backend is a DB cluster or a distributed/NoSQL/SQL Azure DB, then you should consider making it asynchronous.
If you do decide to make your servers asynchronous, just return Tasks; AsyncController is just around for backwards compatibility these days.
Assuming C# 5.0, I would do something like this following:
// A method to get your intensive dataset
public async Task<IntensiveDataSet> GetIntensiveDataSet() {
//in here you'll want to use any of the newer await Async calls you find
// available for your operations. This prevents thread blocking.
var intensiveDataSet = new IntensiveData();
using (var sqlCommand = new SqlCommand(SqlStatement, sqlConnection))
{
using (var sqlDataReader = await sqlCommand.ExecuteReaderAsync())
{
while (await sqlDataReader.ReadAsync())
{
//build out your intensive data set.
}
}
}
return intensiveDataSet;
}
// Then in your controller, some method that uses that:
public async Task<JsonResult> Intense() {
return Json(await GetIntensiveDataSet());
}
In your JS you'd call it like this (With JQuery):
$.get('/ControllerName/Intense').success(function(data) {
console.log(data);
});
Honestly, I'd just show some sort of spinner while it was running.
If you do need some sort of feedback to the user, you would have to sprinkle updates to your user's Session throughout your async calls... and in order to do that you'd need to pass a reference to that Session around. Then you'd just add another simple JsonResult action that checked the message in the Session variable and poll it with JQuery on an interval. Seems like overkill though. In most cases a simple "This may take a while" is enough for people.
You should consider the option of implementing asynchronization using AJAX. You could handle the client "... processing" message right in your View, with minimum hassle,
$.ajax({
url: #Url.Action("ActionName"),
data: data
}).done(function(data) {
alert('Operation Complete!');
});
alert('Operation Started');
// Display processing animation
Handling async calls on the server side can be expensive, complicated and unnecessary.

Zend\Session\Container annoyingly locks while in use, what's your workaround?

I have a controller with two actions. One performs a very long computation, and at several steps, stores status in a session container:
public function longAction()
{
$session = new Container('SessionContainer');
$session->finished = 0;
$session->status = "A";
// do something long
$session->status = "B";
// do more long jobs
$session->status = "C";
// ...
}
The second controller:
public function shortAction()
{
$session = new Container('SessionContainer');
return new JsonModel(
array(
'status' => $session->status
)
);
}
These are both called via AJAX, but I can evidence the same behavior in just using browser tabs. I first call /module/long which does its thing. While it completes its tasks, calling /module/short (I thought would just echo JSON) stalls /module/long is done!
Bringing this up, some ZFers felt this was a valid protection against race conditions; but I can't be the only one with this use case that really doesn't care about the latter.
Any cheap tricks that avoid heading towards queues, databases, or memory caches? Trying to keep it lightweight.
this is the expected behavior. this is why:
Sessions are identified using a cookie to store the session id, this allows your browser to pickup the same session on the next request.
As you long process is using sessions, it will not call session_write_close() until the whole process execution is complete, meaning the session is still open while the long process is running.
when you connect with another browser tab the browser will try and pickup the same session (using the same cookie) which is still open and running the long process.
If you open the link using a different browser you will see the page will load fine and not wait around for the session_write_close() to be called, this is because it's opening a separate session (however you will not see the text you want as it's a separate session)
You could try and manually write and close (session_write_close()) the session, but that's probably not the best way to go about things.
It's definitely worth looking at something like Gearman for this, there's not that much extra work, and it's designed especially for this kind of async job processing. Even writing status to the database would be better, but that's still not ideal.

Show notification after a CSV file has been fully exported with Vaadin

I have the following code:
Button export = new Button("CSV");
export.addListener(new ClickListener()
{
public void buttonClick(ClickEvent event)
{
CsvExport csvExport;
csvExport = new CsvExport(_table);
csvExport.setDisplayTotals(false);
csvExport.setDoubleDataFormat("0");
csvExport.excludeCollapsedColumns();
csvExport.setReportTitle("Document title");
csvExport.setExportFileName("Nome_file_example.csv");
csvExport.export();
getWindow().showNotification("Document saved", "The document has been exported.");
}
}
I would like the notification to appear only after the file has been exported and downloaded, but actually the notification is not working, maybe because it does not "wait" for the statement
csvExport.export();
to finish. If I comment it, the notification works.
Does anybody have any suggestions?
Thanks very much,
You'll need to split the work into a separate thread, then provide a way to notify the user 'later'.
So, first, create a thread... if you're on Java EE, use the built-in thread pooling, otherwise use something else (we're on tomcat, we rolled our own, to allow us better control).
Then, when you're done, synchronize your thread, work your way back into your UI class (We use closures from Groovy, but you can make your own listener), and call the method to notify your user. window.showNotification('All Done')
So here's the tricky part, you've notified your user, but Vaadin has already sent the 'click' response back... so the Server part thinks it's notified the user, but it isn't able to show the user yet... You'll need a progress indicator on your page, as it asks the server every 5 seconds if anything has changed.
There are also some 'push' plugins, but I've found that most of the places that we we're spinning up threads, we want to show a 'loading' animation, so the progress indicator works well.

ASP MVC - Comet/Reverse Ajax/PUSH - Is this code thread safe?

I'm trying to implement comet style features by polling the server for changes in data and holding the connection open untill there is something to response with.
Firstly i have a static variable on my controller which stores the time that the data was last updated:
public static volatile DateTime lastUpdateTime = 0;
So whenever the data i'm polling changes this variable will be changed.
I then have an Action, which takes the last time that the data was retrieved as a parameter:
public ActionResult Push(DateTime lastViewTime)
{
while (lastUpdateTime <= lastViewTime)
{
System.Threading.Thread.Sleep(10000);
}
return Content("testing 1 2 3...");
}
So if lastUpdateTime is less than or equal to the lastViewTime, we know that there is no new data, and we simply hold the request there in a loop, keeping the connection open, untill there is new information, which we could then send back to the client, which would handle the response and then make a new request, so the connection is essentially always open.
This seems to work fine but i'm concerned about thread safety, is this OK? Does lastUpdateTime need to be marked as volatile? Is there a better way?
Thanks
edit: perhaps i should use a lock object when i update the time value
private static object lastUpdateTimeLock = new object();
..
lock (lastUpdateTimeLock)
{
lastUpdateTime = DateTime.Now;
}
Regarding your original question, you do have to be careful with DateTimes, since they're actual objects in the .NET runtime. Only a few data types can be natively accessed (eg ints, bools) without locking (assuming you're not using Interlocked). If you want to avoid any issues with Datetimes, you can get the ticks as a long and use the Interlocked class to manage them.
That said, if you're looking for comet capabilities in a .NET application, you're unfortunately going to have to go a lot further than what you've got here. IIS/ASP.NET won't scale with the approach you've got in place right now; you'll hit limits before you even get to 100 users. Among other things, you will have to switch to using async handlers, and implement a custom bounded thread pool for the incoming requests.
If you really want a tested solution for ASP.NET/IIS, check out WebSync, it's a full comet server designed specifically for that purpose.
Honestly my concern would be with the number of connections kept open and the empty while loop. The connections you're probably fine on, but I'd definitely want to do some load testing to be sure.
The while (lastUpdateTime <= lastViewTime) {} seems like it should have a Thread.Sleep(100) or something in there. Otherwise I'd think it would consume a lot of cpu cycles needlessly.
The lock does not seem necessary to me around lastUpdateTime = DateTime.Now since the previous value does not matter. If it were lastUpdateTime = lastUpdateTime + 1 or something, then maybe it would be.

Resources