Posted By: aza | May 18th, 2004 @ 6:31 AM
page 1 of 1
Comments: 24 | Views: 14723
aza
aza
Hi,

A question that I have never really found a good answer for is what is the best way to inidcate common errors in a method?

The options would be:

- Indicate using the return object. The problem here is returning false or null doesn't say much about what caused the error,

- Indicate using a return type and set an error property. This is the equivalent of the Win32 GetLastError call. Problem with this is it needs broad acceptance and since it's not done this way in the .Net base library would just cause confusion,

- Throw exceptions on any error conditions encountered. Problem with this is it's supposed to be bad practice.

The throw exceptions approach seems to me the most elegant and flexible. Obviously it brings in a performance hit but in the context of managed code is it a significant one?

The .Net base libraries seem to throw exceptions for easily detected conditions. Is the consesnus error handling approach in the .Net libraries to throw exceptions?

Aaron
gmiley
gmiley
what
What I usually do is write a generic HandleErr() function or procedure. I pass to it:

ex As Exception,
ErrAction As myProject.customActions (As Integer)

The ErrAction is just basically 0-n for different actions I plan on taking, this just makes it easier to read, no other reason.

Similar to:
Ignore = 0
SilentWriteLog = 1
NotifyUser = 2
NotifyUserWriteLog = 3

More can be added as you see fit such as:

EmailSupport = 4
EmailSupportNotifyUser = 5
EmailSupportSilentWriteLog = 6
EmailSupportNotifyUserWriteLog = 7

Aboviously you could come up with better names, but these work.

Then in the HandleErr I will pass the Exception and the ErrAction and have more than likely a case statement to handle the different actions.

Most general errors I write out to a log file, if I need to notify the user that there was a problem I will use option 3 (NotifyUserWriteLog) and display a friend error message, while write the technical mumbo-jumbo to the logfile. If I need to do support for that user, and cannot deduce right away from their error report, I just request that they email me the appname.err file in their program directory. I look it over and figure out whats going on.

Also, what I sometimes do as well is, if the appname.err file doesnt exist yet, on creation I have the application write out environment information as a .err file header so I know what im working with if an error does show up.

Hi Aaron

I've mainly experience with server-side .net. For single-user client applications i think you can use exceptions more liberally?

From the server's pov. i would only throw exceptions in exceptional circumstances. Although try{} / finally{} is essentially free in .net, it still hurts perf a lot to use throw() / catch{} in normal code flow. I've seen cases of asp.net apps gaining 10x throughput by removing exception throwing / catching from the common path for example...

In addition to all the code cycles - throwing exceptions plays havoc with the cpu's data and code caches which can impact a server pretty badly..

My preferred option would probably be to return an object that can describe a richer set of states than null / false. I'm not keen on the GetLastError() idea as it's hard to make work in a multithreaded environment.

You are right that the base class librarys throw in common cases. Some of these behaviors are wrong imo in .net 1.0 /1.1 ( Int32.Parse( "cat" ) shouldn't throw for example ). Most of these are addressed in Whidbey with the addition of TryParse() etc.

There's some good general advice on exceptions on the PAG site here...

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt05.asp

 





gmiley
gmiley
what

I guess I should elaborate further on my post.
When you use the method I described above, all the error handling is done within the functions/subroutines in functions you can simply return Nothing or -1, or False, whathaveyou as long as you can decipher that in code at the return point and make adjustments in case it fails.

Basically everything, as I said, is handled at the point of exception and the process returns whatever it needs to based on they type of exception and the action you chose for it at design time (or, presumably possible at runtime). Once that error is handled you just need to make sure your program knows that the function did not perform correctly.

FluffyDevilBunny
FluffyDevilBunny
GO GO GADGET COMPILER!
Well lets do an example here. Lets say that you had a function

bool LogonUser(string userId, string password);

You could easily just return a bool for your result, which is good.

Within the LogonUser function you would want to catch errors in the event that your user store was not available (SQLServer, ADS, etc).

But now lets say that you were using SQLServer and you catch the error inside LogonUser and then pass back a false to the caller. Well this could lead to a problem. The user would think they entered something wrong if you did not inform them that SQLServer was rebooting or whatever.

In select circumstances you *should* throw a new Exception with that being one of them. This way the caller knows the function has gone wrong.

If you think that is too expensive then perhaps modifying the application to:

bool LogonUser(string userId, string password, out int errorCode);

Still using errorCodes are not very readable and you still have the expense of looking at the error codes on the event of a failed logon... Even if the logon was due to an incorrect password. You have no way of knowing that your failed function was the result of an error or was just denied.

This is where I think that exception handling is the best way to detect errors. Even on the back end of things. Try Catch is going on everywhere in the framework so you are not Try Catch free by avoiding the use of if.

Just my opinion.
Charles
Charles
Welcome Change
As SPOD mentions, it's best to throw exceptions in exceptional cases, especially in ASP.NET applications for the reasons he describes.

Remember, it is never a good idea to just catch Exception. You should be proactive when it comes to exception handling. Just catching Exception can get you into some serious trouble from a security perspective if you happen to be calling into unmanaged code that throws in your try and passes control to your catch which suppresses the exception. If there is a buffer overrun vulnerability in the unmanaged chain, then you can be in for a very bad surprise. Just don't do it.

Charles
jj5
jj5
Yeah. We got goth served.
spod wrote:
You are right that the base class librarys throw in common cases. Some of these behaviors are wrong imo in .net 1.0 /1.1 ( Int32.Parse( "cat" ) shouldn't throw for example ). Most of these are addressed in Whidbey with the addition of TryParse() etc.


Where can I find the doco for the Whidbey APIs? Or, what is the TryParse() signature?

I'd rather have an IsParseable(String) or IsValid(String) method, and have Parse(String) throw.

I don't like methods that return status codes, and prefer to avoid default values (which I'm guessing TryParse will accept?) when possible.

John.

jj5 wrote:

Where can I find the doco for the Whidbey APIs? Or, what is the TryParse() signature?

I'd rather have an IsParseable(String) or IsValid(String) method, and have Parse(String) throw.


Hi jj5...

not sure where to get the docs externally i'm afraid...

the sig is
[ C# ]
public static bool TryParse(
string s,
ref int result
);

there was a long and interesting argument about this internally. The main reason for not doing

if( IsParsable( String ) )
   int i = Int.Parse(string );

is that it's hard to avoid a double parse of the string, which is too much of a perf hit in some cases...
 

Charles
Charles
Welcome Change
aza wrote:
...the .Net base class libraries seem to ignore the guideline.

What makes you think that the BCL ignores this guideline? In many cases, BCL methods will throw specific types of exceptions, not catch and continue. 

Charles 
jj5
jj5
Yeah. We got goth served.
Hey spod,

spod wrote:
there was a long and interesting argument about this internally. The main reason for not doing

if( IsParsable( String ) )
   int i = Int.Parse(string );

is that it's hard to avoid a double parse of the string, which is too much of a perf hit in some cases...


Bah! I knew you'd say that. I think that the wrong decision was made.

I'd prefer to have Boolean Int32.IsInvalid(String) and Int32 Int32.Parse(String).

If you want performance then you wouldn't check for invalid data, you'd assume it was valid and let the exception fall out.

I guess there is a case for TryParse, although every bone in my body wants to deny it. I imagine this would typically be used in UI code (e.g. to get an Int32 value from a TextBox) in this case the performance hit of double parsing is negligable. If you were trying to get an Int32 value out of a text file or what have you, it would be better (in my opinion) to insist that your data was valid and let the exception fall out (so you wouldn't check at all).

What are the cases where TryParse(String, ref Int32) significantly helps performance?

Why not support all methods? I.e. have an IsInvalid/IsValid/IsParseable query, a Parse method that throws and TryParse as is?

John.

jj5
jj5
Yeah. We got goth served.
For my money all the TryParse functionality should be moved into an 'advanced' class, such as System.Text.FastParser for example.

All the BCL value types that support parsing should have a Parse method that throws and an IsInvalid(String) method. (I like to test for 'invalid' because that tends to be the exceptional case, but I'd be happy enough with IsValid(..)).

Keep the common APIs simple, clean, and consistent. Having TryParse on Int32 is just ugly.

John.

I feel the same as aza on this. It's much more intuitive, to me at least, to look for or try an is<type>(String).

While currently writing a Database appliction I've used large sections that run IsDBNull(object) to verify my information coming back can be fit into my variables (I wouldn't have any Nulls in the DB but I have been overridden on this issue).

While this may be right or wrong I am already used to this check and if I needed to check for parsing I would immediatly use intellisense or index to look for an is<type>().

Now I'm not the level of programming that some here are. I am definitley not worried about the performance hits* of is<type>() check statemnents so take this as you will.

Thanks,
Risu

*I'm dealing with a closed internal system with few users on relatively quick servers and client machines. Ease of use and future adaptability have been our key design points. Speed is up there but only if very noticeable.

that's interesting....i'll feed that back to the framework people. I assumed that people would really like the TryParse idea ( i did ), and that the IsType double parse problem was a concern to many...

It seems a reasonable idea to include both an IsType() and a TryParse to me ( but what do i know Smiley )

There are a few subtleties with the Is<type> / Parse() idiom. It's hard to avoid a race between the two commands, so you really need the try catch also in certain cases...

if( IsInt( some global string ) )
{
   Int32.Parse( some global string ) // hmm, is this the same string?
}

robust code would probably try/catch this, and it's easy to miss etc...?


Hi jj5...

jj5 wrote:

What are the cases where TryParse(String, ref Int32) significantly helps performance?


Here's an example. I have an app that reads a string from a database. Half the time this string is a datetime and half the time it's a name ( we've all worked on systems like this right Smiley ). In .net 1.1 i write code like:

DateTime d = DateTime.MinValue;
try
{
   d = DateTime.Parse( column );
}
catch( InvalidCatchException )
{
   // swallow
}

Put this code in a web service in a loop ( reading a recordset say), and then put the server under load.

Just reading 10 records per request ( 1/2 of which fail say ) will generate 1000s of exceptions per second in the asp.net wp and really wipe out your performance ( assuming web cpu is your bottleneck etc ). I've seen a number of server apps that are coded exactly like this.

The basic problem is that the Int class can't know what its consumer means by exceptional, so shouldn't impose policy like "anything not an int is an exception" etc...that's a decision only the user of the library can make.

Wow, my head is buzzing now!

 

I would like to go back to the bit of exceptions in server side code if possible. I come from a remoting background and have recently (last 3 months) moved in to the web service arena (and SOA??) and the exception handling model seems to have changed slightly.

 

Back in the days of remoting is was possible to throw an exception in the server side code and catch the same exception type in the client. But with web services it all comes back as SoapException which doesn’t have any inner exception information but does have a SoapFault element with a custom detail element. Presumably because of loose coupling etc etc.

 

I would like to ask the question of how exception management or faults should really be handled when coming out of web services and how this would map to in the future when Indigo is released.

 

Will Indigo allow exceptions to be sent back across the wire or will it be more like a SoapFault.

 

Is it normal to expect to handle application derived exceptions on the client side of a web service?

 

Lots of questions eh, but what a deep subject. Hope I'm not too off topic. 

Hey gravy....i know u don't i? Smiley...

i've asked the indigo guys on their plans in this area.

In the case of web-services the interop requirements make soap fault pretty much the only choice i think though ( u could have a java client on the end, right? )....


clint_hill
clint_hill
C-x,C-f

Exception handling is a tough topic to corral. I now work in a large development environment and even they have yet to formalize a standard exception handling methodology.


IMO, your code should reflect two things when considering exceptions:

1. Possible data entry
2. Possible data corruption

And the key word is obviously "possible". If you cover all possible entries (checking for type safety etc.) and then check for computational correctness then exception handling becomes very small in scale. This is the core. Find the exception. How you deliver it should be flexible. Log files, emails, bubble to the client and blue screen are all effective in getting the point across. (sarcasm on the bsod).

By no means am I an expert. And hardly a "seasoned" exception guru. But I follow this standard in all of my code. And some days it means I do hundreds of drivers for my objects with different data scripts until I find one that bugs out. Then I catch it, and start over. I like to think that if my applications actually get exceptions thrown (and they do without fail), I would hope to see what data caused it cause I will go to the source, add the catch and recompile.