ASP.NET Push Redirect on Session Timeout - asp.net

I'm looking for a tutorial, blog entry, or some help on the technique behind websites that automatically push users (ie without a postback) when the session expires. Any help is appreciated

Usually, you set the session timeout, and you can additionally add a page header to automatically redirect the current page to a page where you clear the session right before the session timeout.
From http://aspalliance.com/1621_Implementing_a_Session_Timeout_Page_in_ASPNET.2
namespace SessionExpirePage
{
public partial class Secure : System.Web.UI.MasterPage
{
public int SessionLengthMinutes
{
get { return Session.Timeout; }
}
public string SessionExpireDestinationUrl
{
get { return "/SessionExpired.aspx"; }
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
this.PageHead.Controls.Add(new LiteralControl(
String.Format("<meta http-equiv='refresh' content='{0};url={1}'>",
SessionLengthMinutes*60, SessionExpireDestinationUrl)));
}
}
}
The SessionExpireDestinationUrl should link to a page where you clear the session and any other user data.
When the refresh header expires, it will automatically redirect them to that page.

You can't really "push" a client from your website. Your site will respond to requests from the client, but that's really it.
What this means is that you need to write something client-side (Javascript) that will determine when the user has timed out, probably by comparing the current time with the most recent time they have in a site cookie (which you update with the current time each time the user visits a page on your site), and then redirect if the difference is greater than a certain amount.
(I note that some people are advocating just creating a script that will forward the user after a certain amount of time on a page. This will work in the simple case, but if the user has two windows open on the site, and is using one window a lot, and the other window not-so-much, the not-so-much one will suddenly redirect the user to the forwarding page, even though the user has been on the site constantly. Additionally, it's not really in sync with any session keeping you're doing on the server side. On the other hand, it's certainly easier to code, and if that's good enough, then great!)

In the <HEAD> section, use a META refresh tag like this:
<meta http-equiv="refresh" content="0000; URL=target_page.html">
where 0000 is your session timeout in seconds, and target_page.html the address of the page to be redirected to.

Using Custom Page class and Javascript also we can achieve it.
Create a custom pagebase class and write the common functionality codes into this class. Through this class, we can share the common functions to other web pages. In this class we need inherit the System.Web.UI.Page class. Place the below code into Pagebase class
PageBase.cs
namespace AutoRedirect
{
public class PageBase : System.Web.UI.Page
{
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
AutoRedirect();
}
public void AutoRedirect()
{
int int_MilliSecondsTimeOut = (this.Session.Timeout * 60000);
string str_Script = #"
<script type='text/javascript'>
intervalset = window.setInterval('Redirect()'," +
int_MilliSecondsTimeOut.ToString() + #");
function Redirect()
{
window.location.href='/login.aspx';
}
</script>";
ClientScript.RegisterClientScriptBlock(this.GetType(), "Redirect", str_Script);
}
}
}
Above AutoRedirect function will be used to redirect the login page when session expires, by using javascript window.setInterval, This window.setInterval executes a javascript function repeatedly with specific time delay. Here we are configuring the time delay as session timeout value. Once it’s reached the session expiration time then automatically executes the Redirect function and control transfer to login page.
OriginalPage.aspx.cs
namespace appStore
{
public partial class OriginalPage: Basepage
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
}
OriginalPage.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeFile="OriginalPage.aspx.cs" Inherits="AutoRedirect.OriginalPage" %>
Web.config
<system.web>
<sessionState mode="InProc" timeout="3"></sessionState>
</system.web>
Note:
The advantage of using Javascript is you could show custom message in alert box before location.href which will make perfect sense to user.
In case if you don't want to use Javascript you could choose meta redirection also
public void AutoRedirect()
{
this.Header.Controls.Add(new LiteralControl(
String.Format("<meta http-equiv='refresh' content='{0};url={1}'>",
this.Session.Timeout * 60, "login.aspx")));
}

Just copy and paste this code snippet in your Web.Config file :
<authentication mode="Forms">
<forms loginUrl="~/Login.aspx" slidingExpiration="true" timeout="29" />
</authentication>
<sessionState timeout="30" mode="InProc" cookieless="false" />
You can put this line to your Site.Master :
Response.AppendHeader("Refresh",
Convert.ToString((Session.Timeout * 60)) +
";URL=~/Login.aspx");

I'm using MVC3 ASp.net as beginner, I tried many solution to solve my session problem ( since i'm using Session variable in my code, and after timeout i didn't have session values while i'm keep using it And I just find that my problem was in config file. the timeout between Authentication and sessionState should be so close. so they Killed (empty) at the same time // add timeout 1 and 2 for testing.. it's should be at least 29 and 30
I used others way it's work too :
Starting from :
protected void Session_Start(object src, EventArgs e)
{
if (Context.Session != null)
{
if (Context.Session.IsNewSession)//|| Context.Session.Count==0)
{
string sCookieHeader = Request.Headers["Cookie"];
if ((null != sCookieHeader) && (sCookieHeader.IndexOf("ASP.NET_SessionId") >= 0))
{
//if (Request.IsAuthenticated)
FormsAuthentication.SignOut();
Response.Redirect("/Account/LogOn");
}
}
}
}
protected void Session_End(object sender, EventArgs e)
{
//Code that runs when a session ends.
//Note: The Session_End event is raised only when the sessionstate mode
//is set to InProc in the Web.config file. If session mode is set to StateServer
//or SQLServer, the event is not raised.
Session.Clear();
}
And :
public class SessionExpireFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
// check if session is supported
if (ctx.Session != null)
{
// check if a new session id was generated
if (ctx.Session.IsNewSession)
{
// If it says it is a new session, but an existing cookie exists, then it must
// have timed out
string sessionCookie = ctx.Request.Headers["Cookie"];
if ((null != sessionCookie) && (sessionCookie.IndexOf("ASP.NET_SessionId") >= 0))
{
ctx.Response.Redirect("~/Home/LogOn");
}
}
}
base.OnActionExecuting(filterContext);
}
}
And even worked with Ajax to solve session issuse:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (Session.Count == 0 || Session["CouncilID"] == null)
Response.Redirect("/Account/LogOn");
if (Request.IsAjaxRequest() && (!Request.IsAuthenticated || User == null))
{
filterContext.RequestContext.HttpContext.Response.StatusCode = 401;
}
else
{
base.OnActionExecuting(filterContext);
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorizeUserAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (!httpContext.Request.IsAjaxRequest())
{//validate http request.
if (!httpContext.Request.IsAuthenticated
|| httpContext.Session["User"] == null)
{
FormsAuthentication.SignOut();
httpContext.Response.Redirect("~/?returnurl=" + httpContext.Request.Url.ToString());
return false;
}
}
return true;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new JsonResult
{
Data = new
{
// put whatever data you want which will be sent
// to the client
message = "sorry, but you were logged out"
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}

Unfortunately it can't be done. The session timeout only occurs on the server side and you won't detect this until the user performs some kind of post back action.
However, what you CAN do is to inject some HTML or JavaScript header code that will automatically push the user to a logout page in the same timeframe as your session timeout. This doesn't guarantee a perfect synch, and you may run into issues if your user is doing some time intensive items and you are not resetting the clock.
I typically add this code to my Page_Load events to accomplish this.
' Register Javascript timeout event to redirect to the login page after inactivity
Page.ClientScript.RegisterStartupScript(Me.GetType, "TimeoutScript", _
"setTimeout(""top.location.href = 'Login.aspx'""," & _
ConfigurationManager.AppSettings("SessionTimeoutMilliseconds") & ");", True)

And if you use the following Logon controller, it will send you to the requested URL before logon:
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
//return Redirect(returnUrl);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}

Of course you need to use [Authorize] over controller class or even Action in specific.
[Authorize]
public class MailController : Controller
{
}

Well this gets tricky for AJAX requests as Zhaph - Ben Duguid pointed out. Here was my solution to make this work with AJAX (using Telerik web controls but they are built using ASP.NET AJAX toolkit I believe).
In a nutshell, I rolled my own sliding expiration session type thing.
In my Site.Master, I am updating a session variable on EVERY postback (postback or AJAX request because AJAX requests still kick off the Page_Load event):
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
if (this.Request.IsAuthenticated)
this.pnlSessionKeepAlive.Visible = true;
else
this.pnlSessionKeepAlive.Visible = false;
}
if (this.Session["SessionStartDateTime"] != null)
this.Session["SessionStartDateTime"] = DateTime.Now;
else
this.Session.Add("SessionStartDateTime", DateTime.Now);
}
Then in my markup for my site.master, I included an iframe with a ASPX page I use "behind the scenes" to check and see if my custom sliding expiration has expired:
<asp:Panel runat="server" ID="pnlSessionKeepAlive" Visible="false">
<iframe id="frame1" runat="server" src="../SessionExpire.aspx" frameborder="0" width="0" height="0" / >
</asp:Panel>
Now in my SessionExpire.aspx page, I just refresh the page every so often and check if the timestamp has lapsed and if so, I redirect to my logout.aspx page that then determines which login page to send the user back to:
public partial class SessionExpire : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
/* We have to do all of this because we need to redirect to 2 different login pages. The default .NET
* implementation does not allow us to specify which page to redirect expired sessions, its a fixed value.
*/
if (this.Session["SessionStartDateTime"] != null)
{
DateTime StartTime = new DateTime();
bool IsValid = DateTime.TryParse(this.Session["SessionStartDateTime"].ToString(), out StartTime);
if (IsValid)
{
int MaxSessionTimeout = Convert.ToInt32(ConfigurationManager.AppSettings["SessionKeepAliveMins"]);
IsValid = (DateTime.Now.Subtract(StartTime).TotalMinutes < MaxSessionTimeout);
}
// either their session expired or their sliding session timeout has expired. Now log them out and redirect to the correct
// login page.
if (!IsValid)
this.Logout();
}
else
this.Logout();
// check every 60 seconds to see if the session has expired yet.
Response.AddHeader("Refresh", Convert.ToString(60));
}
private void Logout()
{
this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "TimeoutScript",
"setTimeout(\"top.location.href = '../Public/Logout.aspx'\",\"1000\");", true);
}
}
Many thanks to the people above who posted info, this lead me to my solution and hope it helps others.

Related

handling sessions on every page of website

I have a data driven website and the current users Id gets stored in Session["UserId"].So all the data that shows up in almost all the pages is user specific.and when a user is using the site anonymously,it is a different set of results that i show and has nothing to do with the UserId.
My problem is I have to check if the Session["UserId"] is not null at every line where I am using Session["UserId"] and i somehow feel that it is not the right way to do it.
Is there a way where I can check if the Session is not null on page_load? If my session turns out to be null, how do i handle it? the page won't even load at all.
I hope i was able to explain
Instead of check session on every of your pages, put the session control in a base class and make all your pages extends this class. Every time your page inits the Page_Init base method will check if user is authenticated. If it's not authenticated the method will throw an exception that will be catched by Page_Error method. This method will clear session resources and redirect to Default page.
Make a hyerarchical classes for session control:
public class UserSession { }
public class AnonymousSession : UserSession {}
On your Page Logon put the UserId on the session based on logon type:
bool isAnon = GetAnonymous(); // Check form page if login is anonymously
UserSession user;
if(isAnon)
user = new AnonymousSession();
else
user = new UserSession();
Session.Contents.Add("UserId", user);
Set a property in PageBase named Anonymously that tells you if user has entered anonymously, and use it in your pages to set the set results of each of your pages:
public class PageBase: System.Web.Ui.Page
{
// Check here if session type is anonymous
protected bool Anonymously
{
get
{
return (UserSession)Session.Contents["UserId"] is AnonymousSession;
}
}
protected void Page_Init(object Sender,System.EventArgs e)
{
var user = (UserSession)Session.Contents["UserId"];
if (user == null)
{
throw new SessionException();
}
}
protected void Page_Error(object sender, System.EventArgs e)
{
Exception ex = Server.GetLastError();
Server.ClearError();
if(ex is SessionException)
{
Context.Session.Clear();
Context.Session.Abandon();
FormsAuthentication.SignOut();
Server.Transfer("Default.aspx", true);
}
}
}

Session management in Visual Studio 2013?

Im new developer in asp.net. I want to make a Session management that if 10 minutes passes without any action, the system will end the session and logout the user.
I searched about it and I found this code:
In Web.config file:
<sessionState
mode="InProc"
cookieless="true"
timeout="10" />
And in the page we want to end the session:
public int Timeout { get; set; }
But when I tried it, it didn't work!
I don't not know should I try it in a server rather than localhost or this code does not satisfy the purpose that I need ?
try
public class PageBase : System.Web.UI.Page
{
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
AutoRedirect();
}
public void AutoRedirect()
{
int int_MilliSecondsTimeOut = (this.Session.Timeout * 60000);
string str_Script = #"
<script type='text/javascript'>
intervalset = window.setInterval('Redirect()'," + int_MilliSecondsTimeOut.ToString() + #");
function Redirect()
{
alert('Your session has been expired and system redirects to login page now.!\n\n');
window.location.href='/login.aspx';
}
</script>";
ClientScript.RegisterClientScriptBlock(this.GetType(), "Redirect", str_Script);
}
}
Read more How to do auto logout and redirect to login page when session expires using asp.net?
Auto redirect to login page when Session is expired
Try this in page load
HttpContext.Current.Session.Abandon();
HttpContext.Current.Response.Cookies.Clear();
Authentication.SignOut();
Response.Redirect("~/Login.aspx");

Response.Redirect() doesn't work

I have Default.aspx page, which inherits from BasePage.cs, which inherits from System.Web.UI.Page. BasePage is where I check if the session has timed out. When the session has timed out and the user clicks on something, I need to redirect the user back to the "Main.aspx" page.
Here is the code in my Basepage
override protected void OnInit(EventArgs e)
{
base.OnInit(e);
if (Context.Session != null)
{
if (Session.IsNewSession)
{
string cookie = Request.Headers["Cookie"];
if ((null != cookie) && (cookie.IndexOf("ASP.NET_SessionId") >= 0))
{
HttpContext.Current.Response.Redirect("Main.aspx", true);
return;
}
}
}
}
HttpContext.Current.Response.Redirect("Main.aspx", true);
I want the redirect to stop execution of BasePage and immediately jump out. The problem is, it doesn't.
When I run in debug mode, it contines stepping through as though it didn't just redirect and leave.
How can I safely redirect?
Seeing that your base class is inheriting from System.Web.UI.Page, you don't need to use HttpContext. Try it without and see if it helps.
EDIT: Added page check around response.redirect
if (!Request.Url.AbsolutePath.ToLower().Contains("main.aspx"))
{
Response.Redirect("<URL>", false);
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
I don't think it's exactly what you are looking for but maybe this would work:
Server.Transfer("<URL>")
I struggled with the same problem but on Asp.Net MVC 3.0.
Response.Redirect simply did not work, so I found simple way to use RedirectToAction method that can be inherit from Controller.
public class SessionExpireFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext context = HttpContext.Current;
if (context.Session != null) // check if session is supported
{
if (context.Session.IsNewSession) // if it says it is a new session, but exisitng cookie exists that means session expired
{
string sessionCookie = context.Request.Headers["Cookie"];
if ((sessionCookie != null) && (sessionCookie.IndexOf("ASP.NET_SessionId") >= 0))
{
string redirectTo = "~/Account/Expired";
filterContext.Result = new RedirectResult(redirectTo);
}
}
else
{
base.OnActionExecuting(filterContext);
}
}
}
}
This works fine for Asp.Net MVC, but that might give an idea of using something else than Response.Redirect.
some time your page has an error and you not see it
please check this code below
HttpContext.Current.ClearError();
HttpContext.Current.Response.Redirect("your destination url", false);

ASP.Net MVC 3 Strange Session Behaviour

I have an mvc 3 app for which I'm implementing authorization using my own login view which checks if the users name and password are allowed and then sets a variable in the session to say that the user is loggged in. This kind of works but for one particular view it is behaving in a strange undesirable way. The said view contains a form which I use to input some data and upload a file. For some reason which I can't figure out, after this form is posted a new session is started and therefore the variable which remembered that the user was logged in is reset to false and subsequently the login page is displayed again.
I'm lost as to why the application is starting a new session at this point? I have not instructed it to do this. Can anyone recommend solutions to stop this behaviour and get it to keep the old session?
Thanks.
UPDATE - Some Code:
Note the session seems to be terminated immediately after the response to the posted Create form
CMS controller which uses a custom Autorize attribute called "RDAutorize" on all actions:
[RDAuthorize]
public class PhotoCMSController : Controller
{
public ActionResult Create()
{
/* Code omitted: set up a newPhoto object with default state */
/* Display view containing form to upload photo and set title etc. */
return View("../Views/PhotoCMS/Create", newPhoto);
}
[HttpPost]
public ContentResult Upload(int pPhotoId)
{
/* Code ommited: receive and store image file which was posted
via an iframe on the Create view */
string thumbnail = "<img src='/path/to/thumb.jpg' />";
return Content(thumbnail);
}
[HttpPost]
public ActionResult Create(string pPhotoTitle, string pCaption etc...)
{
/*Code omitted: receive the rest of the photo data and save
it along with a reference to the image file which was uploaded
previously via the Upload action above.*/
/* Display view showing list of all photo records created */
return View("../Views/PhotoCMS/Index", qAllPhotos.ToList<Photo>());
/* **Note: after this view is returned the Session_End() method fires in
the Global.asax.cs file i.e. this seems to be where the session is
being lost** */
}
}/*End of CMS Controller*/
Custom Authorize action filter:
public class RDAuthorize : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Boolean authorized = Convert.ToBoolean(
HttpContext.Current.Session["UserIsAuthorized"]
);
if (!authorized) {
/* Not logged in so send user to the login page */
filterContext.HttpContext.Response.Redirect("/Login/Login");
}
}
public override void OnActionExecuted(ActionExecutedContext filterContext) {}
public override void OnResultExecuting(ResultExecutingContext filterContext) {}
public override void OnResultExecuted(ResultExecutedContext filterContext) {}
}/*End of Authorize Action Filter*/
Login controller:
public class LoginController : Controller
{
private PhotoDBContext _db = new PhotoDBContext();
public ActionResult Login()
{
string viewName = "";
Boolean authorized = Convert.ToBoolean(Session["UserIsAuthorized"]);
if (authorized)
{
viewName = "../Views/Index";
}
else
{
viewName = "../Views/Login/Login";
}
return View(viewName);
}
[HttpPost]
public ActionResult Login(string pUsername, string pPassword)
{
string viewName = "";
List<Photo> model = new List<Photo>();
var qUsers = from u in _db.Users
select u;
foreach (User user in qUsers.ToList<User>())
{
/* If authorized goto CMS pages */
if (pUsername == user.Username && pPassword == user.Password)
{
Session["UserIsAuthorized"] = true;
var qPhotos = from p in _db.Photos
where p.IsNew == false
select p;
model = qPhotos.ToList<Photo>();
viewName = "../Views/PhotoCMS/Index";
break;
}
}
return View(viewName, model);
}
}/* End of Login controller */
Turns out the whole ASP.Net application was restarting because as part of the photo upload I was storing the image file in a temporary folder and then deleting the directory after moving the file to a permanent location. Apparently its default behaviour for ASP.Net to restart if a directory within the web site is deleted. I found this post
which describes the problem and offers a solution whereby the following code is added to the Global.asax.cs file. Implementing this solution has fixed the problem. The fix is applied by calling FixAppDomainRestartWhenTouchingFiles() from the Application_Start() event:
protected void Application_Start()
{
FixAppDomainRestartWhenTouchingFiles();
}
private void FixAppDomainRestartWhenTouchingFiles()
{
if (GetCurrentTrustLevel() == AspNetHostingPermissionLevel.Unrestricted)
{
/*
From: http://www.aaronblake.co.uk/blog/2009/09/28/bug-fix-application-restarts-on-directory-delete-in-asp-net/
FIX disable AppDomain restart when deleting subdirectory
This code will turn off monitoring from the root website directory.
Monitoring of Bin, App_Themes and other folders will still be
operational, so updated DLLs will still auto deploy.
*/
PropertyInfo p = typeof(HttpRuntime).GetProperty(
"FileChangesMonitor", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
object o = p.GetValue(null, null);
FieldInfo f = o.GetType().GetField(
"_dirMonSubdirs", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.IgnoreCase);
object monitor = f.GetValue(o);
MethodInfo m = monitor.GetType().GetMethod(
"StopMonitoring", BindingFlags.Instance | BindingFlags.NonPublic);
m.Invoke(monitor, new object[] { });
}
}
private AspNetHostingPermissionLevel GetCurrentTrustLevel()
{
foreach (AspNetHostingPermissionLevel trustLevel in
new AspNetHostingPermissionLevel[] {
AspNetHostingPermissionLevel.Unrestricted,
AspNetHostingPermissionLevel.High,
AspNetHostingPermissionLevel.Medium,
AspNetHostingPermissionLevel.Low,
AspNetHostingPermissionLevel.Minimal }
)
{
try
{
new AspNetHostingPermission(trustLevel).Demand();
}
catch (System.Security.SecurityException)
{
continue;
}
return trustLevel;
}
return AspNetHostingPermissionLevel.None;
}
Since sessions are associated with cookies, they are available for a specific domain.
It's a common mistake to ask for a session variable in the same application while the domain has changed (i.e. redirecting to a subdomain).
Does the controller action that you are posting the form contains any [Authorize] attribute. You need to post some code.
Verify a new session is really started every time. Check Trace output for the user's session id to ensure it realllly has changed.
Ensure the cookie getting sent over is actually getting set and sent over. (called ASPsessionIDSOMETHING ) and if that is being sent by the browser. Download the tool Fiddler to check the cookies easily (set cookie header coming from the server and the request cookies going back to the server from the browser. Make sure your browser is accepting the cookie and you dont say... have cookies turned off.
If your session id is changing at every request then your session isn't properly getting set the first time, set a break point on that code if you havent already.
You can log when the worker process resets - ensure that isn't the case. see http://www.microsoft.com/technet/prodtechnol/windowsserver2003/library/IIS/87892589-4eda-4003-b4ac-3879eac4bf48.mspx
I had the same problem. The problem only occured when a post request was send to the server and the session was not modified during that request. What I did as a workaround was, to write a custom filter which does nothing more than writing a key / value into the session on each request and added that filter to the GlobalFilter collection in the global.asax.
public class KeepSessionAlive : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext filterContext)
{
if(filterContext.HttpContext.Session != null)
{
filterContext.HttpContext.Session["HeartBeat"] = DateTime.Now.ToShortDateString();
}
}
public void OnActionExecuted(ActionExecutedContext filterContext) { }
}
And in the global.asax:
protected override void AddCustomGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new KeepSessionAlive());
}
This might be not the best solution but it helped me in my case.

ASP.NET SSL - issue is the postback, so OnInit etc won't work

When should I enforce SSL for secure pages in an ASP.NET page life-cycle?
I mean should I do it inside page_load? or OnInit? or some other function?
I am using the following code to enforce SSL for certain pages, but where should I put this code? Earlier I placed it inside OnInit function, but that did not work well with ASP.NET wizards. Do I need to check whether it's postback or not first?
If postback drops https, shouldn't my code enforce it? If postback does not drop https, shouldn't my code stop redirecting and move to the next step of the wizard? It seems like it keeps redirecting.
if (!HttpContext.Current.Request.IsSecureConnection) {
HttpContext.Current.Response.Redirect(SiteNavigation.ResolveAbsoluteUrl(true, HttpContext.Current.Request.Url.PathAndQuery));
}
You have basically two options.
If you want all authenticated pages to run under SSL, you can set the requireSSL="true" attribute on forms authentication. Just make sure your login page is also running on HTTPS.
You can also set this on a page-by-page basis. I found this works well in a "page base" class that inherits from System.Web.UI.Page, and that all your pages inherit from (instead of System.Web.UI.Page).
public class PageBase : System.Web.UI.Page
{
public bool RequiresSSL {get; set;}
string currentPage = Request.Url.ToString();
public PageBase()
{
Init += new EventHandler(PageBase_Init);
}
void PageBase_Init(object sender, EventArgs e)
{
if ((RequiresSSL) && (WebConfigurationManager.AppSettings["SSLavailable"] == "true"))
{
if (currentPage.ToLower().StartsWith("http://"))
{
redirectTo = "https://" + currentPage.Substring(7);
Response.Redirect(redirectTo);
}
}
else
{
if (currentPage.ToLower().StartsWith("https://"))
{
redirectTo = "http://" + currentPage.Substring(8);
Response.Redirect(redirectTo);
}
}
}
}
The AppSettings value of SSLavailable allows you to switch the whole mechanism off when you're running in test mode without SSL.
For pages that need to run in SSL mode, all they need to do is set RequiresSSL:
public partial class ChangePassword : PageBase
{
public ChangePassword()
{
PreInit += new EventHandler(ChangePassword_PreInit);
}
void ChangePassword_PreInit(object sender, EventArgs e)
{
RequiresSSL = true;
}
}
It works, very smoothly, and any other pages they go to after the secure page will automatically switch back to HTTP protocol.
I usually do this in the OnPreLoad event to force SSL:
protected override void OnPreLoad(EventArgs e)
{
base.OnPreLoad(e);
String qs;
qs = Request.QueryString;
//// Force the page to be opened under SSL
if (!Request.IsSecureConnection)
{
if (qs != "")
{
qs = "?" + qs;
}
Response.Redirect("https://" +
Request.ServerVariables["SERVER_NAME"].ToString() +
Request.ServerVariables["PATH_INFO"].ToString() + qs);
}
}
If you want to force SSL for all pages, it may be a good fit for an HttpModule. I have come up with the following:
using System;
using System.Web;
namespace CustomHttpModules
{
public class EnforceSSLModule : IHttpModule
{
public void Init(HttpApplication httpApp)
{
httpApp.PreRequestHandlerExecute += this.OnPreRequestHandlerExecute;
}
public void Dispose()
{
}
public void OnPreRequestHandlerExecute(object o, EventArgs e)
{
using (HttpApplication httpApp = (HttpApplication)o)
{
if (HttpContext.Current != null)
{
HttpContext ctx = HttpContext.Current;
String qs;
qs = ctx.Request.QueryString;
//// Force the page to be opened under SSL
if (ctx.Request.IsSecureConnection)
{
if (qs != "")
qs = "?" + qs;
ctx.Response.Redirect("https://" +
ctx.Request.ServerVariables["SERVER_NAME"].ToString() +
ctx.Request.ServerVariables["PATH_INFO"].ToString() + qs);
}
}
}
}
}
}
To use the HttpModule in IIS5.1 or IIS6, drop the compiled assembly for the HttpModule in your site's bin folder and add the following to your web.config's HttpModules section:
<add type="CustomHttpModules.EnforceSSLModule, dllname" name="EnforceSSLModule" />
(where dllname is the name of your assembly file without the extension)

Resources