I'm developing ASP.Net application and I'm currently struggling with exception handling. I've already managed to do proper exception handling but I don't really know how to handle internal errors that are not suitable for UI.
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
LogManager.GetCurrentClassLogger().Error(ex);
Response.Clear();
HttpException httpEx = ex as HttpException;
if (httpEx == null)
{
switch(ex.GetType())
{
//Convert ex into httpexception
//with statuscode that depends on the exception type
}
}
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
routeData.Values.Add("action", "Handler");
routeData.Values.Add("exception", httpEx);
Server.ClearError();
Response.TrySkipIisCustomErrors = true;
var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
var c = ControllerBuilder.Current.GetControllerFactory().CreateController(rc, "Error");
c.Execute(rc);
}
Instead of trying to cast your exception to a HttpException just try to create a new HttpException with the original exception as the inner one:
HttpException httpEx = new HttpException(500, msg, ex);
Related
I have read many articles now about how to handle errors in asp.net, and I think it is a lot of information to take in.
I'm using service layer pattern, and in my service model, I have the following code:
public List<SpotifyAlbumModel> AddSpotifyAlbums(List<SpotifyAlbumModel> albums)
{
try
{
if(albums != null)
{
ctx.SpotifyAlbums.AddRange(albums);
ctx.SaveChanges();
}
return albums;
}
catch(Exception e)
{
throw new Exception();
}
}
If a problem rises, I want to redirect the user to a error page that says something went wrong.
I call my service method from my controller:
public ActionResult AddSpotifyAlbums(List<SpotifyAlbumModel> albums)
{
_profileService.AddSpotifyAlbums(albums);
return Json(new { data = albums });
}
How can I determine in my controller method if something went wrong in the service, and then redirect the user to the error page?
Or should I have a global errorHandler that transfer the user as soon a excetion is caught?
You can add Application_Error method in global.asax. For example:
void Application_Error(Object sender, EventArgs e)
{
var exception = Server.GetLastError();
if (exception == null) {
return;
}
// Handle an exception here...
// Redirect to an error page
Response.Redirect("Error");
}
We've tried multiple things, but what seems to work best is to just handle every exception yourself. We didn't completely invent this yourself, the inspiration was from here:
ASP.NET MVC 404 Error Handling
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 404)
{
Log.Debug("Application_EndRequest:" + Context.Response.StatusCode + "; Url=" + Context.Request.Url);
Response.Clear();
string language = LanguageUtil.Instance.MapLanguageCodeToWebsiteUrlLanguage(HttpContext.Current.Request, Thread.CurrentThread.CurrentUICulture.Name);
var rd = new RouteData();
//rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
rd.Values["languageCode"] = language;
rd.Values["controller"] = "Error404";
rd.Values["action"] = "Index";
Response.TrySkipIisCustomErrors = true;
IController c = new Controllers.Error404Controller();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
}
else if (Context.Response.StatusCode == 500)
{
Log.Debug("Application_EndRequest:" + Context.Response.StatusCode + "; Url=" + Context.Request.Url);
Response.Clear();
string language = LanguageUtil.Instance.MapLanguageCodeToWebsiteUrlLanguage(HttpContext.Current.Request, Thread.CurrentThread.CurrentUICulture.Name);
Response.Redirect("~/" + language + "/error");
}
}
Is there a way when catching an exception to determine if it were constructed with a non-default message.
try
{
throw new Exception(message); // case 1
//throw new Exception(); // case 2
}
catch(Exception exp)
{
/* what do I put here such that if the case 2 exception were
caught it would output exp.ToString() instead of exp.Message? */
textBox1.Text = exp.Message; // case 1 handeling
}
Just to clarify when Exception(message) is thrown I want it to ouptut exp.Message and when Exception() is thrown I want to output exp.ToString(). I would prefer to accomplish this without adding a custom exception. Thanks.
You need to check the message against a default exception
catch (Exception e)
{
bool isDefaultMessage = e.Message == new Exception().Message;
}
Update
Difference types of Exception
catch (Exception e)
{
bool isDefaultMessage = false;
try
{
var x = (Exception) Activator.CreateInstance(e.GetType());
isDefaultMessage = e.Message == x.Message;
}
catch (Exception) {} // cannot create default exception.
}
Hi all you clever guys,
I have a question regarding exception handling when dealing with .NET Reflection in C#.
Basically I call a constructor on a class through the use of ContructorInfo.Invoke(new object[] { ... }).
I wrap it all in a try/catch like this:
try
{
preset = constructor.Invoke(new object[] { package }) as IExportPreset;
}
catch (Exception e)
{
Exception baseEx = e.GetBaseException();
Utilities.Log("GetBaseException", baseEx.StackTrace);
if (baseEx != null)
throw baseEx;
else
throw e;
}
My question is that why is baseEx.StackTrace not the stacktrace I see when the baseEx is thrown?
The stacktrace I see when throwing the exception does only contain a trace "outside of" constructor.Invoke() whilst Utilities.Log("GetBaseException", baseEx.StackTrace); shows me the full trace "inside of" constructor.Invoke().
EDIT:
By using the answer of #Knaģis, here is the actual solution to my problem:
Exception baseEx = e.GetBaseException();
if (baseEx != null)
{
throw new Exception("CreateExport Exception", baseEx);
}
When you do throw baseEx; the runtime will assign a new stack trace for the exception thrown. This has nothing to do with Reflection or your specific use case.
If you need to preserve the original stack trace, use a simple throw; (without an argument) - it rethrows the exact same exception you caught, preserving all details:
try
{
preset = constructor.Invoke(new object[] { package }) as IExportPreset;
}
catch (Exception e)
{
Exception baseEx = e.GetBaseException();
Utilities.Log("GetBaseException", baseEx.StackTrace);
throw;
}
try this:
using System.Runtime.Serialization;
public static class ExceptionHelper
{
public static void PreserveStackTrace(this Exception e)
{
var streamingContext = new StreamingContext(StreamingContextStates.CrossAppDomain);
var objectManager = new ObjectManager(null, streamingContext);
var serializationInfo = new SerializationInfo(e.GetType(), new FormatterConverter());
e.GetObjectData(serializationInfo, streamingContext);
objectManager.RegisterObject(e, 1, serializationInfo);
objectManager.DoFixups();
}
}
and use before rethrow:
try
{
preset = constructor.Invoke(new object[] { package }) as IExportPreset;
}
catch (Exception e)
{
Exception baseEx = e.GetBaseException();
Utilities.Log("GetBaseException", baseEx.StackTrace);
baseEx.PreserveStackTrace();
if (baseEx != null)
throw baseEx;
else
throw e;
}
We have strange situation where something is causing an exception on Http.Current object such as .Response or .Request. The exception is NullReferecne. I was under the impression that HTTPContext under normal circumstances can't be null. But since in our case it can how should I handle this type of exception? We're already handle HTTPException in Global.asax.cs and with ErrorSeverity as Fatal which is home grown class. I 've modified the code that checks for null value but I'm not cetain if that really catches this scenario - see code below:
protected void Application_Error(object sender, EventArgs e)
{
try
{
Exception exception = Server.GetLastError();
HttpException httpException = exception as HttpException;
if (httpException != null)
{
if (httpException.GetHttpCode() == 404)
{
return;
}
}
string errMessage = "Running Application_Error. An unhandled error occured in the application.";
errMessage = errMessage + "Error message = " + exception.Message;
//This is the IF-ELSE I've added but it just doesn't "feel right"
if (HttpContext.Current.Request != null || HttpContext.Current.Response != null)
{
StaticServices.ErrorLogger.LogSingleException(exception, ErrorSeverity.Fatal);
}
else
{
StaticServices.ErrorLogger.LogSingleException(exception, ErrorSeverity.Info);
}
exception = exception.InnerException;
while (exception != null)
{
StaticServices.ErrorLogger.LogSingleException(exception, ErrorSeverity.Fatal);
exception = exception.InnerException;
}
QSession session = QSession.GetInstance();
bool mobileIndicator = session != null ? session.Packet.QPolicy.IsMobileApplication : false;
if (mobileIndicator)
{
LogAndRedirectTechDiff("MobileTechnicalDifficulties.htm", session != null);
}
else
{
//This is the IF-ELSE I've added but it just doesn't "feel right"
if (HttpContext.Current.Request != null || HttpContext.Current.Response != null)
{
LogAndRedirectTechDiff("TechnicalDifficulties.htm", session != null);
}
else
{
LogAndRedirectTechDiff("UnsupportedBrowser.htm", session != null);
}
}
}
catch (Exception ex)
{
EventLog.WriteEntry("FQ",
"Global.asax.cs Application_Error method caused an exception. This is the error message :" +
ex.ToString(), EventLogEntryType.Error);
}
}
Good day to all! Trying to solve a problem. I use a method that handles all errors on the site (This method found on the blog of one man)
Global.asax
protected void Application_Error(object sender, EventArgs e)
{
HttpContext ctx = HttpContext.Current;
Exception ex = ctx.Server.GetLastError();
ctx.Response.Clear();
RequestContext rc = ((MvcHandler)ctx.CurrentHandler).RequestContext;
IController controller = new CategoryController();
var context = new ControllerContext(rc, (ControllerBase)controller);
var viewResult = new ViewResult();
var httpException = ex as HttpException;
if (httpException != null)
{
switch (httpException.GetHttpCode())
{
case 404:
viewResult.ViewName = "Error404";
break;
case 500:
viewResult.ViewName = "Error500";
break;
default:
viewResult.ViewName = "Error";
break;
}
}
else
{
viewResult.ViewName = "Error";
}
viewResult.ViewData.Model = new HandleErrorInfo(ex, context.RouteData.GetRequiredString("controller"), context.RouteData.GetRequiredString("action"));
viewResult.ExecuteResult(context);
ctx.Server.ClearError();
}
When I start Projects in the studio, causing the error. I get exception at that code:
RequestContext rc = ((MvcHandler)ctx.CurrentHandler).RequestContext;
Exception:
Unable to cast object of type 'System.Web.DefaultHttpHandler' to type 'System.Web.Mvc.MvcHandler'
Once I stop debugging (Shift + F5). This method works well and handles any errors. But at the start of project, causing the error. Looking for a solution to these topics, but this problem is not found. Help please.
[HandleError]
public class CategoryController : Controller
{
// some methods
}
Solved his problem by using code:
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex is HttpException && ((HttpException)ex).GetHttpCode() == 404)
{
Response.Redirect("~/Error/404");
}
else
{
Response.Redirect("~/Error/Other");
}
Server.ClearError();
}