Display exception message using JavaScript in Base Page's OnError event - asp.net

I want to display all unhandled excpetions in the appplication using Javascript. For this I have defined onError event inside my custom base class of my pages. Here is the code for my Base Page:
namespace Loan
{
public class BasePage : System.Web.UI.Page
{
public BasePage()
{
}
protected override void OnError(EventArgs e)
{
//Report Error
Exception ex = Server.GetLastError();
if (ex is HttpUnhandledException && ex.InnerException != null)
{
ex = ex.InnerException;
}
var _message = "Error : "+ ex.Message.ToString();
DisplayAlert(_message);
Server.ClearError();
return;
}
protected virtual void DisplayAlert(string message)
{
ClientScript.RegisterStartupScript(
this.GetType(),
Guid.NewGuid().ToString(),
string.Format("alert('{0}');", message.Replace("'", #"\'")),
true
);
}
}
}
The alert is never displayed for an unhandled exception. However, if I call the DisplayAlert from any Page
base.DisplayAlert(ex.Message);
the javascript alert is displayed. How can I get the javascript alert to be displayed for the unhandled exceptions from the base page.Or is there any other way to display these exception messages to the user. I don't want to redirect them to a generic error page as it sends them back and forth.

This is expected. If the exception is unhandled, the OnError event on BasePage will execute and your child page won't continue to execute, there's nothing to render as the BasePage is pure code. If you want to spit out the alert you'd need to write directly to the Response but you should still see a blank page after an unhandled exception occurs.
protected virtual void DisplayAlert(string message)
{
Response.Write(string.Format("<script>alert('{0}');</script>", message.Replace("'", #"\'")));
}
Of course, when you call DisplayAlert directly, it works because you are just calling a method, the Page execution continues normally.
I frankly dislike your approach. You should log the exception and redirect to another page, the typical Oooooooooopsss, me screwed up kind of thing.

Related

There are some unhandled FacesMessages, this means not every FacesMessage had a chance to be rendered

I am little frustrated on this problem - I have an small application recently migrated to Webspehere 8.5.5 and trying to save an order, expected to render a message that is not displaying. Below is snippet of code we are using for rendering the message.
Error Message- are some unhandled FacesMessages, this means not every FacesMessage had a chance to be rendered.
if (headerKey != null && !headerKey.equals("0")) {
addErrorMessage("A new order has been submitted.");
}
protected void addErrorMessage(String message) {
addErrorMessage(null, message);
}
protected void addErrorMessage(String componentId, String message) {
this.getFacesContext().addMessage(
componentId, new FacesMessage(FacesMessage.SEVERITY_ERROR,
message, message));
}
just run over this by google:
In my case the problem was that I forgot to update the h:message/p:growl etc component in the view.
After adding an update=":form:growlMessages" to my action, it worked.

asp.net + exceptions and redirecting

My intention is to log an error(I am using Log4Net) when an exception is caught and redirect to a pretty looking page with some error message. I have a class that returns a Type T object , mostly a DataSet.
In my Catch statement I wrote this, it works but I am not sure if there's a more appropriate way of handling, can someone please advice. Thanks. Note that the throw cannot be omitted because the class has a return type.:
catch (Exception ex)
{
log.Error(ex);
HttpContext.Current.Response.Redirect("~/errorPage.aspx");
throw ex;
}
It depends upon how you want to handle error on the page, In general , unhandled exception should be bubbled up to application_error in gloabl.asax file to it generic.Here is one simple way to handle this error.
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();
}

ASP.NET ToolkitScriptManager AsyncPostBackError - throw exception from Content Page

Wonder if anyone can help. I'm trying to implement the ToolScriptManager OnAsyncPostBackError.
The ToolkitScriptManager is on the Masterpage and I've set the OnAsyncPostBackError property:
<ajax:ToolkitScriptManager ID="ToolkitScriptManager"
runat="server" EnablePartialRendering="true"
OnAsyncPostBackError="ScriptManager_AsyncPostBackError">
</ajax:ToolkitScriptManager>
On my content page I'm catching an exception and, logging it and then throwing it
private void LogError(Exception ex, bool full)
{
...
_presenter.LogError(this, error, ex);
throw new ApplicationException(
"Error Occured",
ex
);
}
where it then gets picked up by the handler on the Master Page
protected void ScriptManager_AsyncPostBackError(object sender, AsyncPostBackErrorEventArgs e)
{
if (e.Exception.Data["GUID"] != null)
{
string _message =
(
e.Exception.InnerException != null
) ? e.Exception.InnerException.Message : e.Exception.Message;
ToolkitScriptManager.AsyncPostBackErrorMessage = _message +
" When reporting this error use the following ID: " +
e.Exception.Data["GUID"].ToString();
}
else
{
ToolkitScriptManager.AsyncPostBackErrorMessage =
"The server could not process the request.";
}
}
This all works as expected, I'm picking up the error via the PageRequestManager EndRequest and displaying on the page
The problem is that I'm getting an Application_Error in my Global.asax stating that an Exception of type 'System.Web.HttpUnhandledException' was thrown.
I kinda get it I think, cause I'm throwing the exception which is not caught by a catch I'm assuming?!
Any advice on what I'm missing, or where in fact I'm going wrong?
Thanks in advance!
Ian

How do I catch an exception raised on my ASCX control (not the code-behind)?

I have a large ASPX page with many ASCX controls. If a control throws an exception, it should log the exception and hide only itself. All the other controls should still render.
How do I handle exceptions on individual ASCX's raised from the front-end file (the ASCX and not the code-behind)? for example: a control trying to reference an invalid property using the <%= MethodThatThrowsANullReferenceException() %> syntax.
Obviously using the generic error handler method in Global.asax won't solve the problem. I need to handle exceptions on individual controls.
Make all your UserControls inherit from a custom base class, like such:
public class CustomUserControl : UserControl
{
protected override void Render(HtmlTextWriter writer)
{
try
{
base.Render(writer);
}
catch (Exception e)
{
writer.Write("Could not load control. Sad face.");
}
}
}
I tried overriding Render method but this doesn't cover all exceptions.
For example, if some kind of exception is thrown during Page_Init, Load or Render, this will prevent the page from rendering.
We have different people working on different modules (controls) that can be loaded into a single Page, but I'm not responsible for the quality of the code of each module, so even if it's not best practice, i needed to catch exceptions and identify which control fails to load, because the application can't fail just because one module does.
For this particular scenario that is not so rare nowadays, neither custom, application or page error handling will work well.
The solution I've come up was:
Each Module (Control.ascx) when needs to be loaded into the Page (aspx) , is contained into a ModuleShell that will hold some specific features and will be responsible for helping the Page_Error handling to work properly.
This ModuleShell , instead of trying to trap the exception of its child control that failed, will just monitor in each life cycle stage if it managed to Load properly.
Here's an snippet of it:
protected void Page_Init(object sender, EventArgs e)
{
Modules.CurrentState = _mod;
}
protected void Page_Load(object sender, EventArgs e)
{
Modules.CurrentState = _mod;
}
protected void Page_PreRender(object sender, EventArgs e)
{
Modules.CurrentState = _mod;
}
Modules is a static class used to store session variables.
CurrentState is a variable that ModuleShell use to record their names in.
The Page_Error located in the only aspx we got, will get the last recorded ModuleShell that tried to load. Since any exception will stop page rendering, the last ModuleShell to record its name to the main Page, it's probably the one that failed to load properly.
It's a sloppy solution but it's transparent to the Module Developer.
AFAIK, this is not possible (at least in an easy way).
Rich Custom Error Handling with ASP.NET:
When errors happen, an exception is
raised or thrown. There are three
layers at which you may trap and deal
with an exception: in a
try...catch...finally block, at the
Page level, or at the Application
level. The first two happen right
inside a page's code, and code for
application events is kept inside
global.asax.
The Exception object contains
information about the error, and as
the event bubbles up through the
layers, it is wrapped in further
detail. In rough terms, the
Application_Error exception contains
the Page_Error exception, which
expands on the base Exception, which
triggered the bubbling in the first
place.
If there is an exception occured inside the user control, the only way to catch it inside the user control is to handle it inside a try { } catch { } block.
I think the lowest level when the exception like this could be caught is the next - Page_Error level like this:
protected void Page_Error(object sender, EventArgs e)
{
// the control which throw an exception
var control = (Control)sender;
control.Visible = false;
// the exception itself
var exception = Server.GetLastError();
Context.ClearError();
}
the Context.ClearError() method is even preventing an exception from bubbling up further on to Application_Error. But unfortunatelly, then unhandled exception is thrown the page processing stops and error processing is started instead. This means the render of page will stop too (so you won't see the controls next to that which caused this exception).
You could wrap the method you are trying to call in your own method that will return the same type, but with a try {} catch {} block.
public string MethodWrapper()
{
try
{
return MethodThatCanThrowException();
}
catch (SomeExceptionType)
{
//log exception
return string;
}
}
One option, as suggested by Jim Bolla was to make all controls inherit from the same base class and use a Try/Catch in the Render method. This would have worked. Unfortunately many of the controls I am dealing with already have different base classes.
This solution worked for me:
I added the following code to each user control (I'm sure this can be refactored further to reduce duplication):
#region Error Handling
public event EventHandler ControlCrashed;
private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
protected override void RenderChildren(HtmlTextWriter writer)
{
try
{
base.RenderChildren(writer);
}
catch (Exception exc)
{
Logger.Error("Control failed to load. Hiding control. Message: " + exc, exc);
//Ignore and hide the control.
this.Visible = false;
if (ControlCrashed != null)
ControlCrashed(this, EventArgs.Empty);
}
}
#endregion
This catches any front-end rendering problems. The parent page can handle the ControlCrashed event if it wishes to display a nice error message.

Filtering signalled exceptions out of Elmah error mails

I've implemented a wrapper method around Elmah's Error Signaling, where a raised exception is only seen by Elmah for logging and mailing, but now I'd like to filter only these signalled exceptions out of the mailing, but still log them. How can I do this?
This is my simple wrapper:
public void LogException(Exception exception)
{
ErrorSignal.FromContext(HttpContext.Current).Raise(exception);
}
I've thought of wrapping the input exception in a custom SignalledException, and filtering those out of mailing, but then my logs get full of SignalledExceptions, and not the real exceptions.
Any other ideas please?
Elmah filtering works mainly on exception types. Programmatic filtering would allow me to examine information added to an exception, but I have yet to come across an Exception type with an ElmahFilteringData property, and I prefer not to 'invade' the exceptions I want logged. Here is how I accomplished only sending email notificatins for certain signalled exceptions:
First I have a special wrapper exception, purely for telling Elmah not to send an email notification for exceptions of this type:
public class ElmahEMailBlockWrapperException: Exception
{
public const string Explanation = "This is a wrapper exception that will be blocked by Elmah email filtering. The real exception is the InnerException";
public ElmahEMailBlockWrapperException(Exception wrappedException):base(Explanation, wrappedException) {}
}
Then, when I raise an exception I normally only want logged and not emailed, but maybe sometimes emailed, I use this code in my exception logging service:
public void LogException(Exception exception, bool includeEmail)
{
if (includeEmail)
{
ErrorSignal.FromContext(HttpContext.Current).Raise(exception);
}
else
{
// Wrap the input exception in a special exception type that the Elmah email filter can block.
var wrappedException = new ElmahEMailBlockWrapperException(exception);
ErrorSignal.FromContext(HttpContext.Current).Raise(wrappedException);
}
}
Now, in the Elmah filter events in Global.asax, I unwrap the exception to log it, and if it is wrapped, dismiss it from the email notification pipeline:
public void ErrorLog_Filtering(object sender, ExceptionFilterEventArgs e)
{
// If the exception was wrapped in a ElmahEMailBlockWrapperException exception to be blocked by the ErrorMail filter, the InnerException
// of the the ElmahEMailBlockWrapperException is the real exception to be logged, so we extract it, log it, and dismiss the wrapper.
var ebw = e.Exception.GetBaseException() as ElmahEMailBlockWrapperException;
if (ebw != null)
{
ErrorLog.GetDefault(HttpContext.Current).Log(new Error(ebw.InnerException));
e.Dismiss();
}
}
public void ErrorMail_Filtering(object sender, ExceptionFilterEventArgs e)
{
// If the exception was wrapped, i.e. raised only to be logged by Elmah and not emailed, dismiss it.
if (e.Exception.GetBaseException() is ElmahEMailBlockWrapperException)
{
e.Dismiss();
}
}

Resources