Monday, November 14, 2011

Exceptions - More Expensive Than You Might Think

So, everybody knows that you shouldn't use exceptions in control logic right?  Meaning, you shouldn't expect exceptions to be thrown and you shouldn't plan on reacting to them under normal code execution circumstances, right?  Exceptions are, well, exceptional.  They are the exception, not the norm.

Recently I wrote some code where I violated this rule in a manner that seemed innocent enough to me.  I wrote an extension method for IDataReader that looked like this:










It's purpose was to check if a value exists in a data reader before trying to access it.  I was looping through a data reader to populate an object, and I was doing a lot of converts (ToBoolean, ToDateTime, ToDecimal, etc), so I wanted to make sure the values existed.  The column names matched property names on my object.  I was looping through the properties of the object using reflection, and not all the properties were being populated from the database call that populated the data reader, so an exception was being thrown quite often in TryGetObject, because a lot of the data didn't exist.

I had written a web service method that called the database stored procedure I was using.  Initially I noticed this was taking ~2.5 seconds to complete which I though was ridiculous.  After looking through my code I saw that this was the only "wrong" thing I was doing, so I replaced it with a method that loops through all the columns of the data reader to check if one exists.  This took my execution time down to ~150ms.  That's a decrease of well over ten-fold.

So the moral of the story is:  Exceptions are more expensive than you might think. 



Tuesday, November 1, 2011

How Uninstalling The .NET Framework Can Screw Up ODP.NET

Recently I started working on my first project that uses Oracle as the backend database.  Since Microsoft has deprecated the Oracle client built into the .NET framework, I am using ODP.NET from Oracle.  This client works well and follows the familiar patterns familiar to ADO.NET developers, i.e. Connections, Command objects, DataReaders, etc.

However, during development of the project I ran into a gotcha.  I saw some other blog posts describing this same fix and resolution, but I figured one more on explanation on the internet couldn't hurt, right?  More search results for the same problem :)

In the .NET Framework's machine.config file, DBProviderFactories for custom providers (i.e. non System.Data.Odbc, System.Data.OleDb, and System.Data.SqlClient providers) are listed in a <DBProviderFactories> element so the .NET Framework can instantiate connections them when you reference the provider in the provider attribute of the connection string.  In the case of the Oracle ODP.NET client, the entry looks like this:

My gotcha happened when I uninstalled the .NET Framework to try and fix some sort of unrelated corruption issue.  At the time I was unaware of this provider factory entry, so I was confused as to why ODP.NET would not work after I re-installed the framework.  I could not create a connection.  After a while, google finally told me that it is because the DBProviderFactory entry above was missing, since I re-installed the .NET framework and a fresh copy of the machine.config file was put on my machine. 

A quick re-install of ODP.NET fixed everything.  Fail on my part, I guess.