Error in debug mode - c#

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");

Related

Record Exception w/ AWS X-Ray .NET MVC

I am having an issue with recording an exception to AWS X-Ray.
Here is what is in Application_Error:
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
if (exception != null)
{
var InnerException = exception.InnerException;
Session["error"] = String.Format("{0} ::: {1}", exception.Message, exception.StackTrace);
try
{
AWSXRayRecorder.Instance.AddException(exception);
}
catch (Exception ee)
{
// ignore errors for XRay
}
}
Server.ClearError();
}
However, an error is thrown on the AddException line stating "Segment doesn't exist in CallContext"
First time trying to get X-Ray going. Any advice? Are there any tutorials that anybody has run into that may help?
The default behavior of XRay is to throw an exception if you are attempting to access a Segment, and none is currently setup in the current context. You can see the default behavior mentioned in the environment variables documentation.
As that documentation points out, you can set the AWS_XRAY_CONTEXT_MISSING environment variable on your EC2 instance to LOG_ERROR to adjust this behavior.
Alternatively, you can use the ContextMissingStrategy property to change this behavior within the code. Documentation link.
Set AWS_XRAY_CONTEXT_MISSING to LOG_ERROR can stop AddException to throw the "Segment doesn't exist" exception, but this also means nothing gets recorded to XRay service.
To really solve the problem, you should create a Segment at the beginning of your logic. When you are writing an ASP.NET Web API application, you can add an interceptor to automatically create a segment for each incoming request. There is a sample application you can try.
https://github.com/awslabs/aws-xray-dotnet-webapp

Response.write in application_error not working?

Ok, I have a weird problem and can't find anything about it online. I'm trying to get custom application-level error handling working in ASP.NET. I have customErrors turned off in the web.config with the hopes of handling everything in application_error. Bear with me...
My code in global.asax is very simple:
void Application_Error(Object sender, EventArgs e) {
HttpContext.Current.Trace.Write("ERROR MESSAGE");
Response.TrySkipIisCustomErrors = true;
var error = Server.GetLastError();
HttpContext.Current.Response.Write("ERROR MESSAGE");
HttpContext.Current.ClearError();
}
I created a simple aspx page and threw an error in Page_Init or Page_Load, and everything worked as expected, i.e.: I see "ERROR MESSAGE" on a blank page when an error occurs.
Now I dynamically add some user controls to that aspx page and everything renders as expected. If I then throw an error from INSIDE one of the controls, I only get a blank white page. "ERROR MESSAGE" does not appear.
Now I know that application_error is still firing because when I remove the call to ClearError(), I get a Yellow Screen Of Death. Also, I can execute a Server.Transfer in there and that works fine. But nothing will come out for Response.Write.
This goes further: I can set Response.StatusCode, but a Response.Redirect will error out (and thus throw me into an infinite loop). Trying to write to the Event Log also errors out, but instead of throwing a new error, it throws the original, i.e.: "Input string was not in a correct format." when I try to convert a string to a number. As mentioned, Response.Write doesn't do anything, though it does not throw an error.
So looking at my trace log, in the second case (exception inside dynamically added user control) I see a full control tree and the error occurs right after Begin Render. In the first case, the tree is empty and the error is thrown either after Init or Load. Both times, trace.axd reports Unhandled Execution Error.
When I move the throw inside the control to the control's constructor or OnInit, things work as expected. When I move it to OnLoad or Render, it gets goofy.
So I'm wondering if at some point the Response object loses certain functionality. I've tried all sorts of permutations, from syntax (using HttpContext.Current.Response vs Context.Response vs pulling the Response object from the "sender" parameter), to moving the ClearError() or Response.Clear(), etc methods around, etc. I've tested the Response object for "null-ness" as well, and it never reports a null. I can set some response properties (http status code) but not others.
I'm using IIS7.5 integrated mode (.NET v4), but experienced similar problems when I tried Classic mode.
So I'm trying to solve this mystery, obviously, but my goal is to ultimately handle all errors, no matter what point in the asp.net lifecycle they occur, and to be able to write out some information from the handler (ie application_error).
Handled unhandled exceptions using this approach. Custom error is off in web.config.
All 3 options work.
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
Response.TrySkipIisCustomErrors = true;
this.Server.ClearError();
this.Server.GetLastError();
//DO SOMETHING WITH GetLastError() may be redirect to different pages based on type of error
//Option 1:
Response.Write("Error");
//Option 2:
Response.Redirect("~/Error.aspx");
//Option 3:
this.Server.Transfer("~/Error.aspx");
}

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.

In ASP codebehind, is there any benefit to adding the return keyword after a redirect?

I was wondering whether if it was necessary to keep a return statement after my Response.RedirectPermanent call in my codebehind? It doesn't seem like it, but I wanted to confirm with others.
Response.RedirectPermanent(vpd.VirtualPath);
return;
Is there any reason to do so either for a functional or performance gain?
Answer overhaul:
Hold the phone! The detail in my previous answer was, following further research, not at all true. In fact, the MSDN documentation specifies the following:
When you use this method in a page handler to terminate a request for one page and start a new request for another page, set endResponse to false and then call the CompleteRequest method. If you specify true for the endResponse parameter, this method calls the End method for the original request, which throws a ThreadAbortException exception when it completes. This exception has a detrimental effect on Web application performance, which is why passing false for the endResponse parameter is recommended.
http://msdn.microsoft.com/en-GB/library/a8wa7sdt.aspx
So, in actual fact, the rest of the page is not executed (in theory - see 'Update' below for an example of when this falls over); however, there is still a very tangible issue with doing it the way you are, which is that the endResponse mechanism is implemented by throwing a ThreadAbortException, which is a relatively expensive way of terminating the processing of the current thread.
Instead, you should tell it to let the thread continue, but return immediately - also be sure that other methods in the call stack are doing what they should:
Response.RedirectPermanent(vpd.VirtualPath, false);
return;
Better yet, wrap the call in a conditional to ensure that undesirable code doesn't get called and then use the CompleteRequest method (which does not terminate the currently-executing code but will bypass all subsequent events):
if (_redirecting)
{
Response.RedirectPermanent(vpd.VirtualPath, false);
Context.ApplicationInstance.CompleteRequest();
}
else
{
/* Code I don't want to execute if I do a redirect */
DeleteUsersDataForever(_currentUser);
}
There's an in-depth article on this very topic here and even the documentation itself seems to have an unhealthy distaste for the HttpResponse.End method, which is what's called if you allow Response.Redirect to do the response termination for you.
Update: Additionally, given that the thread is terminated by raising an exception, consider what happens if you try and do your redirect inside a try/catch:
try
{
// Redirect and terminate execution
Response.Redirect(someUrl, true);
}
catch
{
// Handle some errors.
}
DeleteUsersDataForever(_currentUser);
The exception that's raised by Response.End is caught in your catch block. The rest of your code is, therefore, still executed and you have accidentally deleted all of _currentUser's data (unless you do something to prevent this in your catch block, such as bubbling the exception to the caller).
I have tried the code below :
Page1.aspx
protected void Page_Load(object sender, EventArgs e)
{
Response.RedirectPermanent("~/Page2.aspx");
Session["afterRedirect"] = "after redirect";
}
Page2.aspx
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(Session["afterRedirect"] ?? "nothing to show");
}
Result
nothing to show
Code after RedirectPermanent does not execute so Iguess using a return or not will have the same effect.

FormsAuthentication.SignOut throwing NullReferenceException

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.

Categories

Resources