FormsAuthentication.SignOut throwing NullReferenceException - c#

This problem seems related to this post, but I was not able to infer a solution from the thread.
I noticed this code in an application I inherited (after noting in a log file that an exception was being eaten):
protected void Session_End(object sender, EventArgs e)
{
try
{
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
//if (this.Context.Handler is IRequiresSessionState || this.Context.Handler is IReadOnlySessionState)
//{
// FormsAuthentication.SignOut();
// FormsAuthentication.RedirectToLoginPage();
//}
}
catch (Exception ex)
{
this.GetType().GetLogger().Error(ex);
}
}
I am wondering a few things. First, how is SignOut throwing a null reference exception? Is it an exceptional case, or am I doing something inherently wrong in my program? Next, what should I be testing against to head-off this exception before it is thrown?
15:51:57,288 [13] ERROR ASP.global_asax - System.NullReferenceException: Object reference not set to an instance of an object.
at System.Web.Security.FormsAuthentication.SignOut()
at MvcApplication.Session_End
Thanks

It's important to realize that Session_End doesn't get necessarily executed in the the context of an HTTP request. It may run when a session times out. You cannot send anything to the client at that time, because it simply isn't there anymore!
Consequently, you should not try to delete the forms authentication cookie in Session_End. If you want, you should do that sooner, when a "Sign Off" button is clicked somewhere in your application. If you need a user's forms authentication ticket to expire after a timeout occures, you should simply set the cookie expiration time appropriately (possibly equivalent to session timeout value) in the config file.

Related

Error in debug mode

When I run my code in debug mode, I get an exception (System.Web.HttpException: 'Request is not available in this context'), but when I run in release mode (Ctrl-F5), the exception doesn't even show up. The exception appears at the Server.Transfer line.
How can I prevent this from happening when I run in debug mode?
protected void Application_Error(object sender, EventArgs e)
{
//Gets the last error, emails it
var exc = Server.GetLastError();
Server.ClearError();
if (exc == null)
{
exc = new ApplicationException("*** Application Exception - Unknown/null exception ***");
}
if (exc is HttpException)
{
var errorCode = ((HttpException)exc).GetHttpCode();
Response.Redirect("~/ErrorPage.aspx?e=" + errorCode.ToString());
}
else
{
exc.Publish();
Server.Transfer("~/ErrorPage.aspx?e=unknown");
}
}
I believe the issue may be that IIS runs in single-threaded mode when debugging. The Server.Transfer queues a message behind the current request which calls it but the current request cannot complete because the Server.Transfer cannot complete because the thread is blocked.
Try removing all breakpoints from your initial request and adding one in ErrorPage.aspx.
Alternatively, try a Response.Redirect instead of Server.Transfer. Because Response.Redirect will return to the client it completes the current request. I realise this may not be the functionality you require but it will help in debugging, then you can return to Server.Transfer for live running.
Server.Transfer can only happen for single HttpContext. Each virtual directory or app has its own HttpContext object and they know not that they co-exists!
You can find a more complete explanation here Error Message When You Use Server.Transfer or Server.Execute in ASP.NET Page
The solution is to change the method for another like Response.Redirect("~\somepath.aspx"); or HttpContext.Current.RewritePath("somepath.aspx");

Why Session End is called on App Start up?

I wanna free some DB resources and set few flags when User Session Ends in ASP.NET Site. But when I write my code to access session variables in Session End method of Global.asax file, its getting called everytime the App starts, Why this weird behavior?
Secondly, I want to access user specific session variables and free them up in DB on Session End. Thus I am using few session Variables where I am setting them in a webmethod on a Page and trying to access them on Session End. But since Session end is being called on App start up its always throws Null reference exception.
Here is mycode. for Setting up a variable in Webmethod in a .aspx page
[WebMethod(EnableSession=true)]
protected void checkUser()
{
Session["TestObject"] = "Hello I am session";
}
In my global.asax file I am trying to access as follows in Session_End method
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.
if (this.Context.Session != null && this.Context != null)
{
string k = this.Session["TestObject"].ToString();
}
}
I even tried HttpContext.current.Session etc.. but none worked. All are throwing exception as Session end is called on App start up and even when session timed out.

where can I catch the db connection exception in session mode: sqlserver?

I have an ASP.NET MVC 5 application and I set up the session state using SQL Server. Everything works fine.
I am currently on my developer server, so I thought to disconnect the internet [the session db is online], to see what happens. Not surprisingly the famous yellow page of death occurred. Then I thought to catch this exception and I used :
try{
session["age"]= 25;
}catch
{ //log the exception here and continue}
but I was surprised that this will not cause any exception here; because the application will not contact the SQL Server at this stage.
It seems that when the IIS prepared the view page to show the user; it then contact the SQL Server to save the session information and if failed then it will throw that yellow page of death.
My question is:
is there any way to catch the exception in the code? Other than in Global.asax?
Session load/access happens at the beginning of the request lifecycle (HttpApplication.AcquireRequestState Event) and persisted back at the end of the request lifecycle (HttpApplication.ReleaseRequestState Event). It is not at the point where you'd get a value out of the session. To catch it, use an MVC Global Action Filter to handle exceptions, including the SQLException which will occur when this is the case. Alternatively, create an HttpModule to handle exception events.
In your RegisterGlobalFilters method (which is called by Global.asax.cs):
public class FilterConfig
{
public static void RegisterGlobalFilters( GlobalFilterCollection filters )
{
filters.Add( new YourCustomExceptionHandlingAttribute } );
}
}
And YourCustomExceptionHandlingAttribute should implement HandleErrorAttribute

Cleanest way to throw an error but not show the user that it has errored (without custom error pages)

I'm running some code that only has to run once but it depends on external resources and may fail. I want the error to appear in the event log but I do not want the user to see it. I'd like to avoid using custom error pages if possible.
I could catch the exception and write it to the event log myself but I'm concerned that I can't guarantee what the name of the asp.net event source would be (it appears to change depending on the framework version.) I also can't create my own event source since that requires administrative permissions.
The approach that I'm currently working towards is a bit of a hack (which doesn't work yet) and it looks like this:
public void Init(HttpApplication context)
{
try
{
throw new Exception("test"); // This is where the code that errors would go
}
catch (Exception ex)
{
HttpContext.Current.Application.Add("CompilationFailed", ex);
}
}
private void context_BeginRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Application.AllKeys.Contains("CompilationFailed"))
{
// It failed on Init - we can't throw an exception there so lets try it here
var origEx = (Exception)HttpContext.Current.Application["CompilationFailed"];
// Only ever do this once
HttpContext.Current.Application.Remove("CompilationFailed");
// This should just look like a normal page load to the user
// - it will be the first request to the site so we won't be
// interrupting any postbacks or anything
HttpContext.Current.Response.AddHeader("Location", "/");
HttpContext.Current.Response.StatusCode = 301;
try
{
HttpContext.Current.Response.End();
}
catch (ThreadAbortException ex)
{
throw origEx;
}
}
}
Ideally what I would really like is a RecordException() method within IIS if anything like that exists.
I recommend Elmah for ASP.NET.
sounds like you want to be notified when there is an error but don't want the user to know about it. you could have the page redirect (if Fatal Error) or finish executing the rest of the file/page after sending you an E-mail or writing to data source that you have access to.

Response is not available in this context in asax file

I have a login page that works only with Firefox. It does not work with any other browsers.
When I checked the event log, I saw a "response is not available in the current context". It tells me that the error is in the global.asax file, at the response.redirect line:
void Session_End(object sender, EventArgs e)
{
Response.Redirect("~/Login.aspx?li=1");
// 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.
}
What could be the problem?
I have tried httpcontext.Current as suggested but then I get a Null Reference Exception, Object Reference not set to an instance of an object
Thank you.
Try using HttpContext.Current.Response it should definitely work.
Did you try using HttpContext.Current.Response?
Happy coding!!

Categories

Resources