ASP.NET Exception Handling presentation to user - asp.net

I have added try catches in my site which work great. The next part in development is to set up some exception handling output. Obviously I don't want the site to crumble when an error occurs and I don't want a horrible error screen. So, somewhere in the middle would be nice.
I was thinking to have an exception handler user control in the main master page which wil output a nice little message when something goes wrong.
What would be the best way to pass the exception to this user control? I was thinking of using a session variable.
Does anyone have a solution to this problem?
Thanks

This is easier than you're making it. Create a page called error.aspx (or whatever you want to call it), and turn the CustomErrors on in the web.config.
<configuration>
<system.web>
<customErrors defaultRedirect="errors.aspx"
mode="On">
</customErrors>
</system.web>
</configuration>
There is a lot of configurability to handle different http errors or random exceptions. If you want, you can dump the exception message (or the exception itself) into the session or use the HttpServerUtility.GetLastError (documentation)and then output any number of different messages on the error page. This will even catch exceptions that you DON'T catch.
CustomErrors Documentation
Edit:
#Icarus indicates that OP is looking for a solution by which the page continues to render and output while only showing an error message within the page, so I'll provide an answer to that as well.
There are a few ways I've handled this in the past. For very complex pages where the behavior requested is fatal (the page result can't be known), I've always deferred to an error page as I mentioned above that includes major master elements. So the menu, header, etc are all still there, but the notification of cataclysm is evident.
The behavior you seem to be looking for is something I would use less out of a need to report exceptions than to report general messages. My preference is to have a user control that has a public bindable property that a message can be injected into. Such as (forgive the VB, I can't seem to find my C# version):
<BrowsableAttribute(True), Bindable(False), Category("Misc"), _
Description("Gets or sets the NavigateUrl property for the link to start a new request.")> _
Public Property MyImportantMessage() As String
Get
Return _myImportantMessage
End Get
Set(ByVal value As String)
_myImportantMessage= value
End Set
End Property
Then the output could be any string message you like or you could program in a number of presets, fetch from resources, whatever. As to how to get it in there, we have taken the MasterPage route. We have a method in our master pages which assigns such a property in the user control directly. In order for this method to be callable, each page that uses the master page has to include the VirtualPath property, otherwise the method will not be available at compile time.
<%# MasterType
VirtualPath="~/MasterPage.master" %>
This then allows the Master property to be called from within the page itself to call this property:
'Keeping the VB theme
Me.Master.SetImportantMessage(message)
Keep in mind that Me.Master from within the page is not the same as Page.Master. So your exception will either need to bubble up to the actual page or the page reference itself will have to be sent down to your usercontrols as a property.

If you're wanting to provide an error for a handled exception, it's really as simple as populating a label with some sort of a notice that the application had a problem processing a request. You would do this within the "catch" part of the statement. I've even gone as far as presenting different messages depending on the role of the user. For instance if an admin generates an error you could actually output the actual exception message, but if someone in a lesser role generates it it would show them a more generic error and send the admin group a message/email.
try
{
//your code here
}
catch (Exception ex)
{
if (Role!="Admin")
{
Label1.Text = "There was an error, the administrator has been notified."
}
else
{
Label1.Text = "Error: " + ex.Message + ": " + ex.StackTrace; //you could add further here if you want to look for an inner exception.
}
}

Related

How to handle Object Data Source Exception handling in DotNetNuke

I've created several DNN (5.2.3) modules and I'm finding that if an error happens on the object data source (ODS) DNN will then show that error to everyone. A sample (though not a ODS specific error in this case) is shown below. This has no meaning to user. The exception should really be "Thing not found" or something like that to the user. The problem is that this DropDownList is bound to an ODS. So my questions are:
How in DNN can I override this behavior to show a helpful message using ODS binding?
How in DNN can I override this behavior to show a generalized exception for all errors for the current module, if a specific exception cannot be caught to give a helpful message to the user?
Sample:
'SelectedThingDropDown' has a SelectedValue which is invalid because it does not exist in the list of items. Parameter name: value
PS> I know about try/catch Exceptions.ProcessModuleException(e,ex). The problem is this does not work for ODS binding, unless I'm doing something wrong.
There are number of places you can inspect while dealing with ODS and DropDownList. Here is list of some of them.
ODS_Selected event, check e.Exception: This object is having errors when calling Select method provided. It's null if there is no error. If you find error, you can disable the ddl and place a user friendly message in label for notification.
DDL_DataBound event: Don't directly bind the selected value, try to find the the dll items by value like :
ListItem item = ddl.Items.FindByValue('');
if(item != null) item.selected = true;
Keep in mind that module load exception will be there only if you are not handling the exceptions, if you feel they are not helpfull to user, you can override them by your own user notification method with the help of try catch as you said. but don't forget to create entries in the event log for the error so that you can track your errors and optimize them.
Good luck.

ServerControl randomly null

I got a master page with a server control in it. Randomly the server control is inaccessible from codebehind. This doesn't happen on a specific action (eg a Button click or so). Currently I have no clue what this could be. I don't think it's output caching since this is not explcitly activated and the error happens far to seldom for that. But I'm going to disable caching in the master page explicitly with next deployment.
Anyone an idea how to find more info to find what's happening? Or has someone had a similar error?
The control is defined in markup. The accompaning codebehind is:
PGFMainNavi.HasAccessToFunction = HasAccessToNaviItem;
// HasAccessToNavi is a local function
Exception is:
System.NullReferenceException: Object reference not set to an instance
of an object
Thanks.
sa
I have similar errors when I cache my controls - and I always check if their null, or if they are the correct types.
I think that your control is cached somewhere.
Use this code, to check that is not cached.
if(PGFMainNavi != null)
{
PGFMainNavi.HasAccessToFunction = HasAccessToNaviItem;
}
or find where you set the case on this control and remove it.
Second Solution
Some times after an online update I get this error, because compiler did fail to read correct all involving files - probably some user read the page the same time I copy the files or something.
To avoid that I always use the app_offline.htm before make my updates.

ASP.NET control events exception handling

Suppose I have a button in an aspx page that performs a save of the form data to the database. In the associated event handler, before sending the updates, I read something from a webservice, operation that might result in an exception. In case of an error I want to have an adequate message displayed on the page, and all the data in the form preserved. How can I achieve this? Also, all my pages inherit from a basepage, so I would like, if possible to have all the error handling code in the base class. I do not want, if possible, to surround any web service call with try-catch blocks, I would in case of any unhandled exception to call some method automatically, something like Page_error, but still preserve the data in my forms.
You can easily put a method that manages the display message (maybe setting the text of some errorMessageLabel) in a superclass called from any derived class (if you wanna use inheritance to setup a template for your pages) if an exception is thrown (you can put the call to the superclas method in a catch block if there's actually an exception being thrown or you can manage this manually if the webservice is unavailable depending on your programming style).
As far as preserving the data presented, if viewstate is on and you are not populating your page dynamically then you're ok - if not, you need to explicitly save state information in viewState or session entries and retrieve them back if something goes wrong.
This bit really depends on how your page is actually implemented.

Hiding the stacktrace for an exception returned by a asp.net WebMethod?

I am using methods with the Attribute [WebMethod] in my aspx pages. I don't use any asp.net ajax but jQuery to call these methods and return objects in JSON. This all works fine.
Next I added an authorization check inside the webMethod, if the current user doesn't have access to the feature I need to let the calling JavaScript know.
So I am throwing an AccessViolationException exception which can then be parsed by the OnError callback function in JavaScript. This works too but the exception includes the full StackTrace and I don't want to make this available to the calling client.
What other ways I could use to return an "Access Denied" to the client when the WebMethod returns a business object?
I'm using ASP.Net 3.5SP1 and jQuery 1.32
You can also add a:
customErrors mode="On"/
in your web.config, this will cut away the stack trace and leave you only the exception message
Why propagate errors through the wire? why not use an error response ?
Just wrap your object in a response object wich can contain an error code for status and an error message to present to users.
As suggested by NunFur I changed my approach and rather than throwing an error, I return a 'richer' object.
There are at least two options, the first one would be to encapsulate my business object into a response object with some status properties. I tried this but it makes the JSON more complicated.
So rather than adding a new object I added two properties to my business object, something like ServiceStatus and ServiceMessage. By default these are 200 and '', but can be set by the WebMethod code if anything goes wrong (no access, proper error). In this case they business object will be 'empty' (no data). The JavaScript code then first checks for the ServiceStatus and reacts appropriately.
I add the two fields to all my objects that are returned by WebMethods, even a simple string. They have to implement an Interface with those two properties.
Now I have complete control over that goes over the wire in case something unexpected is happening.
Thanks for the input
I save exceptions for when things go really wrong. (e.g. can't connect to the database)
Either return nothing (null/nill/whatever), or return a false bool value.
Sorry that I don't have a better answer than that...I'll have to keep looking myself.
You could look at SoapException: http://msdn.microsoft.com/en-us/library/system.web.services.protocols.soapexception(VS.71).aspx
I'm just not sure, if it will work when it is called from JavaScript. Espeially if it's called with a get-request.
BTW AccessViolationException is to my best knowlegde ment to be thrown when the application is accessing memory it has no access to.
/Asger

Good error handling practice

What is a good error handling practice for an asp.net site? Examples? Thanks!
As with any .net project I find the best way is to only catch specific error types if they are may to happen on the given page.
For example you could catch Format Exceptions for a users given input (just incase JavaScript validation fails and you have not use tryparse) but always leave the catching of the top level Exception to the global error handler.
try
{
//Code that could error here
}
catch (FormatException ex)
{
//Code to tell user of their error
//all other errors will be handled
//by the global error handler
}
You can use the open source elmah (Error Logging Modules and Handlers) for ASP.Net to do this top level/global error catching for you if you want.
Using elmah it can create a log of errors that is viewable though a simple to configure web interface. You can also filter different types of errors and have custom error pages of your own for different error types.
One practice that I find to be especially useful is to create a generic error page, and then set your defaultRedirect on the customErrors node of the web.config to that error page.
Then setup your global.asax for logging all unhandled exceptions and then put them (the unhandled exceptions) in a static property on some class (I have a class called ErrorUtil with a static LastError property). Your error page can then look at this property to determine what to display to the user.
More details here: http://www.codeproject.com/KB/aspnet/JcGlobalErrorHandling.aspx
Well, that's pretty wide open, which is completely cool. I'll refer you to a word .doc you can download from Dot Net Spider, which is actually the basis for my small company's code standard. The standard includes some very useful error handling tips.
One such example for exceptions (I don't recall if this is original to the document or if we added it to the doc):
Never do a “catch exception and do nothing.” If you hide an exception, you will never know if the exception happened. You should always try to avoid exceptions by checking all the error conditions programmatically.
Example of what not to do:
try
{
...
}
catch{}
Very naughty unless you have a good reason for it.
You should make sure that you can catch most of the errors that are generated by your application and display a friendly message to the users. But of course you cannot catch all the errors for that you can use web.config and defaultRedirect by another user. Another very handy tool to log the errors is ELMAH. ELMAH will log all the errors generated by your application and show it to you in a very readable way. Plugging ELMAH in your application is as simple as adding few lines of code in web.config file and attaching the assembly. You should definitely give ELMAH a try it will literally save you hours and hours of pain.
http://code.google.com/p/elmah/
Code defensively within each page for exceptions that you expect could happen and deal with them appropriately, so not to disrupt the user every time an exception occurs.
Log all exceptions, with a reference.
Provide a generic error page, for any unhandled exceptions, which provides a reference to use for support (support can identify details from logs). Don't display the actual exception, as most users will not understand it but is a potential security risk as it exposes information about your system (potentially passwords etc).
Don't catch all exceptions and do nothing with them (as in the above answer). There is almost never a good reason to do this, occasionally you may want to catch a specific exception and not do any deliberately but this should be used wisely.
It is not always a good idea to redirect the user to a standard error page. If a user is working on a form, they may not want to be redirected away from the form they are working on. I put all code that could cause an exception inside a try/catch block, and inside the catch block I spit out an alert message alerting the user that an error has occurred as well as log the exception in a database including form input, query string, etc. I am developing an internal site, however, so most users just call me if they are having a problem. For a public site, you may wish to use something like elmah.
public string BookLesson(Customer_Info oCustomerInfo, CustLessonBook_Info oCustLessonBookInfo)
{
string authenticationID = string.Empty;
int customerID = 0;
string message = string.Empty;
DA_Customer oDACustomer = new DA_Customer();
using (TransactionScope scope = new TransactionScope())
{
if (oDACustomer.ValidateCustomerLoginName(oCustomerInfo.CustId, oCustomerInfo.CustLoginName) == "Y")
{
// if a new student
if (oCustomerInfo.CustId == 0)
{
oCustomerInfo.CustPassword = General.GeneratePassword(6, 8);
oCustomerInfo.CustPassword = new DA_InternalUser().GetPassword(oCustomerInfo.CustPassword, false);
authenticationID = oDACustomer.Register(oCustomerInfo, ref customerID);
oCustLessonBookInfo.CustId = customerID;
}
else // if existing student
{
oCustomerInfo.UpdatedByCustomer = "Y";
authenticationID = oDACustomer.CustomerUpdateProfile(oCustomerInfo);
}
message = authenticationID;
// insert lesson booking details
new DA_Lesson().BookLesson(oCustLessonBookInfo);
}
else
{
message = "login exists";
}
scope.Complete();
return message;
}
}

Resources