Tech Off Thread

25 posts

Error Handling, use exceptions?

Back to Forum: Tech Off
  • User profile image
    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

  • User profile image
    gmiley

    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.

  • User profile image
    spod

    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

     





  • User profile image
    gmiley

    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.

  • User profile image
    aza

    I recall reading that chapter in the past and subsequently becoming wary of using exceptions excessively. It's hard to disagree with what it says with regards to performance but with respect to programming flexibility and elegance exceptions are, to my mind at least, a superior approach to putting information into method return values.

    The article states that exceptional paths should only be taken less than one time in a thousand. But at the same time a lot of the .Net base libraries throw exceptions at the drop of a hat.

    A classic example is System.IO.File, whenever an attempt is made to open a file exceptions will be thrown if the file doesn't exist, the user doesn't have permission, the file is already locked etc. To me this makes perfect sense. If the Open method just returned false my application would then have to look somewhere else to find out why the file could not be opened.

    My, rather long winded, point is that exceptions maybe aren't good in situations needing optimal performance, such as ASP.Net, but they are a pretty good way to handle and promulgate error information otherwise!

    I am starting to think that I should use exceptions more in client side code rather than less. If a method has three input parameters needing validation wouldn't it be better to throw an exception to inidcate how the parameters are incorrect rather then just returning false or something?

    Regards,
    Aaron

  • User profile image
    FluffyDevil​Bunny

    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.

  • User profile image
    Charles

    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

  • User profile image
    jj5

    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.

  • User profile image
    aza

    I think the art of exception management is knowing where to use try-catch blocks. Over the last couple of years I find myself using less and less of them and now tend to place them only in the top level consumer classes (of course there are always exceptions).

    I am more concerned with throwing exceptions as a way of tranferring information about an error condition. If an exception isn't thrown then the caller has to check for an error condition after the method call has returned. The latter can get onerous especially when the mechanism to check for error conditions varies across different modules. Exceptions present a standard way to transfer the error details and have the added benefit that they can be allowed to bubble up if the caller doesn't want to handle them.

    From the msdn chapter referenced by spod one of the guidelines for exceptions is:

    "Do not use exceptions to control application flow"

    The reason being that exceptions are expensive. However exceptions make the code much more intuitive and the .Net base class libraries seem to ignore the guideline. I wonder if it really is that expensive in a "typical" managed application?

  • User profile image
    spod

    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...
     

  • User profile image
    Charles

    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 

  • User profile image
    jj5

    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.

  • User profile image
    aza

    In addition isn't this a deviation from most of the other base class libraries? I can't recall ever using a reference parameter to check for an error in the .Net libraries...in Win32 yes.

    Personally I think one of the strengths of .Net is its uniformity. Even if a mechanism isn't perfect for every situation it makes life a lot easier if the mechanism is already known, i.e. the same in all base classes. 

    IsValid and Parse (with an exception) seem a lot more intuitive then TryParse. 

    Aaron

  • User profile image
    jj5

    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.

  • User profile image
    risu

    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.

  • User profile image
    spod

    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...?


  • User profile image
    spod

    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.

  • User profile image
    Gravy

    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. 

Comments closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.