Why is my Web api Application_Error not catching Exceptions? - c#

I am using a .net framework web-api project and in my global.asax.cs file i have this:
protected void Application_Error(object sender, EventArgs e)
{
var ctx = HttpContext.Current;
var exception = ctx.Server.GetLastError(); // get exeption
// log exeption
Context.Response.ContentType = "application/json";
Context.Response.StatusCode = 500;
// if debug return detailed exeption else generic like below
Context.Response.Write("Internal server error");
}
I enabeled custom erros in webconfig:
<customErrors mode="On" />
And in a controller endpoint I throw an exception:
throw new Exception("test");
Result I see in the browser is :
{
"Message": "An error has occurred."
}
Result I would have expected is:
what is written in the Application_Error method:
Context.Response.Write("Internal server error");
Something is not registering here, what have I missed?

Related

Resonse.Redirect(URL) is not working in global.asax

In my requirement i am returning custom error. in global.asax application error is not redirecting any other URL. Response.Redirect(URL),Server.Transfer(URL) is not redirecting. it show Cannot redirect after HTTP headers have been sent. i tried but not working. please try to help me.below is my code
try
{
Exception exc = Server.GetLastError();
ErrorLogger LogError = new ErrorLogger();
// Handle HTTP errors
if (exc.GetType() == typeof(HttpException))
{
ex = (HttpException)Server.GetLastError();
int httpCode = ex.GetHttpCode();
// Filter for Error Codes and set text
if (httpCode >= 400 && httpCode < 500)
ex = new HttpException
(httpCode, "Safe message for " + httpCode + " HTTP codes.", ex);
else if (httpCode > 499)
ex = new HttpException
(ex.ErrorCode, "Safe message for " + httpCode + " HTTP codes.", ex);
else
ex = new HttpException
(httpCode, "Safe message for unexpected HTTP codes.", ex);
// Log the exception and notify system operators
ErrorLogger.Error(ex);
Server.ClearError();
Response.Clear();
Response.Buffer = true;
Response.Redirect("http://www.stackoverflow.com");
if (!Response.IsRequestBeingRedirected)
// Will not be called
Response.Redirect("http://www.google.com");
//ScriptManager.RegisterStartupScript(Page, typeof(Page), "OpenWindow", "window.open('ErrorPage.aspx');", true);
//Response.Write("<script> window.open('http://localhost:54749/ErrorPage.aspx','_blank'); </script>");
//Response.Redirect("http://www.google.com", true);
//Response.Redirect("~/ErrorPage.aspx");
}
else
{
ErrorLogger.Error(exc);
// LogError.NotifySystemOps(exc);
// Clear the error from the server
//Server.ClearError();
}
}
catch (Exception ex)
{
ErrorLogger.Error(ex);
}
According to the MSDN documentation for Response.Redirect(string url), it will throw an HttpException when "a redirection is attempted after the HTTP headers have been sent". Since Response.Redirect(string url) uses the Http "Location" response header (http://en.wikipedia.org/wiki/HTTP_headers#Responses), calling it will cause the headers to be sent to the client. This means that if you call it a second time, or if you call it after you've caused the headers to be sent in some other way, you'll get the HttpException.
One way to guard against calling Response.Redirect() multiple times is to check the Response.IsRequestBeingRedirected property (bool) before calling it.
// Causes headers to be sent to the client (Http "Location" response header)
Response.Redirect("http://www.stackoverflow.com");
if (!Response.IsRequestBeingRedirected)
// Will not be called
Response.Redirect("http://www.google.com");
Note* You cannot change the HTTP Response Status Code once a redirect 301/302 has been issued as well.
Have you tried Response.Redirect("http://www.google.com", true);
can you tell us also which part of global.asax file you are using this code.
void Application_BeginRequest(object sender, EventArgs e)
{
}
or it is somewhere else
also try following code
HttpContext.Current.Response.Redirect("http://www.google.com/");
Try this:
this.Response.Redirect("http://www.stackoverflow.com");

Custom Error Handler

I have searched the web and stitched together an error handling solution that doesn't work mainly because I don't understand fully how the exception pipeline works. I used different guides, but I didn't get any of theme to work for me. What I want the error handler to do is this. I have a class called workplanRepo where all my queries are executed. I have covered all queries with a try and catch block. What I want is when an error occurs is for an exception to be thrown that allows me to customize a specific message for each query and the default exception message. I then want to be able to retrieve the messages in the error view that the exception handler has redirected the user to. I would also like a default handler that catches all other errors. but don't necessarily have the custom message part. If anybody could explain or show me how I can achieve this. I would be very grateful!. This is one of the query methods:
try {
newItem["Author"] = _user.Id;
newItem["Title"] = _user.Title;
newItem.Update();
clientContext.ExecuteQuery();
}
catch (Exception e) {
throw new HttpException("Oops, there must have been an error: " + e.Message);
}
In ASP.NET MVC 5, we can catch error inside Global.asax.cs's Application_Error event instead of using try catch block in every query. From then redirect to custom error page.
In addition, we can also use logging framework like Log4Net and NLog.
For example,
protected void Application_Error(object sender, EventArgs e)
{
var exception = Server.GetLastError();
LogException(exception);
if (exception is HttpAntiForgeryException)
{
Response.Clear();
Server.ClearError();
Response.TrySkipIisCustomErrors = true;
// Call target Controller and pass the routeData.
IController controller = EngineContext.Current.Locator.GetInstance<CommonController>();
var routeData = new RouteData();
routeData.Values.Add("controller", "Common");
routeData.Values.Add("action", "AntiForgery");
var requestContext = new RequestContext(new HttpContextWrapper(Context), routeData);
controller.Execute(requestContext);
}
else
{
// Process 404 HTTP errors
var httpException = exception as HttpException;
if (httpException != null && httpException.GetHttpCode() == 404)
{
Response.Clear();
Server.ClearError();
Response.TrySkipIisCustomErrors = true;
// Call target Controller and pass the routeData.
IController controller = EngineContext.Current.Locator.GetInstance<CommonController>();
var routeData = new RouteData();
routeData.Values.Add("controller", "Common");
routeData.Values.Add("action", "PageNotFound");
var requestContext = new RequestContext(new HttpContextWrapper(Context), routeData);
controller.Execute(requestContext);
}
}
}
private void LogException(Exception ex)
{
if (ex == null)
return;
// Ignore 404 HTTP errors
var httpException = ex as HttpException;
if (httpException != null &&
httpException.GetHttpCode() == 404)
return;
try
{
// Log error message
}
catch (Exception)
{
// Don't throw new exception if occurs
}
}
You can view sample project which use Log4Net at GitHub.

Application_Error renders page on local host but not on production(www)

I have an Application_Error which renders an error page:
private void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
// A good location for any error logging, otherwise, do it inside of the error controller.
Response.Clear();
HttpException httpException = exception as HttpException;
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
routeData.Values.Add("action", "Index");
// Clear the error, otherwise, we will always get the default error page.
Server.ClearError();
routeData.Values.Add("id", httpException.GetHttpCode());
Response.StatusCode = httpException.GetHttpCode();
Context.Response.ContentType = "text/html";
// Call the controller with the route
IController errorController = new ErrorController();
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
works on my local machine seamlessly. when i push it to production, it renders the regular asp 404 page instead of the page which the controller is supposed to server.
Even on production server, when i use localhost instead of www it works.
i should add that i have no configrations in web.config for customerrors. i tried turning them off and that didnt help either.
to me it seems like it is the url that is causing this but cant figure out why/how.
Any idea how to solve the problem?
In your Application_Error method please try adding this...
Response.TrySkipIisCustomErrors = true;

Custom error page for failed windows authentication in ASP.NET MVC application

According to How to use custom Errors page in Windows Authentication (although never marked as an answer), you have to add an IIS HTTP error handler to "catch" failed windows authentications and serve up a custom error page.
However, 403 is never reached, failed WinAuth ends with 401 Unauthorized. However, if I add an IIS HTTP error handler for 401, the NTLM authentication process does not work anymore (uses 401 internally as well).
Anybody has a working solution for a custom error page (not static, I want to execute an MVC controller action!) when windows authentication failed?
The code below isn't exactly what you need, but this is how I am handling unhandled Exceptions. You could alter this to route differently based on status code or exception type. (This is from Global.asax)
protected void Application_Error(object sender, EventArgs e)
{
var ex = Server.GetLastError().GetBaseException();
Server.ClearError();
var routeData = new RouteData();
routeData.Values.Add("controller", "Error");
routeData.Values.Add("action", "Global");
int status = 0;
if (ex.GetType() == typeof(HttpException))
{
var httpException = (HttpException)ex;
var code = httpException.GetHttpCode();
status = code;
}
else
{
status = 500;
}
//Create a new error based off the exception and the error status.
NameSpace.Models.ErrorModel Error = new ErrorModel(status, ex);
string innerException = "";
if (ex.InnerException != null)
{
innerException = "\n Inner Ex: " + ex.InnerException.StackTrace;
}
log.Error("Error Id: " + Error.ErrorId + " Error: " + ex.Message + ". Stack Trace: " + ex.StackTrace + innerException);
routeData.Values.Add("error", Error);
IController errorController = new NameSpace.Controllers.ErrorController();
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
Update: Apologies, I did not read your post completely. If you were to perform LDAP authentication within your application you could leverage the above code to catch and handle the error with a controller. Unfortunately, I cannot provide direct guidance on your issue above.

How do I create a global custom error page for ASP.NET MVC3?

I brand new to ASP.NET MVC3. How would I create a global custom error page for MVC3? The general idea is when an exception is thrown it would show a generic message to the user and it would log the exception to a database for developers to investigate later.
Thanks in advance for your help.
Here is what I ended up doing in global.asax.cs:
protected void Application_Error()
{
var exception = Server.GetLastError();
Log.Error("Exception", exception);
var httpException = exception as HttpException;
Response.Clear();
Server.ClearError();
var routeData = new RouteData();
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "General";
routeData.Values["exception"] = exception;
Response.StatusCode = 500;
if (httpException != null)
{
Response.StatusCode = httpException.GetHttpCode();
switch (Response.StatusCode)
{
case 403:
routeData.Values["action"] = "Http403";
break;
case 404:
routeData.Values["action"] = "Http404";
break;
}
}
IController errorsController = new ErrorController();
var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
errorsController.Execute(rc);
}
In your Global.asax file implement the Application_Error method:
protected void Application_Error() {
HttpContext ctx = HttpContext.Current;
var error = ctx.Server.GetLastError();
ctx.Response.Clear();
ctx.Response.End();
}
Following up on Maess' comment:
Read this: Error Handling in asp.net mvc 3
What I've done in my project is I created a BaseController and overridden the OnException event as below,
protected override void OnException(ExceptionContext filterContext)
{
// do some logging using log4net or signal to ELMAH
filterContext.ExceptionHandled = true;
var exModel = new HandleErrorInfo(filterContext.Exception,
filterContext.RouteData.Values["controller"].ToString(),
filterContext.RouteData.Values["action"].ToString());
View("Error", exModel).ExecuteResult(ControllerContext);
}
Also I removed the HandleError action filter registered in the Global.asax.cs.
Note: You should have a view with name Error in shared folder.
Update: To extract the error information from the Error view you have to bind the Error view to the model HandleErrorInfo.
#model System.Web.Mvc.HandleErrorInfo
Then you can easily access the exception anywhere in the view as
#Model.Exception
Create a view called Error and add it to your Views\Shared folder. Then in your catch blocks, after you have logged the error, redirect the action to the error view. If you want to display a sophisticated message create an Error model and pass it to the view, or put the information into the ViewBag.
For information on unhandled exceptions and HTTP errors see Ropstah's post.

Categories

Resources