Global asax Session_End not fired when session lost - asp.net-mvc

I am doing ajax call to asp.net mvc action(it is name SearchResults action)
In SearchResults action I set a session
context.Session["FlightSearchRequest"] = flightSearchRequest;
and then Redirect To another Action
return RedirectToAction("GetAvailableFlights");
In GetAvailableFlights action I want to access session
return context.Session["FlightSearchRequest"] as FlightSearchRequest;
But it is null
I think my session lost but why?I want to debug this
I added
protected void Session_End(object sender, System.EventArgs e)
{
}
to global.asax but it is not fired...When my session get null I want catch this what should I do ?

Related

ASP.net mvc5 upgrade from mvc3 loses HTTPContext.User

I'm in the process of upgrading a legacy app that I inherited from MVC3 to MVC5 and somehow I broke the HTTPContext.User object.
The app has a custom authentication mechanism that seems to be working correctly as it returns a proper User object to the rest of the pipeline. Specifically, in Global.asax.cs:
protected void Application_BeginRequest(object sender, EventArgs args)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.GetType().FullName.Equals("Citation.AMS.Users.UserContext", StringComparison.OrdinalIgnoreCase))
{
try
{
using (IAuditor auditor = CoreFactory.AuditorCreate())
{
auditor.WriteAudit(HttpContext.Current, "Compliance");
}
}
catch (Exception ex)
{
using (ILogger log = CoreFactory.LoggerCreate())
{
log.WriteFatalError("Exception in Application_BeginRequest::Audit.", ex);
}
}
The check for HTTPContext.Current.User returns the correct object above. But by the very next method call:
protected void Application_AcquireRequestState(object sender, EventArgs args)
{
CultureInfo ci = null;
HttpCookie cookie = Request.Cookies[CookieHelper.CookieName];
if (cookie != null && !string.IsNullOrWhiteSpace(cookie.Values[CookieHelper.CultureName]))
{
ci = new CultureInfo(cookie.Values[CookieHelper.CultureName]);
}
else
{
The object is converted then to an RolePrincipal instead of the correct User type.
There must be some processing done between those two method calls in the pipeline but I can't figure out what's happening between them that would change the user object.
In the original code base, this doesn't happen. I've also created a new branch based on the MVC3 branch and upgraded all the nuget packages and updated the web.config files as I found issues and that seems to work better (don't want to go that route because my other branch has a lot of other changes that would be challenging to replicate.)
Can someone tell me what I'm missing or how to find out why the object is changing between these method calls?
Found it, it was custom javascript that was redirecting my controllers.

AppDomain.CurrentDomain.UnhandledException not firing in MVC

I have default template of MVC4 project and following subscription for UnhandledException event in my Global.asax:
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
protected void Application_Start()
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Debugger.Break();
// Some logging code here
}
In my HomeController Index action I simply write:
throw new Exception("Test exception"):
Console application with such subscription works fine. But in MVC project handler call never occurs.
What is wrong with MVC?
UnhandledException callback is not called because when action raise exception its handled by MVC framework and AppDomain doesn't have unhandled exception so its not candidate to be unloaded and it can handle next request.
The shortest way to log exception:
protected void Application_Error(object sender, EventArgs args)
{
Debugger.Break();
Exception error = ((HttpApplication)sender).Context.Server.GetLastError();
// Some logging code here
}

How to access data after redirect

Again there are multiple articles which says how to access data after redirect. but doesn't serves my purpose.
I am having errorcontroller which is having index action method and error index view.
If there is any error in the application it will caught in Application_Error event.
inside Application_Error event I had logged the error and redirected to Error Index page like this -
protected new void Application_Error(object sender, EventArgs e)
{
Exception error = Server.GetLastError();
log.error(error.Message);
HttpContext.Current.Response.Redirect("~/Error/Index");
}
Now in the error index view, I would like to display the error message. What should I do in Application_Error event which can be access by Error Index view?
Updated : I don't want to use Session as session object may not be available in Application_Error event. this is dependent on when the error occurred.
Approach - 1
As per my knowledge you can use TempData to store the posted data. It is like a DataReader Class, once read, Data will be lost. So that stored data in TempData will become null.
var Value = TempData["keyName"] //Once read, data will be lost
So to persist the data even after the data is read you can Alive it like below
var Value = TempData["keyName"];
TempData.Keep(); //Data will not be lost for all Keys
TempData.Keep("keyName"); //Data will not be lost for this Key
TempData works in new Tabs/Windows also, like Session variable does.
You could use Session Variable also, Only major problem is that Session Variable are very heavy comparing with TempData. Finally you are able to keep the data across Controllers/Area also.
Approach - 2
This works for me. This is very easy and no need to consider any change in Web.Config or Register the Action Filter in Global.asax file.
ok. So, First I am creating a simple Action Filter. This will handle Ajax and Non Ajax requests.
public class MyCustomErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
var debugModeMsg = filterContext.HttpContext.IsDebuggingEnabled
? filterContext.Exception.Message +
"\n" +
filterContext.Exception.StackTrace
: "Your error message";
//This is the case when you need to handle Ajax requests
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
error = true,
message = debugModeMsg
}
};
}
//This is the case when you handle Non Ajax request
else
{
var routeData = new RouteData();
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "Error";
routeData.DataTokens["area"] = "app";
routeData.Values["exception"] = debugModeMsg;
IController errorsController = new ErrorController();
var exception = HttpContext.Current.Server.GetLastError();
var httpException = exception as HttpException;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (System.Web.HttpContext.Current.Response.StatusCode)
{
case 504:
routeData.Values["action"] = "Http404";
break;
}
}
var rc = new RequestContext
(
new HttpContextWrapper(HttpContext.Current),
routeData
);
errorsController.Execute(rc);
}
base.OnException(filterContext);
}
}
Now you can implement this Action Filter on Controller as well as on the Action only.Example:
I am going little off topic. I thought this is bit important to explain.
If you pay attention to the above highlighted part. I have specified the order of the Action Filter. This basically describes the order of execution of Action Filter. This is a situation when you have multiple Action Filters implemented over Controller/Action Method
This picture just indicates that let's say you have two Action Filters. OnActionExecution will start to execute on Priority and OnActionExecuted will start from bottom to Top. That means in case of OnActionExecuted Action Filter having highest order will execute first and in case of OnActionExecuting Action Filter having lowest order will execute first. Example below.
public class Filter1 : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Execution will start here - 1
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Execution will move here - 5
base.OnActionExecuted(filterContext);
}
}
public class Filter2 : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//Execution will move here - 2
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Execution will move here - 4
base.OnActionExecuted(filterContext);
}
}
[HandleError]
public class HomeController : Controller
{
[Filter1(Order = 1)]
[Filter2(Order = 2)]
public ActionResult Index()
{
//Execution will move here - 3
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
}
You may already aware that there are different types of filters within MVC framework. They are listed below.
Authorization filters
Action filters
Response/Result filters
Exception filters
Within each filter, you can specify the Order property. This basically describes the order of execution of the Action Filters.
Use TempData for getting value.
Some feature about TempData
TempData is a dictionary object that is derived from TempDataDictionary class and stored in short lives session.
TempData is used to pass data from current request to subsequent request means incase of redirection.
It’s life is very short and lies only till the target view is fully loaded.
It’s required typecasting for complex data type and check for null values to avoid error.
It is used to store only one time messages like error messages, validation messages.

Handle Session Timeout in .Net MVC Razor

I am working on a website which is API based, client side is being developed in .Net MVC. For exception handling, I am using
public void Application_Error(object sender, EventArgs e)
{
string action = "Index";
Exception exception = Server.GetLastError();
Response.Clear();
HttpException httpException = exception as HttpException;
if (httpException != null)
{
switch (httpException.GetHttpCode())
{
case 404:
// page not found
action = "Error404";
break;
default:
action = "Index";
break;
}
// clear error on server
Server.ClearError();
}
Response.Redirect(String.Format("/error/{0}", action));
}
so for any exception thrown by try catch from Controller, the page redirects to error page.
Now I want that when session is expired it should redirect to Login page, How can I do that?
Right now what is happening is, after session expires, when I try to access the session value, it throws exception "object reference not set to an instance of object." then it redirects to the default error page.
I don't think you're going to be able to do this from inside a generic exception handler because - as you said - missing session variables simply throw a NullReferenceException. Perform a null check on the session variable from your controller:
Public ActionResult MyAction ()
{
if (Session["myVariable"] == null)
{
RedirectToAction("SessionTimeOut", "Error");
}
...
}
If you have session variables that should always exist unless the session has expired, you could try overriding the OnActionExecuting method for your controller and performing your null check in there. To do this for multiple controllers, define a BaseController, override its OnActionExecuting method and then inherit this in your other controllers.

How can I get the Initial Timestamp of Page Request when a page request is began in .NET Asp MVC?

How can I get the Initial Timestamp of Page Request when a page request is began in .NET Asp MVC? I'd like to compare that Timestamp to the beginning of an Action, and then again as the OnActionExecuted and see where in the pipeline my app is spending time before it begins responding with the "head" element, which it does concurrently while models and data requests are being processed. Any suggestions?
You subscribe to Application_BeginRequest in your Global.asax, you put the current timestamp into the HttpContext and then inside your OnActionExecuted or whatever you retrieve this timestamp from the HttpContext, calculate the new timestamp and make a substraction:
Global.asax:
protected void Application_BeginRequest(object sender, EventArgs e)
{
this.Context.Items["timestamp"] = DateTime.UtcNow;
}
OnActionExecuted:
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
DateTime initial = (DateTime)filterContext.HttpContext.Items["timestamp"];
DateTime current = DateTime.UtcNow;
long totalMilliseconds = (long)(current - initial).TotalMilliseconds;
...
}

Resources