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.
Related
I´m on MVC and using KnockoputJS. I select the value from 2 select. In the first select i choose IDCompany, and the second select i choose IDSubsidiary.
I send the model in Json to JsonResult in the controller and I create a variable session and a cookie and save IDCompany in the Session variable and in the cookie with the same name.
I do the same with IDSubsidiary. Finally, I return to the ajax function (which call "Save" at first)
[HttpPost]
public JsonResult Save(ViewModel viewModel)
{
Session["IDCompany"] = viewModel.IDCompany.ToString();
Response.Cookies["IDCompany"].Value = viewModel.IDCompany.ToString();
Response.Cookies["IDCompany"].Expires = DateTime.Now.AddDays(1);
Session["IDSubsidiary"] = viewModel.IDSubsidiary.ToString();
Response.Cookies["IDSubsidiary"].Value = viewModel.IDSubsidiary.ToString();
Response.Cookies["IDSubsidiary"].Expires = DateTime.Now.AddDays(1);
return Json(true);
}
The problem is that after a while (30 mins approximately), i lose Session["IDCompany"] and Session["IDSubsidiary"] (becomes null).
The problem can be that, for example, Session["IDSubsidiary"] and Response.Cookies["IDSubsidiary"] has the same name?
There are two reasons this could be happening. 1) The session is timing out, or 2) you are using "In Process" session state.
If the user sits on a page for thirty minutes, and then the value is gone the next time they refresh or go to another page, its likely a timeout problem. You could try increasing the sessionState timeout; however, you'll probably start running into the issue described below. If you are determined to use Session variables, you should probably switch to a different state mode than "in process" which is the default.
If it is not timing out, the reason your value is lost is because "In Process" session state, goes away when the App Pool recycles. This can happen for a variety of reasons. You probably want to change your session state mode to State Server or SQL Server. This will keep your session data around between app pool recycles, but you will need to enable the "ASP.NET Session State Service" on the web server if you go the State Server route.
There are several state modes, each with different behaviors. You can read about them here on MSDN.
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.
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.
In my app, I have an external monitor that pings the app ever few minutes and measures its uptime / response time Every time the monitor connects, a new server session is created, so when I look at the number of sessions, it's always a minimum of 15, even during times where there are no actual users.
I tried to address this with putting the session creation code into a filter, but that doesn't seem to do it - I guess session automatically gets created when the user opens the first page?
all() {
before = {
if (actionName=='signin') {
def session = request.session //creates session if not exists
}
}
}
I can configure the monitor to pass in a paramter if I need to (i.e. http://servername.com/?nosession, but not sure how to make sure the session isn't created.
Right now there is nothing you can do to prevent the session creation. See: http://jira.codehaus.org/browse/GRAILS-1238
Fortunately, until you are hitting high numbers of requests per second, this isn't a huge problem. One thing we did to get around the false data in our "currently active users" report, was to log the sessions to the database. We create a session record only when the user logs in. Then on specifically mapped URLs, we will "touch" that session record to update the last accessed time. The session record keeps track of user agent, IP, etc and is useful for many reasons. Doing something like this would get around the bogus session count.
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.