HttpNotFoundResult causes an HttpException to be thrown? - c#

For testing purposes, I have this method:
public ActionResult Index()
{
System.Diagnostics.Debug.Write("Index");
return new HttpNotFoundResult();
}
The method is being called ('Index' is outputted). Somehow, it is causing a HttpException to be thrown. In my Global.asax file I have an Application_Error implementation:
void Application_Error(object sender, EventArgs e)
{
Exception exc = Server.GetLastError();
if (exc is System.Web.HttpException)
{
string msg = "UrlReferrer: "
+ Context.Request.UrlReferrer + " UserAgent: " + Context.Request.UserAgent
+ " UserHostAddress: " + Context.Request.UserHostAddress + " UserHostName: "
+ Context.Request.UserHostName;
ErrorHandler.Error(exc.Message, msg);
}
else {
...
}
}
This method is being called after the system has processed the request for Index. I think that the HttpNotFoundResult causes the exception to be thrown - or perhaps the exception is thrown for any ActionResult with a status code of 404.
This is quite annoying, as it is side-stepping the OnException handler on my controller. For my website, Application_Error is supposed to be a last-ditch fallback - most normal errors are intended to be handled in other places (by the controllers, or action filters). I only want Application_Error to log completely unexpected exceptions, or 404s for things like image or .js files.
Is there a way to stop asp.net from throwing exceptions for programatically generated 404s? Alternatively, is there a way to determine in Application_Error if the HttpException was caused by a programatically generated 404?

You can create a custom exception filter that handles 404 exceptions raised by all the actions. You could use HttpContext.Items collection to track whether it is a programatically raised 404 or not.
Custom exception filter
public class NotFoundExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
// ignore if the exception is already handled or not a 404
if (filterContext.ExceptionHandled || new HttpException(null, filterContext.Exception).GetHttpCode() != 404)
return;
filterContext.HttpContext.Items.Add("Programmatic404", true);
filterContext.ExceptionHandled = true;
}
}
You need to apply NotFoundExceptionFilter as a global filter.
Application_Error event
public static void Application_Error(object sender, EventArgs e)
{
var httpContext = ((MvcApplication)sender).Context;
// ignore if it is a programatically raised 404
if(httpContext.Items["Programmatic404"] != null && bool.Parse(httpContext.Items["Programmatic404"].ToString()))
return;
// else, Log the exception
}

Related

ASP.NET: Only catch certain errors at page level?

Looking at:
https://learn.microsoft.com/en-us/aspnet/web-forms/overview/getting-started/getting-started-with-aspnet-45-web-forms/aspnet-error-handling
and specifically:
private void Page_Error(object sender, EventArgs e)
{
Exception exc = Server.GetLastError();
// Handle specific exception.
if (exc is HttpUnhandledException)
{
ErrorMsgTextBox.Text = "An error occurred on this page. Please verify your " +
"information to resolve the issue."
}
// Clear the error from the server.
Server.ClearError();
}
Is there a way to only handle asp.net file uploader file size too big (e.g. over 50MB) and let all other errors be handled at the application level?
BTW, here is code to catch files that are too big at the application level:
//Global.asax
private void Application_Error(object sender, EventArgs e)
{
var ex = Server.GetLastError();
var httpException = ex as HttpException ?? ex.InnerException as HttpException;
if(httpException == null) return;
if (((System.Web.HttpException)httpException.InnerException).WebEventCode == System.Web.Management.WebEventCodes.RuntimeErrorPostTooLarge)
{
//handle the error
Response.Write("Too big a file, dude"); //for example
}
}
So in other words, can we "throw" an application level error from a page level error method (e.g., when it's anything other than that file size exception that we want to handle on that specific page)?

How to pass Exception from Global.asax to another controller

I am using Application_Error method to handle and log exceptions. I need to pass Exception from Global.asax to Error controller
I tried
this.Session["w"] = (Exception)exception;
but that's not working.
My code looks like this:
protected void Application_Error(Object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
if (exception != null)
{
this.Session["w"] = (Exception)exception;
Server.ClearError();
ExceptionManager.LogExceptionToTextFile(exception);
ExceptionManager.LogExceptionToEmail(exception);
if (!Response.IsRequestBeingRedirected)
Response.Redirect("~/Error/Index");
}
}
You can try something like this
Exception exception = Server.GetLastError();
string errorId = Guid.NewGuid().ToString();
if (exception != null)
{
this.Application.Lock();
this.Application[errorId] = exception;
this.Application.Unlock();
Server.ClearError();
ExceptionManager.LogExceptionToTextFile(exception);
ExceptionManager.LogExceptionToEmail(exception);
if (!Response.IsRequestBeingRedirected)
Response.Redirect("~/Error/Index?errorId="+errorId);
}
and in the error controller
var Exception = (Exception)Application[Request["errorId"]]
EDIT:
If you want to use sessions, You might also want to replace
Response.Redirect("~/Error/Index");
With
Response.Redirect("~/Error/Index", false);
Reason you loose your session, is due to thread cancellation.
You can read more about it at When Should I Use Response.Redirect(url, true)?:

Custom Error using Global.asax asp.net

I made an error; the page directs users in case of error in any applications within the website. I made Global.asax rather than using Webconfig. My question is : Is it possible to redirect user from Global.asax for those statusCodes "401", "404" and "500" in case of error rather than using Webconfig ?
In other words, using Global.aspx rather than Webconfig !? I am just curious to know.
Thank you
protected void Application_Error(Object sender, EventArgs e)
{
Exception ex = this.Server.GetLastError();
if(ex is HttpException)
{
HttpException httpEx = (HttpException)ex;
if(httpEx.GetHttpCode() == 401)
{
Response.Redirect("YourPage.aspx");
}
}
}
Yes it is possible. Here is little code example. This should be added in Global.asax.cs.
Never set customErrors to Off in your Web.config file if you do not have an Application_Error handler in your Global.asax file. Potentially compromising information about your Web site can be exposed to anyone who can cause an error to occur on your site.
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
// Get the exception object.
Exception exc = Server.GetLastError();
// Handle HTTP errors
if (exc.GetType() == typeof(HttpException))
{
// The Complete Error Handling Example generates
// some errors using URLs with "NoCatch" in them;
// ignore these here to simulate what would happen
// if a global.asax handler were not implemented.
if (exc.Message.Contains("NoCatch") || exc.Message.Contains("maxUrlLength"))
return;
//Redirect HTTP errors to HttpError page
Server.Transfer("HttpErrorPage.aspx");
}
// For other kinds of errors give the user some information
// but stay on the default page
Response.Write("<h2>Global Page Error</h2>\n");
Response.Write(
"<p>" + exc.Message + "</p>\n");
Response.Write("Return to the <a href='Default.aspx'>" +
"Default Page</a>\n");
// Log the exception and notify system operators
ExceptionUtility.LogException(exc, "DefaultPage");
ExceptionUtility.NotifySystemOps(exc);
// Clear the error from the server
Server.ClearError();
}
Also once can get error code like
exc.GetHttpCode() == 403 so that
if (exc!= null && httpEx.GetHttpCode() == 403)
{
Response.Redirect("/youraccount/error/forbidden", true);
}
else if (exc!= null && httpEx.GetHttpCode() == 404)
{
Response.Redirect("/youraccount/error/notfound", true);
}
else
{
Response.Redirect("/youraccount/error/application", true);
}
Also see Custom error in global.asax

ASP.NET error handling problems

I'm new to ASP.NET and I have a very basic site that I just want to grab all Application Errors and email them to me, while giving the user a error page. I read a lot on the subject and seems to be a lot of information. Below is what I came up with but I'm having problems keeping the Exception in session so I can email it to me.
I keep getting a NullReferenceException was unhandled by user code on the ex.Message from the Error.aspx.cs file.
Any thoughts?
Global.asax.cs-
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
HttpContext.Current.Response.Redirect("~/Error.aspx");
}
Error.aspx.cs-
public partial class Error : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Exception ex = (Exception)Session["Exception"];
this.SendEmail(ex);
Session.Remove("Exception");
}
}
private void SendEmail(Exception ex)
{
string body = "An exception occured at "
+ DateTime.Now.ToLongTimeString()
+ " on " + DateTime.Now.ToLongDateString()
+ "<br />" + ex.Message; //ERROR HERE
MailMessage msg = new MailMessage("from#email.com", "to#email.com");
msg.Subject = "Exception in Portal Website";
msg.Body = body;
msg.IsBodyHtml = true;
SmtpClient client = new SmtpClient("localhost");
client.Send(msg);
}
}
Your problem is that you are never setting Session["Exception"], so on your Error.aspx, Exception ex is always going to be null... and then doing ex.Message will throw the NullReferenceException. Even if you fix that and appropriately set Session["Exception"], what you are doing isn't ideal.
You could just send the email from the Application_Error function.
Your Response.Redirect (MSDN Entry) is going to cause ANOTHER exception (ThreadAbortException)
You should look at implementing ELMAH. It is easy to implement and does everything you want to do.
But if all you want to do is fix your code, just move the send email logic to Application_Error and then you don't have to worry about Session.
What I did in a similar instance is to throw all exceptions and then in your global.asax uses the Application_Error method to perform any work you need to with the error message.
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
string exception;
Exception ex = Server.GetLastError();
if (ex.InnerException != null)
{
Exception innerException = ex.InnerException;
exception = ex.InnerException.Message;
}
else
{
exception = ex.Message;
}
//Send email here
//redirect to error page
}
I don't see you pushing the exception object to session, why not move the SendEmail method to global.ascx and SendEmail then redirect user to Error page. There are third party plugins like ELMAH that can do all this easily for you with simple configurations.
I'm in a similar bind. I'm going to check out ELMAH, but my project has a huge restriction on Open Source Projects, yours may to. Sucks to be me!
In which case I'd suggest creating a logging function for the message that you can call directly from the Global.asax. Something like:
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
LogException(ex);
HttpContext.Current.Response.Redirect("~/Error.aspx");
}
//Somewhere Else
void LogException(Exception ex)
{
WriteExceptionToEndOfTextFile(ex);
SendEmail();
}
This way if someone decides they want to suppress our exceptions, they can still properly handle the exception.

How to change where UnauthorizedAccessException redirects to in ASP.Net

Pretty straightforward.
I'm throwing an UnauthorizedAccessException in an AuthorizationFilter. I want UnauthorizedAccessException to head to an Error page, NOT to the /Account/Login page.
How can I make that change?
Try setting up something like this in global.asax.cs
protected void Application_Error(object sender, EventArgs e)
{
// excpt is the exception thrown
// The exception that really happened is retrieved through the GetBaseException() method
// because the exception returned by the GetLastError() is a HttpException
Exception excpt = Server.GetLastError().GetBaseException();
if(excpt is UnauthorizedAccessException)
{
// redirect here
}
}
You can use multiple exception handlers
try
{
// code here
}
catch (UnauthorizedAccessException)
{
Response.Redirect(errorPageUrl, false);
}
catch (Exception)
{
Response.Redirect(loginPageUrl, false);
}

Categories

Resources