The last year and a half I have been working on a project based on .Net framework 1.1, that (among other things) involved handling multiple time zones. If you have ever worked on such a project you either did it wrong without knowing or you have spent a whole lot of time getting it nearly 100% right. The biggest problems are the XML serialization that always assumes en DateTime represents local time, and the lack of a specific Date-only data type which is time zone independent. When it comes to handling DateTimes in different time zones .Net framework 1.1 just doesn't cut it.
Framework 2.0 brings partly good news, only last week I happened to 'intellisense' over a new property on the DateTime structure; DateTime.Kind. It seems that Microsoft has found a use for 2 unused bits in the 64 bits that hold up the data for a DateTime structure. These 2 bits were not enough to store the actual UTC offset. Instead they choose for three possible values, Local, UTC and Unknown. This is a big improvement because it solves the incorrect XML serialization problem of UTC DateTimes.
The lack of the actual UTC offset in the DateTime structure still has the downside of not being able to handle time zones other than UTC or your own (the one configured in the regional settings) without storing the offset in a separate field and doing your own transformations. Of course the DateTime being a structure which cannot be inherited from doesn't really help to create a generic solution for this one. Second it causes an ambiguity in the hour in the fall when the clock shifts to daylight saving time. This can cause an UTC time being converted to local and back to UTC not to be the same as the original. Last time this happened some of our unit tests broke because the daily build cycle runs exactly within this hour.
Thursday, March 22, 2007
Monday, February 19, 2007
SQL Server 2005 vs. Office Web Components
Last week I installed SQL Server 2005 Developer Edition on a development PC. This took almost as long as installing an Oracle server, which is not what I am used to when running a 'routine' SQL Server Setup.
The SQL 2005 installer starts off with a check for all the prerequisites, and all lights were green. I choose an allmost default install of the client tools and the SQL instance itself. When half way installing the required components I got a message that I had a previous version of the 'Office Web Components' (OWC) installed. I needed to remove this previous installation and restart the setup of SQL Server. Bummer.
Checking the 'Add / Remove programs' applet I found that there was indeed a OWC XP version installed, after choosing 'Remove' and clicking through the dialogs I was ready for a retry. Starting up de SQL server setup again choosing the same options as before, all lights green again and …. 'a previous version of OWC is found, please uninstall and redo all the stuff you did twice before ….grrrrr.
Once again I fired up the add / Remove programs and found that now OWC 2003 was installed. Again I uninstalled it, did a reboot for safety and restarted the SQL Server Setup. What do you know… again the same message.
For the third time (of the forth I forgot the actual count) I uninstalled OWC from the Add / Remove programs applet and immediately after removing it I reopened the Add / Remove programs and It was still there!! Even after another reboot, uninstall etc etc the Add remove programs still showed OWC 2003 installed.
As a last resort I located the OWC11.msi on the SQL Server 2005 CD and reinstalled it directly from there. After this I was able to to re-run the SQL Server setup with no problem.
The SQL 2005 installer starts off with a check for all the prerequisites, and all lights were green. I choose an allmost default install of the client tools and the SQL instance itself. When half way installing the required components I got a message that I had a previous version of the 'Office Web Components' (OWC) installed. I needed to remove this previous installation and restart the setup of SQL Server. Bummer.
Checking the 'Add / Remove programs' applet I found that there was indeed a OWC XP version installed, after choosing 'Remove' and clicking through the dialogs I was ready for a retry. Starting up de SQL server setup again choosing the same options as before, all lights green again and …. 'a previous version of OWC is found, please uninstall and redo all the stuff you did twice before ….grrrrr.
Once again I fired up the add / Remove programs and found that now OWC 2003 was installed. Again I uninstalled it, did a reboot for safety and restarted the SQL Server Setup. What do you know… again the same message.
For the third time (of the forth I forgot the actual count) I uninstalled OWC from the Add / Remove programs applet and immediately after removing it I reopened the Add / Remove programs and It was still there!! Even after another reboot, uninstall etc etc the Add remove programs still showed OWC 2003 installed.
As a last resort I located the OWC11.msi on the SQL Server 2005 CD and reinstalled it directly from there. After this I was able to to re-run the SQL Server setup with no problem.
Friday, October 27, 2006
Show source file and line number information in your Stack traces
A while ago I wrote a blog-post about not breaking the stack trace while throwing an exception up the call stack. Stack traces are the very first place you look when finding the cause of an unexpected exception. Today I was once again saved by a stack trace. A project I am currently working on is starting a pilot in Cairo next week and had some trouble with a NullRefrenceException that was blocking one of the main scenarios. The entire pilot should be called-off, if this didn't get fixed right away.
Luckily the application's crash screen did not only allow me to view the exceptions stack trace (which is pretty common), but we had also deployed the compilers .PDB files along with the application's assemblies. PDB files contain (among other things) information about which IL-instruction corresponds to which source file and line number. The Visual Studio debugger uses this to place the yellow arrow at the next line of code that will be executed. Because most people don't debug on their production environment why should you deploy these files? By default Visual Studio doesn't even generate them for a Release build.
Besides assisting the debugger, the information in the .PDB files are also used at runtime when you call the Exception.ToString() method. At each level in the stack trace after the name of the executing method, the source file and the line number of the executing statement are added, if a PDB file is present for the assempley containing the method. This looks something like this.
System.NullReferenceException: Object reference not set to an instance of an object.
at Demo.Class1.Foo(Object parameter) in c:\projects\Demo\class1.cs:line 48
at Demo.Class1.Main(String[] args) in c:\projects\Demo\class1.cs:line 21
With this information I retrieved the correct version of the source file from source control (of course we label the sources with the build-number in our build cycle) and scrolled to the line number I had found in the stack trace. This showed me the exact statement that caused the NullReferenceException in less than five minutes, without having to reproduce the error in the development environment (which would have been quite tricky in this case). By only looking at the code I was able to see that someone had made a configuration error while installing the pilot environment. Correcting the configuration error fixed the problem and the pilot was ready to go. So unless you have good reasons to hide information about your source code from your end users, you should always set the compilers 'Generate Debugging Information' option to true for Release builds and keep the PDB files along side the assemblies wherever they go.
Luckily the application's crash screen did not only allow me to view the exceptions stack trace (which is pretty common), but we had also deployed the compilers .PDB files along with the application's assemblies. PDB files contain (among other things) information about which IL-instruction corresponds to which source file and line number. The Visual Studio debugger uses this to place the yellow arrow at the next line of code that will be executed. Because most people don't debug on their production environment why should you deploy these files? By default Visual Studio doesn't even generate them for a Release build.
Besides assisting the debugger, the information in the .PDB files are also used at runtime when you call the Exception.ToString() method. At each level in the stack trace after the name of the executing method, the source file and the line number of the executing statement are added, if a PDB file is present for the assempley containing the method. This looks something like this.
System.NullReferenceException: Object reference not set to an instance of an object.
at Demo.Class1.Foo(Object parameter) in c:\projects\Demo\class1.cs:line 48
at Demo.Class1.Main(String[] args) in c:\projects\Demo\class1.cs:line 21
With this information I retrieved the correct version of the source file from source control (of course we label the sources with the build-number in our build cycle) and scrolled to the line number I had found in the stack trace. This showed me the exact statement that caused the NullReferenceException in less than five minutes, without having to reproduce the error in the development environment (which would have been quite tricky in this case). By only looking at the code I was able to see that someone had made a configuration error while installing the pilot environment. Correcting the configuration error fixed the problem and the pilot was ready to go. So unless you have good reasons to hide information about your source code from your end users, you should always set the compilers 'Generate Debugging Information' option to true for Release builds and keep the PDB files along side the assemblies wherever they go.
Friday, September 29, 2006
Peek into the database during your unit test
Have you ever had the following problem?
You are debugging a unit test which has just inserted some records into your database. While the unit test is waiting on a breakpoint you want to see the result of the insert in the database. You start up SQL Query Analyzer type 'select * from customers' and hit. What happens? If you are lucky you get to see the table as it was before you started the unit test, if you are unlucky your query just 'hangs'. Now why is that?
Anyone who understands a little bit about transactions knows this must be because the insert is done inside a transaction which has not yet been committed. Therefore the result of the insert is isolated from any other database process or a table lock might even prevent you from reading the table at all.
When I ran into this (again) today I started thinking about it and found a solution which in fact is very simple. Before running your select * from customers you execute the command:
SET TRAN ISOLATION LEVEL READ UNCOMMITTED
The trick is that by setting the isolation level to 'read uncommitted' you can read the data that was inserted by the unit test code even though there might be table locks and the changes might eventually even get rolled back (which is usually the case in a unit test).
You are debugging a unit test which has just inserted some records into your database. While the unit test is waiting on a breakpoint you want to see the result of the insert in the database. You start up SQL Query Analyzer type 'select * from customers' and hit
Anyone who understands a little bit about transactions knows this must be because the insert is done inside a transaction which has not yet been committed. Therefore the result of the insert is isolated from any other database process or a table lock might even prevent you from reading the table at all.
When I ran into this (again) today I started thinking about it and found a solution which in fact is very simple. Before running your select * from customers you execute the command:
SET TRAN ISOLATION LEVEL READ UNCOMMITTED
The trick is that by setting the isolation level to 'read uncommitted' you can read the data that was inserted by the unit test code even though there might be table locks and the changes might eventually even get rolled back (which is usually the case in a unit test).
Sunday, September 24, 2006
Keep your hands off my stack traces!
When the first beta of the .Net framework was released one of the best features I thought was that the Exception.ToString() method shows you the stack trace from the place where the exception is thrown to where it is caught. Stack traces are your best friend when finding the cause of an unexpected exception. Back in the VB 6 time we spent a lot of effort harvesting this information ourselves.
This is why I get really upset when someone screws up the stack trace information by doing something like the following.
try
{
// method call that might throw an exception at some deeper level
some.Method();
}
catch (Exception ex)
{
// some code to figure out what to do with the exception (maybe logging or whatever)
// hmm in this case we do not really handle this exception after all, lets re-throw
throw ex;
}
What is wrong with this code? It is the 'ex' behind the throw. When you re-throw an exception this way the stack trace information in the Exception object is cleared and it will appear to who ever catches it at a higher level as if the exception originated from the location where it is re-thrown, thereby loosing valuable information about the location where the exception really occurred.
Inside a catch block you are allowed to use trow; (without an exception). The C# reference doesn't say very much about this, except that it is used when re-throwing the current exception object in a catch clause. Sounds like it is pretty much the same as when you do explicitly throw the exception you just caught as in the code example.
There is however a big difference that is not directly clear from the documentation. When you use throw without an exception you are actually saying "lets pretend I never caught this exception". This causes the Exception to be thrown further up while preserving the whole stack trace from the original throw to the next catch up the call stack.
Now pretty please, with sugar on top, use throw; instead of throw ex; inside a catch block, and leave my stack trace alone!
This is why I get really upset when someone screws up the stack trace information by doing something like the following.
try
{
// method call that might throw an exception at some deeper level
some.Method();
}
catch (Exception ex)
{
// some code to figure out what to do with the exception (maybe logging or whatever)
// hmm in this case we do not really handle this exception after all, lets re-throw
throw ex;
}
What is wrong with this code? It is the 'ex' behind the throw. When you re-throw an exception this way the stack trace information in the Exception object is cleared and it will appear to who ever catches it at a higher level as if the exception originated from the location where it is re-thrown, thereby loosing valuable information about the location where the exception really occurred.
Inside a catch block you are allowed to use trow; (without an exception). The C# reference doesn't say very much about this, except that it is used when re-throwing the current exception object in a catch clause. Sounds like it is pretty much the same as when you do explicitly throw the exception you just caught as in the code example.
There is however a big difference that is not directly clear from the documentation. When you use throw without an exception you are actually saying "lets pretend I never caught this exception". This causes the Exception to be thrown further up while preserving the whole stack trace from the original throw to the next catch up the call stack.
Now pretty please, with sugar on top, use throw; instead of throw ex; inside a catch block, and leave my stack trace alone!
Subscribe to:
Posts (Atom)