I have a web page written in ASP.NET and I need to retrieve the end user's local time at Page_Load. I thought about using Javascript to get the local time (by using new Date()) but the problem is that the script is run after the server events.
Any ideas on how to accomplish this?
EDIT: My page is quite complex: it displays a chart with lots of calculated fields from a database, object/fields selection lists, etc; The customer now requested that it should consider the user's timezone and that the timezone should be determined automatically by the web page. The user date is important to determine the chart interval (which day to display data on).
Data loading (since it is so complicated) is done in both Page_Load and Page_PreRender. Giving up these events would require a full page rewrite.
FINAL SOLUTION INSPIRED BY ANSWER:
Here is how I solved the problem eventually. I am keeping the local date in a cookie. Here is the method that sets the cookie:
function SetLocalDateCookie() {
var cookieName = 'LOCALDATE';
var localDate = new Date();
var realMonth = localDate.getMonth() + 1;
var localDateString = localDate.getFullYear() + "/" + realMonth + "/" + localDate.getDate();
setCookie(cookieName, localDateString, 2);
try {
var exdate = new Date();
exdate.setDate(exdate.getDate() + 2);
document.cookie = cookieName + "=" + escape(localDateString) + ";expires=" + exdate.toGMTString();
}
catch (e)
{ }
}
In my Master page I call this method on $(document).ready.
On the page where I use this cookie I added the following code to Page_Init:
if (string.IsNullOrEmpty(CookieHandler.Instance.GetCookie(CookieKeys.LocalDate)))
{
Response.ClearContent();
Response.Write(#"<form id='local' method='post' name='local'>
<script type='text/javascript'>
SetLocalDateCookie();
document.getElementById('local').submit();
</script>
</form>");
Response.Flush();
Response.End();
}
Then I can just use the cookie value in the C# code.
Thank you for your answers/comments!
I'll explain a bit the following code and what lefts for you to do.
At the first request off this page, the code checks if the LocalTime is not already stored in Session and if not it will write a form element, a hidden input and a javascript which will post that form with the local time. The response ends, so your report won't get the chance to be generated.
This submit will immediately create a POST request with the localTime set, then ASP .Net stores this POST value into the Session.
I also added a 302 redirect (Response.Redirect) to the original page, because of the usability. The User made initially a GET request, not a POST, so if he/she wants to refresh the page, the browser will reiterate the last action, which was that form.submit() and not the GET request.
You have now the local time. But you don't have to read it at every request since it can be compared to the UTC time, then with the server's time.
edit: You need to parse the UTC time into a DateTime, but probably it's easy to find the format, though might depend on the user's culture (not sure about this statement).
public ReportPage()
{
this.Init += (o, e) =>
{
// if the local time is not saved yet in Session and the request has not posted the localTime
if (Session["localTime"] == null && String.IsNullOrEmpty(Request.Params["localTime"]))
{
// then clear the content and write some html, a javascript code which submits the local time
Response.ClearContent();
Response.Write(#"<form id='local' method='post' name='local'>
<input type='hidden' id='localTime' name='localTime' />
<script type='text/javascript'>
document.getElementById('localTime').value = new Date();
document.getElementById('local').submit();
</script>
</form>");
//
Response.Flush();
// end the response so PageLoad, PagePreRender etc won't be executed
Response.End();
}
else
{
// if the request contains the localtime, then save it in Session
if (Request.Params["localTime"] != null)
{
Session["localTime"] = Request.Params["localTime"];
// and redirect back to the original url
Response.Redirect(Request.RawUrl);
}
}
};
}
I don't think this would be possible, you can't get the time off the client's local machine at server side.
The only way to achieve this would be using some javascript (as this is client based, so it will use the client's current date/time). But as you've stated, this will be after your server events have been ran, and your web page has been rendered into HTML and sent to the client.
One alternative would be to capture the clients time before the Post Back, but it wouldn't be possible to do this with an inital Page_Load.
How about you place a hidden textbox on the page, attach an OnChange-eventhandler to it in C# and use an OnLoad JavaScript function to set the value to the value you need from the client?
As far as I'm aware, there isn't any way to get the users local time in the Page_Load event as that is executed on the server-side, and would therefore only be aware of the server's local date time.
To get the user's local time you would need to either execute an asynchronous call to the server upon the page loading in JavaScript, or store the local time in a hidden field and then read it on post-back.
Or just use an interstitial page that contains nothing but the js to get local time and redirects to your current page passing the time information via query string or session variable or post
Related
In my current project I have to show a Popup(Welcome Info) every time he/she login to the site. In the Popup user have a option(Onclick CheckBox) to hide the Popup for 30days.
I'm achieving this by saving a UserUniqueId to cookie(Which should be an array/list) when he/she click checkBox on popup. As Below
var UniqueId = "xxx";
var uIDCookies = [];
// looping to get all the values that are stored in cookie
$.each($.cookie(), function(i, v) {
uIDCookies.push(i);
});
// if current userUID not found in cookie then showing popup
if (($.inArray(UniqueId, uIDCookies)) === -1) {
//show popup
} else {
// hide popup
}
// create cookie and set expire time
$('.checkBox').on('click', function () {
var date = new Date();
var minutes = 3;
date.setTime(date.getTime() + (minutes * 60 * 1000));
$.cookie(UniqueId, { expires: date, path: '/' });
//hide popup
});
No matter what I'm looping through all cookie values that are stored on client browser so, I feel that there could be a better way to achieve this. Suggestions Please..!!
You are saving the cookie with the UniqueID as the name. Just check if that cookie already exists directly:
if (! $.cookie(UniqueId) ) {
//show popup
} else {
// hide popup
}
This sounds very suspiciously like a very bad design choice, but to answer the question as asked, just serialise the array and convert the string to Base64. Then you can parse it back out again afterwards.
As mentioned in the OP's comments though, there are very few edge cases where this is necessary in the scenario you have mentioned. Also, don't set or get cookies in jQuery. Use your serverside language to gather and set cookie information whereever possible, and send it to the page where needed. Don't use cookies where it would be better to use a data store. You have no control over the cookie information once it has been set, and so they can be a security vector into your application.
Cookies are stored per profile, per browser, per user, per computer, and so aren't always the best way to store this info. Instead, consider adding two columns to your user profile table, DisplayWelcomeMessage as a boolean, and SuppressWelcomeMessageExpiry as a DateTime. That way, the info is set per user, not per cookie. It allows the application to be more scalable, as it gives the user the option to turn it back on before the expiry runs out.
I am creating an online quiz application and need server side timer. For example if the user opens another browser or refresh the page or leave and back time shoud be proper.
Now i am using jquery timer and in every 5 minutes send ajax request to store proper information into the database. Also when the user answers the question i immediately send again ajax requst for the same purpose.
Should i use signalr instead? What would be more proper way to handle server side timer in asp.net mvc?
As long as you have a session, you could simply store the timestamp of when the user began taking the quiz in session state.
You could tell the time of any future event by looking at the timestamp of that event, minus the timestamp of when the user took the survey.
Example (server-side code):
if (Session["startTime"] == null)
{
Session["startTime"] = DateTime.Now;
}
var ticksRemaining = DateTime.Now - Session["startTime"];
// Use ticksRemaining to populate the start value for the count-down timer
// Works just fine even if they reload the page or open a new browser tab.
// You won't catch if they open a brand-new browser and start a new session,
// but that's a different kind of problem.
I have a web form of Asp.Net, in which I want JavaScript to count how many time i have refreshed the page.
If you want to do it on clientside just save (and retrieve) the information on localstorage every time load event occurs
Do you want to count this per user ? Or for whole application ?
If you are doing for whole application you can use application variable in Global.asax on each page request . But that might get lost if your application recycles .
If you want to do for each user You can use server side sessions or cookies on clientside .
You can set the value in a cookie using js or asp, or in a session value (for a single user) or in application value (for all the users), is not necessary javascript.
You have to put this code server side on page load.
For all users:
Application["refresh_count"] =
Convert.ToInt64(HttpContext.Current.Application["refresh_count"]) + 1;
For a single user with session:
Session["refresh_count"] = Convert.ToInt64(Session["refresh_count"]) + 1;
OR
Response.Cookies["UserSettings"]["refresh_count"] = Convert.ToInt64(Response.Cookies["UserSettings"]["refresh_count"]) + 1;
Response.Cookies["UserSettings"].Expires = DateTime.Now.AddDays(1d);
You can save this in the Session Object.
You can use jQuery calling prepared address.
For example:
$.ajax({
url: ".../countPageRefreshes.aspx",
data: { page: "thisPageAddress" }
})
Then, in countPageRefreshes you can increase number of times, page was refreshed and save it somewhere.
I don't know what is going on but this is really evident in IE 8. It loads up my page and my javascript files.
I then have debug lines in my server side code that should get activated when an ajax request from my jquery comes through. Or some other contact with the server such a refreshing the page.
So I have this
var timeout;
var wait = 300000;
$(function()
{
timeout = null;
timeout = setTimeout("SessionTimeOut()", wait);
$.get('SessionTimeOut', null, function(response)
{
timeout = clearTimeout(timeout);
wait = parseInt(response);
timeout = setTimeout("SessionTimeOut()", wait);
});
});
This should run every time the page is loaded and start a timer to monitor if they should be logged out or not. I reset the timer every time they make a request to the server.
Some times when a user logs in they all of a sudden get timed out. So I put a default timer of 5 mins in to see if that would fix the problem.
So now say the user times out since they are inactive for like 30mins. They come back and get sent to my login page. So they are going to a new page. I would hope all this javascript stuff would be destroyed and all the timeout objects would be destroyed.
They then try to log in(Using IE8). Guess what they will get the message that they where timed out since IE8 seems to not want to run this script anymore.
I tried refreshing the page but that does nothing. It seems like once the script has ran it has ran for the entire time the browser is opened.
I have many pages with that uses the code above. Yet once it ran once in one page and you go to another page it won't run again.
The only way to get it to run again is close the browser down or clear all your cache.
So how can I make it run again?
Edit
Here is my server code(well portion of it)
public ContentResult SessionTimeOut()
{
var time = signOut.FigureSessionTime();
// minues 2 mins to make up for any lost time.
double total = time.TotalMilliseconds - 120000;
return Content(total.ToString());
}
So basically the FigureSessionTime out looking inside the users cookie and checks to see if the cookie is by end of session or if they choose to be kept logged in for 2 weeks.
If they choose 2 weeks then 2 weeks worth of milliseconds will be returned back. If it is by session then 30mins of milliseconds will be returned back.
I just take 2 mins of to be on the save side so the client side should always timeout before serverside.
return the time in millseconds
// this is what it returns
1670778.4725000001
Edit 2
Ok so this is what I just did to test some things out.
IE 8
Launched a page that a user does not need to log into. This means no cookie to check there session meaning -120000 will come back. This was verified by an alert box. Since this was like an instant timeout the second that page loaded up I was timed out.
Next I tried to log into a page that was secure and that would take the cookie out check it and return a timeout time back. I had an alert box and checked what was stored in the wait variable.
What the alert box came was -120000 so this should not be. It should be some high number. I was instantly logged out and sent to the login page.
I then went into the "safety tab" in IE 8 and choose "Delete browsing history" a popup came up and I checked all the avaiable options and hit"Delete".
I did this all while being on my site and never left it. So I just typed in my login credentials and logged in.
Now the wait variable has this in it "1677207". So this is like 27mins or something like that.
So why did the first time come back negative? Is it because it first timed out on some other page and cached this or did it just not feel like to work?
I now just tired something else. I cleared the browsing history and closed down IE 8. I then launched my website through VS2008 and loaded it up on my login page.
I then logged in and out 5 times. Each time I logged in I noted the wait time.
This is the results
1678237
1678237
1678237
1678237
1678237
So for 5 times the time was exactly the same not even a millisecond off.
Now lets check firefox.
I did the same thing started my site through VS2008 to launch firefox and go to my signin page.
I logged in 5 times in and out. Each time the alert box came up with the wait time in it I noted it.
This is the results
1677176
1677800
1678003
1677956
1677800
Every single time I logged in it was a different time. So for some reason firefox brought back different results each time but IE8 magically could always do it in the same time not even a millisecond more or less?
I after did what I did before in IE8 I went to a page that would time the user out and return -12000. I went to this page and it did just that and returned me to the sign in page.
I then logged in and the wait time that showed up was "1677940". So it actually went and ran my code and got a different time back. Where IE8 just used the previous -12000 over and over again. I could probably log in a million times and it would always -12000. Once it gets a value it seems to keep that.
Edit 3
You all can try at home now.
Here is what you need
// Javascript file
var timeout;
var wait = 300000;
$(function()
{
timeout = null;
timeout = setTimeout("SessionTimeOut()", wait);
$.get('SessionTimeOut', null, function(response)
{
timeout = clearTimeout(timeout);
wait = parseInt(response);
alert(wait);
timeout = setTimeout("SessionTimeOut()", wait);
});
/* starts every time a ajax request is made */
$().ajaxStart(function(e)
{
timeout = clearTimeout(timeout);
$('body').css('cursor', 'progress');
});
$().ajaxStop(function(e)
{
$('body').css('cursor', null);
});
$().ajaxComplete(function(event, XMLHttpRequest, ajaxOptions)
{
if (timeout == null)
{
timeout = setTimeout("SessionTimeOut()", wait);
}
});
});
// need to have dialog ui javascript for this.
function SessionTimeOut()
{
// $('#content').append('<div id="SessionTimeout" title="Session Time Out">Your session has timed out. You must sigin again.</div>');
// $('#SessionTimeout').dialog(
// {
// height: 140,
// resizable: false,
// modal: true,
// closeOnEscape: false,
// buttons:
// {
// 'Return To Sign In Page': function()
// {
// window.location.href = "/account/signin";
// }
// }
// });
// $('#ui-dialog-title-SessionTimeout').siblings('a').remove();
}
// Index View
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Index</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script src="../../JScript1.js" type="text/javascript"></script>
</head>
<body>
<div>
</div>
</body>
</html>
//TestController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
namespace MvcApplication1.Controllers
{
public class TestController : Controller
{
//
// GET: /Test/
public ActionResult Index()
{
return View();
}
public ContentResult SessionTimeOut()
{
Random random = new Random();
return Content(random.Next(100).ToString());
}
}
}
If you run this code in IE8 you will get the same random number each time. Try it in firefox and you wont.
I had a similar problem recently. Disabling caching for may ajax call cleared it out. Try this guy:
var timeout;
var wait = 300000;
$(function()
{
timeout = null;
timeout = setTimeout("SessionTimeOut()", wait);
$.ajax({
url:'SessionTimeOut',
success:function(response) {
timeout = clearTimeout(timeout);
wait = parseInt(response);
timeout = setTimeout("SessionTimeOut()", wait);
},
type:'get',
cache:false
});
});
notice the cache:false option
Seeing as there is no JQuery and ASP.NET experts speaking up, I'll chip in my €0.02: I doubt this is solely a caching issue. I don't speak JQuery fluently enough to understand what your Ajax call is doing but I have a feeling the problem is there rather than in caching. But I can be wrong there.
Anyway, the easiest way to prevent caching of a Javascript file is to append a random timestamp to the URL:
<script language='script.js?timestamp=1020349302930'>
this will make the script load anew on every instance. If you can use only JS, you can use Math.rand to create the random value and then create or document.write the <script> tags. Or of course, use the server side language of your choice. ( I just saw in your tags that that is ASP.NET)
The cleaner way would be setting the right caching headers either in your server configuraiton, or by sending out headers dynamically inside the JS files (which would have to be parsed by a language like PHP or ASP to do that).
Maybe this gives fresh input in hunting down what's wrong. Good luck!
I agree with Pekka that the problem is more likely not to be in the browser caching.
It looks like you're using the $get call to fetch the timeout value from the server. This seems... odd. If that's not what you're trying to do, then why do you parse the response as the timeout value? If that is what you're trying to do, then are you sure that the response that's returned contains the value that you expect it to contain?
Okay, here is the 411 - I have the following event handler in my Global.asax.cs file:
private void Global_PostRequestHandlerExecute(object sender, EventArgs e)
{
if (/* logic that determines that this is an ajax call */)
{
// we want to set a cookie
Response.Cookies.Add(new HttpCookie("MyCookie", "true"));
}
}
That handler will run during Ajax requests (as a result of the Ajax framework I am using), as well as at other times - the condition of the if statement filters out non-Ajax events, and works just fine (it isn't relevant here, so I didn't include it for brevity's sake).
It suffices us to say that this works just fine - the cookie is set, I am able to read it on the client, and all is well up to that point.
Now for the part that drives me nuts.
Here is the JavaScript function I am using to delete the cookie:
function deleteCookie(name) {
var cookieDate = new Date();
cookieDate.setTime(cookieDate.getTime() - 1);
document.cookie = (name + "=; expires=" + cookieDate.toGMTString());
}
So, of course, at some point after the cookie is set, I delete it like so:
deleteCookie("MyCookie");
Only, that doesn't do the job; the cookie still exists. So, anyone know why?
you have to delete your cookie at the same path where you created it.
so create your cookie with path=/ and delte it with path=/ as well..
Have you checked the client-side and server-side cookie domains and paths to ensure they're the same?
Is one cookie secure and the other not?
Other than that, I would suspect server/client clock sync issues, as Erlend suggests.
Weird.. The code you pasted is almost verbatim to this: http://www.quirksmode.org/js/cookies.html which works fine..
I know you are using Ajax, but have you tried quickly knocking it to server side code to see if that works? This may help in figuring if it is a problem with the JS or something else (e.g mystery file locking on the cookie)?
Update
Just had a quick Google, looks like there may be issues with browser settings as well. I don't think your problem is the code here, it's more likely to be something else. I would suggest try the above as PoC and we can move from there. :)
I posted a js cookie util a week or so ago on my blog. This has worked for me on all "A Grade" browsers.
var CookieUtil = {
createCookie:function(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
},
readCookie:function(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
},
eraseCookie:function(name) {
createCookie(name,"",-1);
}
};
Have you tried to use ;expires=Thu, 01-Jan-1970 00:00:01 GMT?
Also if a cookie domain was specified during the creation, I've found that you must also specify the cookie domain while trying to delete (expire) it.
Are we sure there's no code that sets the Cookie to HttpOnly (we're not missing anything above)? The HttpOnly property will stop (modern) browsers from modifying the cookie. I'd be interested to see if you can kill it server side like Rob suggests.
I assume you are calling this javascript on the browser side. Which browser are you using, how are you viewing the cookie to confirm it is still there?