ASP.NET MVC 2 caching problem - c#

I'm writing an app and have come across caching problem which I cannot work out.
I have a default Home controller for the site which checks whether the user is authenticated or not.
If is not then LogOn View is displayed otherwise the client is redirected to another page.
Along with the LogOn view, also a Check cookie is being sent to user to check on response if his browser supports cookies or not.
When I delete the cookie before sending the form with credentials, Home (Post method) in Home controller displays message that cookies must be enabled with a button which
should refresh the page with Logon boxes(http://localhost:1234/)
This button is linked to js refresh function:
var sURL = unescape("/");
function refresh()
{
window.location.href = sURL;
}
I have implemented CacheFilter which is set on the base controller.
public class NoCache : ActionFilterAttribute, IActionFilter
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.SetNoStore();
base.OnResultExecuting(filterContext);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
base.OnResultExecuted(filterContext);
}
}
and the problem is that if I Immediately click the button to refresh LogOn page, browser read it using its cache. But when I do it after a few seconds then the query is sent to the server.
This is wrong, because LogOn page should also create again a Check cookie.
It seems to me that the cache policy is set to 1-2 seconds, and after this time pages are reloaded from the server.
What is wrong? Thanks for help.

I have seen some similar behaviour, related to the javascript in IE7. The browser 'helpfully' realizes that you've recently requested that URL and therefore serves up the cached version. If this is the case, the solution is to make sure the URL is unique every time by adding a pseudo random number. I use something like:
function refresh()
{
window.location.href = sURL + "?rnd="+ Math.random();
}

Am I right in saying you're testing this by running this in Visual Studio?
As far as I know you can't enable things like caching in the Visual Studio Development Server. This is something you will enable on your webserver, which I guess will be IIS in your case.

Related

Disable Cookieless Session .Net MVC 5

We previously had cookieless session enabled on our application. We have disabled this and gone to session cookies however we are having a problem. Users who had the session ID in their URL as a bookmark are still able to navigate to the site with the session id in the url. I have set it to not regenerate expired sessions but it is still allowing it anyways. It also ends up creating a session cookie in addition and then we are getting random session loss. I've come up with a few wonky workarounds like stripping it out using a URL rewrite and stripping it out via javascript but this seems bad. Is there anything built in that I am missing that can help with this? Not that it should matter for this but I will add we are using state server.
For anyone else looking for a solution that won't require users to update their bookmarks I was able to use the following in my Global.asax Application_BeginRequest:
void Application_BeginRequest(object sender, EventArgs e) {
if (CookielessValuesExist()) {
Response.Redirect(Request.Url.OriginalString, true);
}
}
private bool CookielessValuesExist() {
string cookieless = Request.Params["HTTP_ASPFILTERSESSIONID"];
if (string.IsNullOrWhiteSpace(cookieless)) {
return false;
}
return true;
}
A URL rewrite is a good solution to this.
However if you would like users to update their bookmarks, (so you can eventually retire the URL rewrite) you might consider having your URL rewrite send them to a page telling them so:
Oops! That link doesn't work.
And then giving them the usual options to log in etc.

POSTing Ajax form using [Authorize] attribute after the user is logged out ASP.NET

Intro
I am building a WebApp for a client using ASP.NET MVC in C#.
I have an Ajax form within a modal window, that gets submitted when the user clicks a button.
The user has to be logged in, in order to be on this particular page and do this particular action - so I'm using the [Authorize] attribute for the necessary controller actions.
Let's say the controller action the form is POSTing to looks like this (psuedo-code, just an example):
[Authorize]
public ActionResult DoAjaxThings(string field, string anotherfield)
{
// ... do things
if (success)
{
return Json(new { success = true });
}
else
{
return Json(new { success = false, error = "Something went wrong" });
}
}
As you can see I return a Json object back with a success property and an error if necessary.
This is then handled by the callback method in the page, and off it goes to show spinners and unicorns and other magic.
If successful, the modal is closed and a "success" message is shown.
If not successful and an error is returned, an error div is filled with the error message I send back. Sounds fairly straightforward?..
Scenario
Let's say the user's session token only lasts 15 minutes - and is sliding (each new request resets it (not necessarily vital to the question)). They're not using the "remember me" option.
If they've been idle/sitting on a page for more than the allotted time, then the token runs out.
Obviously, by this point their session token has expired, and they will need to log in again.
Usual behaviour would occur when navigating to [Authorize] controller actions: taking the user back to the Login page, with the ReturnUrl=xyz query string.
Imagine This
So, back to the modal's Ajax form.
User has been on the page for 15 minutes, and their token has now expired.
They click the button to perform the [Authorize]d action...
The the Action method is not executed, and the WebApp returns a redirect to the Login page.
But what is returned through this Ajax call is the ENTIRE Login page. And seeing as there is no success, the callback function receives the redirect, which squashes the Login page - all into this one little tiny div.
You don't need me to tell you that this looks fudging hideous.
Question
It is clear to see that WebApp realises the [Authorize] attribute and that the user is logged out.
I can't hit any breakpoints inside the Action, because the [Authorize] takes over and redirects automatically.
So, what I ask is this:
How can I bypass/overcome/solve this issue with the [Authorize] being triggered first and the Action code block not being executed?
Your kind suggestions, answers and general guidance are appreciated, as always.
You could remove the [Authorize] attribute, check the authorization in your controller method (if (User.Identity.IsAuthenticated)), and return a suitable error to the client if the user is not authorized.
you can create a custom attribute, so you can redirect them to the login controller, to whatever you want to do.what I did is return them to my accessdenied action. thru ajax redirect when an ajax onerror occurs.
public class ApiAuthAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
var urlHelper = new UrlHelper(filterContext.RequestContext);
filterContext.HttpContext.Response.StatusCode = 403;
filterContext.Result = new JsonResult
{
Data = new
{
Error = "NotAuthorized",
LogOnUrl = urlHelper.Action("AccessDenied", "Login")
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}
}
check this answer redirects to login if unauthorized ajax call

How to urge a user to update the user's browser when entering a web site

I'm wondering if there is some way to "force" a user to update the user's web browser.
For instance, if a user enters my site and he or she is using an old version of a browser, an area of the page that is ordinarily hidden will be revealed. And that revealed area will contain a browser update recommendation and a hyperlink to an external page where the user can download a new version of the user's browser or update the current version.
Specifically, here are the two aspects of my goal for which I need guidance:
How to recognize the browser and it's version, and
How to show a hidden area specific to the browser the user is currently using. (Maybe there will be an area for each type of common browser, so the question would be how to show the associated area.)
In my research I came across this site which offers a small JavaScript-based notification component:
http://browser-update.org/index.html
This is exactly what I was looking for.
You can for example do this in ActionFilterAttribute. For example it can look like following:
public class WarnAboutOldBrowserAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.HttpContext.Request;
//check if it browser warning was already checked
if (request.Cookies["checked"] != null)
{
return;
}
//exmaple is for IE 6
if (request.Browser.Browser.Trim().ToUpperInvariant().EqualsExact("IE") && request.Browser.MajorVersion <= 6)
{
filterContext.Controller.ViewData["RequestedUrl"] = request.Url.ToString();
filterContext.Result = new ViewResult { ViewName = "OldBrowserWarning" };
}
//add cookie for caching
filterContext.HttpContext.Response.AppendCookie(new HttpCookie("checked", "true"));
}
}
}
Of course you have to add also a view called "OldBrowserWarning" to display information to user.
Other way is to add warning in _Layout.cshtml and in above code set proper flag in ViewBag

Is this possible to clear the session whenever browser closed in asp.net?

In my asp.net application, i want to clear the session whenever my browser closed or my tab (if my browser containing multiple tabs)closed.
Please guide me to get out of this issue...
Short version, No.
There's no solid way of a server detecting if the client has closed their browser. It's just the nature of web development's asynchronous pattern.
Long version, if it's really, really important to you;
Put a bit of javascript in the page that sends a regular post to your website in the background and set up a serverside agent or service that disposes of the sessions if it doesnt receive these regular "heartbeat" signals.
You can put a javascript postback onto the page's unload() event but dont rely on it, it doesnt always fire.
This happens by default whenever you close your browser, and that's not just for ASP.NET. It's for most server-side programming languages that have a session state. Basically, any cookie that is added that doesn't specify an expiration date, will be deleted when the browser is closed.
Where this doesn't apply, is when you close a tab, which is something you will not have any control over because the tab close event will not get sent back to the Web server.
You can try to do that with javascript. Check it at:
http://www.codeproject.com/Tips/154801/How-to-end-user-session-when-browser-closed
Alternatively you can check you previous session state on every new browser opening and can Session.clear() or Session.abandon() the previous session.
this will make sure that every time you start application you will get new session.
use BasePage in your .net application.
Check the session.sessionid on basepage load.
More Inforamtion how to detect new session in basepage. BasePage.Session.Link
Hope this helps
regards
Shaz
public class BasePage : Page
{
protected string mySessionId;
private CurrentUser _currentUser;
public CurrentUser _CurrentUser
{
get { return ((CurrentUser)HttpContext.Current.Session["myCurrentUser"]); }
set { _currentUser = value; }
}
protected override void OnLoad(EventArgs e)
{
if (Session["myCurrentUser"] != null)
{
if (_CurrentUser.ProUser)
{
mySessionId = Session.SessionID; // it means New Session
}
if (!mySessionId.IsNullOrDefault() && mySessionId != Session.SessionID)
{
Session.Abandon(); //Abandon current session and start new one
}
}
}
}
I think cookies can better meet your requirement here for session management.
it means that session data should not be stored on the server and
should be with your call, so that you don't have to worry about
clearing the data on server.
Yes.First of all Browser automatically clear session when browser is closed. you can try to capture browser close or tab close event in browser using javascript function like on before unload and on unload. Mostly onbefore unload event captures browser close event in chrome, Firefox, IE 11.
You can use Session_End event of Global.aspx
//For Specific Session
Session.Remove("SessionName");
//All the Session
Session.Abandon();

How can I handle forms authentication timeout exceptions in ASP.NET?

If the session has expired and the user clicks on a link to another webform, the asp.net authentication automatically redirect the user to the login page.
However, there are cases when the user does not click on links to other webforms. For example: edit link in gridviews, when using AutoCompleteExtender with textboxes and the application attempts to get the information, and basically, in every case when a postback is done and the event is not automatically handled by the asp.net authentication.
What is the best way to handle these exceptions?
UPDATE: I have just modified the question title: forms authentication timeout, instead of the initial session timeout. Thanks for making me aware of this difference.
UPDATE: I have just created a new question with the specific problem I am facing: How to handle exception due to expired authentication ticket using UpdatePanel?. Surprisingly, I have not found much information about it. I would really appreciate your help.
This is why many systems include timers on the page to give approximate timeout times. This is tough with interactive pages. You really need to hook ajax functions and look at the return status code, which is a bit difficult.
One alternative is to use code based on the following which runs early in the page lifecycle and perform an ajax redirect to a login page. Otherwise you are stuck trying to intercept the return code from ajax and in asp.net where the ajax is done 'for you' (ie not a more manual method like jQuery) you lose this ease of detection.
http://www.eggheadcafe.com/tutorials/aspnet/7262426f-3c65-4c90-b49c-106470f1d22a/build-an-aspnet-session-timeout-redirect-control.aspx
for a quick hack you can try it directly in pre_init
http://forums.asp.net/t/1193501.aspx
Edit
what is wanted are for forms auth timeouts, not session timeouts. Forms auth timeouts operate on a different scale than session timeouts. Session timeouts update with every request. Forms auth tickets aren't actually updated until half of the time goes by. So if you have timeouts set to an hour and send in one request 25 minutes into it, the session is reset to an hour timeout, the forms auth ticket isnt touched and expires in 35 minutes! To work around this, sync up the session timeout and the forms auth ticket. This way you can still just check session timeouts. If you don't like this then still - do the below and sync up the timeouts and then parse the auth ticket and read its timeout. You can do that using FormsAuthentication.Decrypt - see:
Read form authentication cookie from asp.net code behind
Note that this code requires that upon login you set some session value - in this case its "UniqueUserId". Also change the login page path below to fit yours.
protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
//Only access session state if it is available
if (Context.Handler is IRequiresSessionState || Context.Handler is IReadOnlySessionState)
{
//If we are authenticated AND we dont have a session here.. redirect to login page.
HttpCookie authenticationCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authenticationCookie != null)
{
FormsAuthenticationTicket authenticationTicket = FormsAuthentication.Decrypt(authenticationCookie.Value);
if (!authenticationTicket.Expired)
{
if (Session["UniqueUserId"] == null)
{
//This means for some reason the session expired before the authentication ticket. Force a login.
FormsAuthentication.SignOut();
Response.Redirect("Login.aspx", true);
return;
}
}
}
}
}
If you're using Forms Authentication, the user will be redirected to the login page when the Forms Authentication ticket expires, which is not the same as the Session expiring.
You could consider increasing the Forms Authentication timeout if appropriate. Even to the extent of using a persistent cookie. But if it does expire, there's no real alternative to redirecting to the login page - anything else would be insecure.
One way to deal with Session timeouts is to use Session as a cache - and persist anything important to a backing store such as a database. Then check before accessing anything in Session and refresh if necessary:
MyType MyObject
{
get
{
MyType myObject = Session["MySessionKey"] as MyType
if (myObject == null)
{
myObject = ... get data from a backing store
Session["MySessionKey"] = myObject;
}
return myObject;
}
set
{
Session["MySessionKey"] = value;
... and persist it to backing store if appropriate
}
}
If you're using a master page or a base page, I would add some logic to one of the events in the page lifecycle to check whether the session is new:
protected void Page_Load(object sender, EventArgs e)
{
if (Session.IsNewSession)
{
//do whatever you need to do
}
}

Categories