CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Karl Seguin

.NET From Ottawa, Ontario - http://twitter.com/karlseguin/

April 2006 - Posts

  • PHP vs ASP.NET

    Do a Google search for "PHP vs ASP.NET" (or "ASP.NET vs PHP") and the first hit you'll get is a seemingly well-written Oracle article. When the article was first published, the .NET community certainly made note of it.  There's actually a follow up article by the same author, but he only skirts around the mistakes he made and never really corrects them.

    This is exactly the kind of crap I was talking about earlier. Macromedia might write documentation with horrible code examples, but Oracle flat out lies. Shouldn't we expect more from Oracle? There's a fine print at the bottom of the article that says "The opinions expressed by this author are entirely his own and do not reflect the position of Oracle or any other corporation." That's of little value when it shows up on oracle.com and as the first hit on Google.

    Honestly, who would ever buy a product/service from Oracle or iHeavy Inc. (the author's employer) when they clearly don't know what they are talking about? Sean Hull's article shows that opinions can be wrong, and ignorance is still king. I'm calling Sean out and daring him to prove me wrong!

    Object Oriented:
    So according to Sean, PHP 5 and ASP.NET both have "strong" object oriented capabilities. It's true that PHP5 language supports every important OO concept, but that's just one part of the equation. Anyone remotely familiar with the ASP.NET or WinForms control model knows that for .NET, being object oriented goes beyond the language.  In ASP.NET, html markup is represented as server-side objects. This provides the ability to easily program against controls as well as extend them.  Gone are the day of procedural includes, you now include an object you can program against. This is a non trivial difference that's at the core of the two platforms.  PHP5 has really good OO support, but compared to ASP.NET it isn't remotely close .


    Exceptions:
    Both PHP5 and ASP.NET support exceptions. Funny how your PHP code uses db_check_errors() for it's "exception handling". Is that how you handle exceptions in PHP? Funnier still is that your ASP.NET example doesn't have any exception handling (or the fact that this ASP.NET example uses Console.WriteLine). If you ignore the fact that PHP5 doesn't have a finally (or using), which is pretty minor, the fact is a number of built-in functions don't throw exceptions nearly as much as they should. Let's take a look at the PHP documentation for opening a connection to oracle:

    $conn = oci_connect('hr', 'hr', 'orcl');
    if (!$conn) {
       $e = oci_error();
       print htmlentities($e['message']);
       exit;
    }


    So PHP5 has good support for exceptions, but you'll mostly be checking return values to see if an exceptional situation occurred. Joel Spolsky might switch to PHP.


    Speed and Efficiency:
    PHP5 is quicker than ASP.NET because Sean said so. No benchmark code is provided. It just is! It's really hard to argue against such a phantom point.  I will say that PHP5 doesn't have a caching API out of the box or support for OutputCaching (you need a Pear library for that sort of stuff).  Oh ya, PHP5 is also more efficient, but there's no explanation as to what that means.


    Price:
    Any price comparison that doesn't take into account total cost of ownership is incomplete. Sean himself admits that "PHP is the quick and dirty type of solution". I know the TOC argument is thrown around by Microsofties a lot. But any experienced developer knows that maintenance cost can far outweigh all other costs. If PHP really is a quick and dirty (and it really is), shouldn't a sane business owner be worried about how easily and quickly they'll be able to maintain it?

    I know this is an old article and most have let it go, but I feel duty bound to clear up some of the FUD. I work with PHP daily, and I do like it.  I plan on making a post about why you would pick PHP over ASP.NET (ie, if you are using the SqlDataSource, just switch to PHP now). But Sean clearly has no idea what he's talking about.

  • ASP.NET 2.0 Is NOT a Silver Bullet

    Before the first concrete information about 2.0 came out, promises about massive code reduction were being made.  "I can't say too much at this point...one of our aggressive goals is to reduce the number of lines of code between v1 and v2 by 70%". Every book, article and blog quoted that oft-repeated line from the ASP.NET development team.  Even when 2.0 was still a year away, we were told that goal was almost reached. Glory hallelujah!. Fast forward to today, months after the 2.0 RTM and you'll quickly realize there is no silver bullet (heck if OO couldn't do it for us, we were fools to ever believe ASP.NET would).

    Every developer thinks his or her code is going to save users and clients 70% of their time. Every time I build a new application I envision mass-workload reductions and international "Karl Seguin" holidays. It's some type of global developer hubris (in the modern sense, not the Greek one), and Microsoft developers are far from immune. But aside from the forgivable enthusiasm, why aren't I (and I assume most people) writing 70% less code?

    First, I consider myself an ASP.NET developer, but I probably spend less than 25% of my time in aspx and codebehind files.  Most of my time is spent in my domain, data access and data layers. Much time is sent writing modules, handlers and server controls. Even if I managed a 70% code reduction, it'd only put a small dent in my overall coding.

    That point aside, I do think some of the time saving features were just blown out of proportion.  One of my favorite example is everything revolving around the new Membership provider.  Yes it's great and yes I use it. But I needed it's functionality over 3 years ago, so I built my own. I was already saving code by using composite controls for my login, registration and password retrieval along with a flexible business and data model. The 2.0 stuff is better than mine, but it doesn't save me from writing any code I didn't already have.

    Secondly, much of the reduced code comes with strings attached. Take the built-in paging and sorting of the datagrid or the gridview. You'll end up paying a huge performance hit for any medium-to-large data set (not necessarily DataSet). Anyone who's had to page results with any type of performance implication _always_ does this at the data layer. Then there's the SqlDataSource, which I love picking on. Sure you can write this application with few lines of code, just forget everything you ever learnt about programming.

    Thirdly, declarative code is still CODE. Not to be rude, but it's bullshit that 5 lines of code to declare my ObjectDataSource in my aspx should be considered as less code than the 2 lines it took to bind to my [highly reusable] business layer. Yes, a designer generated it (btw, clicking next 3-4 times still takes longer to do than to write those 2 very short lines), but a human will have to maintain it.

    You want to know what really makes me productive? Spending time upfront to properly architecture my application.  Making use of libraries, such as Log4Net and Patterns and Practices code block (along with my own, for example localization). Generics are the real 2.0 feature that save me a ton of code (nullable types are a let-down).  Tools like SourceGear's vault, JetBrain's Resharper, DevExpress' CodeRush and CodeSmith Tools's CodeSmith are key. Not to mention everything made by Red-Gate.

    It seems that the only sites that benefit from any code reductions are either the ones being developed by bad programmers or the ones that had little code to begin with. Sure, I'll drag and drop a couple controls for my dad's webpage, and it'll save me 30 minutes - great.  But for the sites I spend months working on, saving 30 minutes upfront is going to violently bite me in the ass.

    The ASP.NET team is passionate and excited about what they do. That's really all I'm accusing them of. I don't feel lied to whatsoever. I am somewhat skeptical of the MS Marketing machine (95% caused by longhorn, 5% from continuously losing anti-trust lawsuits), but I don't think that's intentionally what happened here.

    I do have two fears. First it's that the ASP.NET team may be disconnected with .NET developers in some respect (a topic I want to explore in greater depth another day). More of a concern is that little material is created from the ASP.NET team about sound design and architecture. Every time a demo, tutorial or whatever includes an SqlDataSource, an angel looses its wings.

    By way of closing, it must be stated that I hate posts with negative undertones that start off with an apology - they always seem so fan-boyish. The phrase "don't get me wrong, I love XXX; but..." makes my ears bleed. Obviously I feel my complaint is legitimate (I hope if you disagree you'll let me know), but I don't think it's a huge issue, more like food for thought.


  • Getting the day's name in TSQL

    Surely there's got to be an easier than this, but so far it's the best I've got:

    ALTER FUNCTION GetWeekdayName
    (
       @Weekday INT
    )
    RETURNS VARCHAR(9)
    AS
    BEGIN
       DECLARE
    @temp INT,
               @return VARCHAR(9)

       SET @temp = @@DATEFIRST + @Weekday
       IF (@temp > 7) BEGIN
          SET @temp = @temp - 7
       END

       SELECT
          @return = CASE @temp
             WHEN 1 THEN 'Sunday'
            
    WHEN 2 THEN 'Monday'
            
    WHEN 3 THEN 'Tuesday'
            
    WHEN 4 THEN 'Wednesday'
            
    WHEN 5 THEN 'Thursday'
            
    WHEN 6 THEN 'Friday'
            
    WHEN 7 THEN 'Saturday'
          END

       RETURN @return
    END

    This ought to work regarldess of the DATEFIRST setting

  • I'll be at REAL Development - Ottawa

    I won't get the chance to go to TechEd this year Crying [:'(]  but I will be at MSDN'S upcoming REAL Development in Ottawa (Canada) which focuses on new web technologies and security. Not exactly sure yet how I'm going to be participating, but I hope I'll see some of you there.

    It's being held on May 30th at the Coliseum (no,not Scotia Bank Place, the other coliseum)

    Sign up for free at:
    http://msdn.microsoft.com/canada/realdevelopment/

  • Paging Data - MySQL > Microsoft

    A little while ago, Scott Guthrie talked about record paging in his post "Paging through lots of data efficiently (and in an Ajax way) with ASP.NET 2.0". The important part of the article doesn't have much to do with ASP.NET or Ajax, but rather the new ranking capabilities found in SQL Server 2005. If you've done data paging before, or just think about it for a second, that shouldn't be much of a surprise. Without question, "efficiently" paging through data has to happen directly on the database.

    The alternative to paging data at the database is to page it in ASP.NET. The DataGrid and GridView controls make it easy to page data in ASP.NET, but there's a price to be paid - performance. I know a lot of people are put off by micro optimizations (which you should be), but in my experience, paging even a bit of data under moderate load can have significant performance implications. Instead of simply returning the 10 rows from the database, you need to return all of the rows and let ASP.NET figure our which are the right ones to display. If your data is wide (a lot of columns) or you have a lot of rows, your site will suffer significant performance issues.  You should only use the built-in paging when you know you have very few records - say under a thousand - oh, and make sure to optimize that viewstate!

    Before SQL Server 2005 came out, paging was frustratingly difficult. Ideally you'd be able to rely on an auto-genarated id and simply pick all records where the ID is between 1-10, 11-20, 21-30...But that only works if you can guarantee that there are no holes in your IDs, which likely you can't. One solution, the one I prefer, is to create a temp table (or a table data type), that has an auto id in it. Something like:

    DECLARE @records TABLE(RowId INT IDENTITY(1,1), TableId INT)

    INSERT INTO @records
       SELECT ProductId
       FROM Products
       WHERE Price <= @MaxPrice
          AND Price >= @MinPrice
          AND Category = @CategoryId
       ORDER BY ProductId

    --get the total number of matching products
    SELECT COUNT(*) FROM @records

    --get the data

    SELECT p.ProductId, [Name], Price, ImageUrl
       FROM Products p INNER JOIN @records r ON p.ProductId = r.TableId
       WHERE p.RowId > 0 AND p.RowId < 11 --these would be passed in



    Although just a sample, the above code shows how you can create a temp table and create a series of id's with no holes. The temp table is kept extremely narrow (2 small columns) and short (the filtering is applied upfront), and is joined back against the main table. It ends up working very well. But it's a serious pain in the ass - especially when you consider how basic this is.

    Since the dawn of SQL Server, people have been going about banging their heads on the best way to do this, begging Microsoft to implement a good solution. Disappointed by SQL Server 7 and 2000, the team behind 2005 finally decided to help out. With the new ranking functions, we end up with:

    WITH PagedProducts AS
       (
          SELECT ROW_NUMBER() OVER (ORDER BY ProductId) AS RowNumber, ProductId, [Name], Price, ImageUrl
          FROM Products
          WHERE Price <= @MaxPrice
             AND Price >= @MinPrice
             AND Category = @CategoryId

       )
    SELECT ProductId, [Name], Price, ImageUrl
    FROM PagedProducts
    WHERE RowNumber BETWEEN 1 AND 10

    It's a step in the right direction, but I consider the above code overly complicated for the common task we are trying to accomplish. Why did the SQL team decide not to implement the oft-begged for MySQL LIMIT keyword? Even if LIMIT simply abstracts away the above code, it's embarrassingly simple:

    SELECT ProductId, [Name], Price, ImageUrl FROM Products LIMIT 1,10

    The ranking functions are meant to do more than just paging and that's great if you want to do more than just paging. But I'm convinced that paging is so fundamentally necessary to most applications, it deserves it's own straightforward keyword.

    If you need to page results, MySQL's LIMIT keyword continues to be more handy than anything the .NET or SQL teams have managed to do.

  • Consuming .NET with Flash

    Ever since joining Fuel Industries, I've had a new found respect for Flash development. Flash isn't well suited for every types of development, for example I wouldn't want to see google.com fully implemented in flash! When it comes to adver-gaming, which Fuel Industries is a leader of, Flash rules supreme (although more and more of our development is moving towards Virtools). You simply can't build the same type of web-based immersion/branding in HTML/ASPX (even with Atlas/Ajax). We even build traditional web-based intranet application using Flash frontends. The end result is always something that impresses me a lot.that seems much more desktop-based than web-based.

    Flash is just a presentation layer however, so how can it consume a business layer? The best solution is to use Macromedia's Flash Remoting Technology, which uses a proprietary binary stream (AMF) to communicate with server-side code. Anyone familiar with AJAX should have a good feel for Flash Remoting. The main difference being that you aren't using JavaScrit or XML - but rather ActionScript and AMF.

    The problem with Macromedia's Flash Remoting technology is the cost. It's about $1000USD - which isn't cheap. (the other problem is the "crapstically" written documentation, which I've railed against before). In response to the high price, a group of PHP developers created the highly popular AMFPHP - an open source alternative for PHP. This led to the development of OpenAMF - an open source alternative to Java. The first thing I was tasked with at Fuel was to create an open source .NET alternative - AMF.NET. 

    (there were some .NET alternatives already available, namely Fluorine, but I had some strong reservations against it).

    Knowing little about Flash, my main goal was to make the process of consuming .NET code as transparent as possible. As a presentation layer, Flash should have no impact on how the business layer is implemented. The biggest problem I ran into was the disparity between data types. Of particular interest was the fact that all numeric types in AMF are treated as doubles. So if you call a server side function and pass the integer value 10, it'll get converted to 10.0. A lot of the work AMF.NET does is iron out those riples so your C# or VB.NET code can be written like you'd expect - with an int and not a double and with no extra attributes.

    AMF.NET is implemented as an HttpHandler. So all you need to do is drop the DLL in your bin folder, add a line to your web.config and you're good to go. If you want to let your server-side code get called form multiple domains, you'll also need to dro a crossdomain.xml on the server (more info here)

    It just takes a couple of lines of ActionScript to execute a remoting call:

    var service:Service =
      new Service(
          'http://www.openmymind.net/FuelAmfGateway.aspx',
          null,
          'Company.Security, Company');

    var pc:PendingCall = service.GetUser(1);
    pc.responder =
       new RelayResponder(
             this, 'onSuccess',
             'onFault');
    function onSuccess(re:ResultEvent)
    {   
        trace(re.result.UserName);
    }


    A new service is created and pointing to our HttpHandler. Notice that the service is using the standard .NET type naming to specify the type (namespace.class, assemblyName). We can then call server side method (GetUser) which accept parameters and handle the response.

    So far, AMF.NET has been used on three relatively small projects here. For example, we used it in Hershey's Take5 candy bar game (http://www.hersheys.com/take5/). As we continue to use it, we'll build onto AMF.NET - but so far it's proven extremely capable of doing this simple jobs - and there's no reason to think it can handle a lot more as-is.

    Both the PHP and Java projects were hugely useful in creating AMF.NET. Fiddler was also incredibly useful.

    You can learn more about AMF.NET form the official homepage:
    http://amfnet.openmymind.net/

  • code better - use string.format

    Poorly handled exceptions might speak volumes about someone's coding abilities, but it's string concatenation that's a sure bet to kill a programs readability (thus maintainability). Everyone knows that they should use StringBuilder's for better performance when concatenating a lot, but to improve maintainability, string.format is king!

    On the topic of performance though, you'll be glad to know that there's also an AppendFormat method to the stringbuilder class - so readability and performance aren't exclusive concepts!

    Surely, I can't be the only one that has a hard time writing and maintaining code like:
    document.SelectSingleNode("/graph/data[name='" + name + "']");

    When I do write code like the above, I almost always forget my closing quote or square bracket! And as things get more complicated, it becomes a flat out nightmare.

    The solution is to make heavy use of string.Format. You'll never EVER see me use + (or & in VB.NET) to concatenate something to a string, and there's no reason you should either. To write the above code better, try:
    document.SelectSingleNode(string.Format("/graph/data[name='{0}']", name));

    Personally, even though it's a simple example, I find it a lot better - and as things get more complicated you'll be laughing as you code. But wait, there's more!  string.Format uses string formatting - so you have a lot of control over how objects are turned into strings. So you coul do
    string.Format("Your score is {0:p}", student.FinalExam.Score); 
    which would format the float score into a percentage.

    Understanding .NET String formatting is important because (a) it'll make it so you never ask a question about how to get a date in a certain format, (b) how to get a number in a certain format and (c) it's used all over in .NET.  For example, that DataBinder.Eval() method actually accepts a 3rd parameter which is the string formatter to use.

    Now, like I said earlier, you can also use AppendFormat of the StringBuilder class

    StringBuilder sb = new StringBuilder();
    sb.Append("<books>");
    foreach(Book book in author.Books)
    {
       sb.AppendFormat("<book isbn=\"{0}\">{1}</book>", book.Isbn, book.Name);
    }
    sb.Append("</books>");

    A word of caution. String.format IS NOT a substitute for using command parameters. But dang, it is sweet for almost everything else!
  • Understanding and Using Exceptions

    (this is a really long post...only read it if you (a) don't know what try/catch is  OR (b) actually write catch(Exception ex)  or catch{ })

    The first thing I look for when evaluating someone's code is a try/catch block. While it isn't a perfect indicator, exception handling is one of the few things that quickly speak about the quality of code. Within seconds you might discover that the code author doesn't have a clue what he or she is doing. It may be fun to point and laugh at, but poor exception handling can have a serious impact on the maintainability of a system. Proper exception handling isn't very difficult, technically there's nothing to it. It all comes down to grasping the fundamentals.  Too many developers consider exceptions dangerous to the health of a system. If you come from an exception-less language, you might be cursing Microsoft developers for ever having introduced them in the framework.

    All exceptions in the .NET framework inherit from the base System.Exception class. This class exposes a handful of members you are likely familiar with, such as StackTrace and Message. Exceptions are raised by the framework, a library you are using or your own code when an exceptional situation occurs. While I don't often run into over zealous use of exceptions, it is important to understand that they are meant to be used for truly exceptional scenarios. For example, if a user's registration fails because the email is already in use, throwing an exception might not be appropriate. You'll often hear people say "only use exceptions in exceptional cases", as I just did. This is very sound advice when throwing your own exception, but what about catching and handling exceptions? Well the fundamental point to understand is the same, when an exception does get thrown, be aware that something truly exceptional happened.  That might sound a little bit obvious, but a common example will show just how poorly understood the point is:

    try
      connection.Open()
      command.ExecuteNonQuery()
    catch
      return false
    end try


    You might have seen, or even written, similar code before. In a previous blog post, I pointed out almost identical code in official Macromedia documentation. There's actually more than 1 problem in the above code, but let's focus on the catch block - the place the exception is supposed to get handled. Does anyone see the exception being handled? It isn't. Instead, we've been warned that something truly bad has happened, and swept it under the rug. This is known as exception swallowing, and it's a sure sign of someone who's afraid of and doesn't understand exceptions. If you truly understand that an exception is a sign of an exception situation, you'll never dare sweep it under the rug!

    If you aren't supposed to swallow them, what's the game plan going to be? The first thing to realize is that much more often than not, there's nothing you'll actually be able to do with exceptions. If I was to guess as to why developers get hung up on exceptions, I'd have to say this is it. For many developers, having an exception bubble up through code, where it'll eventually cause the application to crash, seems unimaginable. For some reason, these same developers don't seem to be too worried about not being able to connect to their database - we'll just return false. The simple truth is that if you can't actually handle the exception, don't. We'll implement logging and friendly error messages much higher up in the code, where it can be globally reused and easily maintained. If the above code makes it to a production server, no error message will be displayed, no meaningful data will be recorded and it might take hours (or days) before you even know something's wrong.

    Rethrownig exceptions
    Does that mean that you should never catch exceptions? Not necessarily, but you need to be careful what you do in there. One of the few technical hangups developers have is how to rethrow a caught exception. Since it might not be obvious at first why you'd do that, let's look at an example. Pretend we've build code that allows user's to register. Our code will first enter the record into the database (assuming all business rules pass), and then send a confirmation email out that details how the account can be activated. If sending out the email fails, we'll want to remove the record from the database so that the user can try again with the same username/email (else he or she will get an error saying the username or email is already in use). With proper use of exceptions, this is a simple matter to accomplish:

    try
    {
      Emailer.SendNewUserActivation(this)
    }
    catch (SmtpException ex)
    {
      this.Delete();
     
    throw;
    }


    In the above code we haven't handle the exception, but we've done some important cleaning up. The code can't go in the finally clause because that's called on failure AND success (and we don't want to delete the record if everything was a success).  The real gem in the code is the throw statement. This keeps the exception on the stack, where it'll bubble upwards. The calling code won't know that we ever caught the exception and did a bit of internal house-cleaning - which is just what we want because we did nothing to handle the exception.

    (in the comments below, Mark Kamoski has some alternative solutions to the code above (along with some concerns) that I think are worthwhile, so scroll down and find his post!)

    There are two variations to the code above. Instead of simply using throw; we could actually use throw ex;. The difference between the two, though subtle, it quite important to understand. When you use throw ex; you'll modify the call stack and make it look like your code was the source of the exception. You are effectively throwing away useful debugging information. As I've said before, when you simply throw; it's as though you didn't do anything at all! We'll talk more about throwing your own exceptions in a later post, but if you want to actually be involved in the exception bubbling chain, it's generally better to throw a new exception and specified the caught exception as the inner exception, such as:

    throw new SomeTypeOfException("User Activation send failed", ex);

    Cleaning up after yourself
    If you follow my advice (and I'll give you a much better source than just my own word soon), you'll end up with very few Try/Catch statements. Instead what you should be using are Try/Finally statements, or the using statement.  While you might not be able to handle an exception, you can certainly clean up after yourself. Most people know this, but finally happens whether an exception is raised or not, and is pretty much guaranteed to happen - so you can return in your try block and rest easy knowing your finally cleaned up your resources. Here's an example:

    dim connection as new SqlConnection(GET_CONNECTION_STRING_FROM_CONFIG)
    dim command as new SqlCommand(connection)
    '...set stuff up
    try
      connection.Open()
      'might wanna check for DbNull or something
      return cint(command.ExecuteScalar)
    finally
     connection.Dipose()
     command.Dispose()
    end try


    If you instantiate your code inside the try, make sure to check for nothing before disposing:

    dim connection as SqlConnection
    dim command as SqlCommand
    try
      connection = new SqlConnection(GET_CONNECTION_STRING_FROM_CONFIG)
      command = new SqlCommand(conection)
      '...set stuff up
      connection.Open()
      'might wanna check for DbNull or something
      return cint(command.ExecuteScalar)
    finally
     if (not connection is nothing) then
        connection.Dipose()
     end if
     if
    (not command is nothing) then
        command.Dispose()
     end if
    end try

     
    The above code is a little messy, which is exactly why C# and VB.NET (as of 2005) support the using keyword:

    using (SqlConnection connection = new SqlConnection(...))
    {
      using (SqlCommand command = new SqlCommand(...))
      {
        //..set stuff up
        connection.Open();
        return Int32.Parse(command.ExecuteScalar);
      }
    }


    I've heard some people say they dislike nested using statements, but if you compare the two examples, I think it's much cleaner, readable and less error prone.

    More on actually catching exceptions
    Now there are some times when you'll be able to handle an exception. Everyone knows that you always catch specific exceptions first and work your way towards the base exceptions. You should also, never-ever catch System.Exception. Say we wrote code that took a query string value (or any string for that matter) and tried to turn it into an integer. If it fails, we want to default to a given value. You might write something like:

    public static int ParseInt(string value, int defaultValue)
    {
     try
     {
      return Int32.Parse(stringValue);
     }
     catch(Exception ex)
     {
      return defaultValue;
     }
    }


    That's wrong. What happens if Int32.Parse threw a ThreadAbortException or an OutOfMemoryException, does returning a defaultValue handle those exceptions? No. Instead, you need to catch only the specific exceptions you are handling:

    try
    {
      return Int32.Parse(stringValue);
    }
    catch (FormatException ex)
    {
     return defaultValue;
    }
    catch (InvalidCastException ex)
    {
     return defaultValue;
    }
    catch (OverflowException ex)
    {
     return defaultValue;
    }


    Of course, that can be a serious pain to write and maintain. The solution is to apply what we learnt earlier about rethrowing caught exceptions:

    try
    {
     return Int32.Parse(stringValue);
    }
    catch (Exception ex)
    {
      if (!(ex is FormatException) && !(ex is InvalidCastException) && !(ex is OverflowException))
      {
        throw;
      }
      return defaultValue;
    }

    While it's true I said that you should never catch Exception, notice that it's being rethrown (using throw;) if it isn't the expected type. This works just as well in VB.NET, or you can even use VB.NET's when clause.

    Global Error Handling
    If you've made it this far, you might be getting a little panicked. Since we aren't catching exceptions left and right, they'll bubble until they crash the system. Well that's where global exception handling comes in. It lets us write, in a centralized (i.e., easy to change) way, any exception logging we want and how to display the error in a friendly manner. Now I'm getting a little tired of typing, but here's the httpModule I use to get the job done (notice it relies on log4net to do any logging). If you aren't familiar with httpModules, and you don't want to bother learning, you can take the code from application_error and stick it in your global.asax's application_error.

    using System;
    using System.Web;
    using log4net;

    namespace Fuel.Web
    {
       public class ErrorModule : IHttpModule
       {
          #region Fields and Properties
          private static readonly ILog logger = LogManager.GetLogger(typeof(ErrorModule));
          #endregion

          #region IHttpModule Members      
          public void Init(HttpApplication application)
          {
             application.Error += new EventHandler(application_Error);  
          }      
          public void Dispose() { }
          #endregion

          public void application_Error(object sender, EventArgs e)
          {
             HttpContext ctx = HttpContext.Current;
             //get the inner most exception
             Exception exception;
             for (exception = ctx.Server.GetLastError(); exception.InnerException != null; exception = exception.InnerException) { }
             if (exception is HttpException && ((HttpException)exception).ErrorCode == 404)
             {
                logger.Warn("A 404 occurred", exception);
             }
             else
             {
                logger.Error("ErrorModule caught an unhandled exception", exception);
             }
             ctx.Server.ClearError();
             //if you want, you  can simply redirect to a generic "oops, an error occurred page" ala:
             //this is what I recommend until you get into creating your own exceptions
             //Response.Redirect("error.asx");

             
          }
       }
    }


    What if you disagree with me?
    You might disagree with what I've said. You might even point to this MSDN reference that supposedly tells you how to handle exception: http://msdn2.microsoft.com/en-us/library/24395wz3.aspx.  In it you'll find very different advice, namely:

    "It is preferable to use Try/Catch blocks around any code that is subject to errors rather than rely on a global error handler."

    I'll counter that crap (and i am trying to get it corrected, because it IS flat out wrong), with a quote from Anders Hejlberg (you know, the lead architect for C#, one of few Microsoft distinguished engineers, the inventor of TurboPascal and a lot more):

    "No, because in a lot of cases, people don't care. They're not going to handle any of these exceptions. There's a bottom level exception handler around their message loop. That handler is just going to bring up a dialog that says what went wrong and continue. The programmers protect their code by writing try finally's everywhere, so they'll back out correctly if an exception occurs, but they're not actually interested in handling the exceptions.

    The throws clause, at least the way it's implemented in Java, doesn't necessarily force you to handle the exceptions, but if you don't handle them, it forces you to acknowledge precisely which exceptions might pass through. It requires you to either catch declared exceptions or put them in your own throws clause. To work around this requirement, people do ridiculous things. For example, they decorate every method with, "throws Exception." That just completely defeats the feature, and you just made the programmer write more gobbledy gunk. That doesn't help anybody.

    It is funny how people think that the important thing about exceptions is handling them. That is not the important thing about exceptions. In a well-written application there's a ratio of ten to one, in my opinion, of try finally to try catch. Or in C#, using statements, which are like try finally.

    In the finally, you protect yourself against the exceptions, but you don't actually handle them. Error handling you put somewhere else. Surely in any kind of event-driven application like any kind of modern UI, you typically put an exception handler around your main message pump, and you just handle exceptions as they fall out that way. But you make sure you protect yourself all the way out by deallocating any resources you've grabbed, and so forth. You clean up after yourself, so you're always in a consistent state. You don't want a program where in 100 different places you handle exceptions and pop up error dialogs. What if you want to change the way you put up that dialog box? That's just terrible. The exception handling should be centralized, and you should just protect yourself as the exceptions propagate out to the handle."

    (you can read the entire interview here, very good read, especially if you come from a Java backgorund)

    Make sure to read that and understand that well, because it's all amazing advice and the real foundation of what you need to know with respect to exception handling.

    In Closing:
    Here are the key points:
    - Don't catch exceptions unless you can actually handle them
    - Do know how to rethrow exceptions properly
    - Do use using or try/finally often
    - Don't swallow exceptions
    - Do use a global handler to help you log and display a friendly error message

    I did want to talk about creating your own exceptions, but I think I'll save that for another post.
More Posts

Our Sponsors