Using Nant for Metabase backup on 64bit Windows Server 2003

January 28, 2009 at 4:26 PMAndre Loker

For while now I’ve been using NAnt not only as a build tool but also as the tool running all my backup tasks, such as:

  • database backups
  • Subversion repository backups
  • mail backup
  • website backup

I’ve also used it to create backups of the IIS Metabase using the iisback.vbs script, which works perfectly smooth as long as it is running on a 32 bit Windows.

I’ve been trying to backup the IIS Metabase on a 64 bit Windows Server 2003 server for a while now, but for some reasons I could not make it work. If I tried to call the script directly using the commandline, e.g.

   1: iisback.vbs /backup /s localhost /e something /v NEXT_VERSION 
   2:       /b Metabase123 //E:vbscript

it would ran perfectly fine. However, when executed as a NAnt task I got an error:

Could not create an instance of the CmdLib object.
Please register the Microsoft.CmdLib component.

After digging in the dark for a while I found an interesting forum thread of somebody with a similar problem. So I more or less did what has been proposed in that thread:

  1. I copied cmdlib.wsc over from %WINDIR%\System32 to %WINDIR%\SysWOW64
  2. I also copied isschlp.wsc the same way
  3. I registered cmdlib.wsc and isschlp.wsc using regsvr32 cmdlib.wsc and regsvr32 isschlp.wsc respectively

At that point my NAnt script was happy again and created the backups.

The reason and more trouble

As far as I understand the problem was that NAnt is for some reason running as a 32 bit application. On 64bit Windows boxes, the System32 folder contains the 64bit binaries whereas the SysWOW64 folder contains the 32bit versions. Frankly, this is not the most intuitive naming ever, but it has a reason. If a 32 bit application is running the System32 folder becomes an alias for the SysWOW64 folder, with the effect that for 32 bit applications, Windows looks totally normal (ie. 32 bit). However, this also means that binaries that are found in the unaliased System32 folder are not accessible for 32 bit application. Hence the need to copy and reregister cmdlib.wsc and isshlp.wsc.

Now that I had this one working I directly faced a second problem: the backups of the metabase are stored at %WINDIR%\System32\inetserv\MetaBack. I think you can guess what’s the problem: the folder is hidden for 32 bit applications, which means that I can’t copy the Metabase backups using NAnt, because NAnt only sees the aliased version of System32.

So here’s what I did to solve this issue: I couldn’t find a way to disable the file system aliasing though standard means in NAnt, but I found an API that could help me:

Using the first of those two method disables the aliasing for the current thread. So I wrote a small C# program that first disables the aliasing (by P/Invoking the methods mentioned above) and then copies the backed up files out of the System32 folder into a conventional folder. I could then continue to use NAnt to further process those files (e.g. zipping them, mailing them somewhere – whatever).

Here’s the code of the class that disables/reverts the file system aliasing:

   1: /// <summary>
   2: /// Disables file system aliasing for 32 bit applications
   3: /// on 64 bit systems.
   4: /// </summary>
   5: public class DisableWow64Redirect : IDisposable {
   6:   #region P/invoke
   7:   [DllImport("Kernel32")]
   8:   private static extern bool Wow64DisableWow64FsRedirection(out IntPtr oldValue);
   9:  
  10:   [DllImport("Kernel32")]
  11:   private static extern bool Wow64RevertWow64FsRedirection(IntPtr oldValue)
  12:   #endregion
  13:  
  14:   private readonly IntPtr oldValue;
  15:  
  16:   /// <summary>
  17:   /// Creating a new object disables file system aliasing for the current thread.
  18:   /// </summary>
  19:   /// <remarks>
  20:   /// Use <see cref="Dispose"/> to re-enable file system aliasing.</remarks>
  21:   public DisableWow64Redirect() {
  22:     Success = Wow64DisableWow64FsRedirection(out oldValue);
  23:   }
  24:  
  25:   public bool Success { get; private set; }
  26:  
  27:   /// <summary>
  28:   /// Disposes this object and reenables the file system aliasing.
  29:   /// </summary>
  30:   public void Dispose() {
  31:     if (Success) {
  32:       Success = Wow64RevertWow64FsRedirection(oldValue);
  33:     }
  34:   }
  35: }

Granted, this is probably not the best solution one could think of, but it works for me for the moment. If anyone has a better idea, let me know!

 

Posted in: Windows | Snippets | C#

Tags: , ,

Getting rid of strings (3): take your app settings to the next level

September 5, 2008 at 1:23 PMAndre Loker

In the previous parts of this series (part 1, part 2) I talked about the problems with literal strings in source code and presented different strategies to avoid those problems. In this episode I'll explain how we can abstract from app settings and leverage the power of the Castle DictionaryAdapter to improve the way our applications access their app settings.

Basics

Probably the easiest way to make certain aspects of a .NET application configurable is by using app settings. You can define app settings by adding (or augmenting) an <appSettings> section to your web.config or app.config, depending on the project type. This could look something like this:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <configuration>
   3:   <appSettings>
   4:     <add key="MaxUsers" value="20"/>
   5:     <add key="FeedbackMail" value="foo@localhost"/>
   6:   </appSettings>
   7: </configuration>

[As a small side note: you don't have to physically keep the appSettings section in the web.config/app.config file - read Keep your .config clean with external config files to learn how to move settings outside of the config file.]

To access the settings easily use the configuration API exposed by ConfigurationManager, specifically the AppSettings property. Here's a tiny app that accesses the values from the appSettings section:

   1: using System;
   2: using System.Configuration;
   3:  
   4: public class Program {
   5:   private static void Main() {
   6:     string feedbackMail = ConfigurationManager.AppSettings["FeedbackMail"];
   7:     int maxUsers = int.Parse(ConfigurationManager.AppSettings["MaxUsers"]);
   8:     Console.WriteLine("Feedback e-mail address: {0}", feedbackMail);
   9:     Console.WriteLine("Max users: {0}", maxUsers);
  10:   }
  11: }

As you see, that's fairly simple. Some points of interest:

  • ConfigurationManager lives in System.Configuration. You need to add the assembly System.Configuration.dll to your project to use this class
  • AppSettings has two indexers:
    • One indexer accepts a string: the string provided should be one of the keys as defined in the appSettings section. The value returned is the content of the value attribute of the respective appSettings entry or null if the key wasn't found. Keys are case insensitive by the way, so AppSettings["feedbackMAIL"] returns the same value as AppSettings["FeedbackMail"]. Note, however, that white space before or after the key does count, so AppSettings[" FeedbackMail"] will return null. Also be sure to check your config file for accidentally added white space within the key attribute if your app does not find certain keys.
    • The other indexer accepts an integer, which is the index of the app setting to return. Granted, I don't see much use for that indexer.
  • The values returned by the indexers are always strings. Therefore, if you want to have an app setting as an integer you'll need to parse it.

Let's analyse this basic approach:

  • We use strings to index the AppSettings property which - as you should know by now - is very problematic.
    • If you misspell the key, the value returned is null, but you won't notice it before runtime.
    • If you change the key in the app settings, you'll have to update all references to that key in your code. Remember that strings are hard to refactor.
  • Values are always returned as strings so you need to parse them if you need data of a type other than string

Improving the situation

If you read the first article of this series you know that there are two basic steps that can improve the situation:

  1. Avoid spreading literals all over the code, define and use constants instead
  2. Hide any string dependent code behind an appropriate API

Applying those rules might lead you to the idea to write a class that encapsulates the app settings. A good idea indeed! Here's a class that encapsulates the app settings of our tiny example:

   1: class MySettings {
   2:   // constants that define the keys in the app settings
   3:   private const string MaxUsersKey = "MaxUsers";
   4:   private const string FeedbackMailKey = "FeedbackMail";
   5:  
   6:   public static string FeedbackMail {
   7:     get { return ConfigurationManager.AppSettings[FeedbackMailKey]; }
   8:   }
   9:  
  10:   public static int MaxUsers {
  11:     get { return int.Parse(ConfigurationManager.AppSettings[MaxUsersKey]); }
  12:   }
  13: }

I made the properties static because the class is stateless. Now you can access the settings like this:

   1: public class Program {
   2:   private static void Main() {
   3:     string feedbackMail = MySettings.FeedbackMail;
   4:     int maxUsers = MySettings.MaxUsers;
   5:     Console.WriteLine("Feedback e-mail address: {0}", feedbackMail);
   6:     Console.WriteLine("Max users: {0}", maxUsers);
   7:   }
   8: }

This is much better! The strings are neatly hidden, so is the parsing of the integer. You can refactor the names of the properties easily using the refactoring tool of your choice.

Is this solution the final answer? Certainly not. This solution still suffers from some issues :

  • It's tedious to add and implement properties and possible parsing manually for each setting in the app settings section.
  • The settings are now strictly tied to ConfigurationManager. It's difficult to mock some app settings for unit testing using this approach.

Let me elaborate on the second issue: assume you have a class that is responsible for sending an email to the system administrator in case of an error. Here's a possible excerpt of such a system:

   1: // an interface we use to abstract sending of emails.
   2: public interface IMailSender {
   3:   void Send(string to, string subject, string text);
   4: }
   5:  
   6: // Sends error reports by mail
   7: public class ErrorReporter {
   8:   private readonly IMailSender mailSender;
   9:  
  10:   public ErrorReporter(IMailSender mailSender) {
  11:     this.mailSender = mailSender;
  12:   }
  13:  
  14:   public void SendErrorReport(string text) {
  15:     var email = MySettings.FeedbackMail;
  16:     mailSender.Send(email, "Application error", text);
  17:   }
  18: }
  19:  

It's certainly nice that we did not hardcode the email address that the report is sent to. But if we were to unit test the method we'd have to provide a value for the FeedbackMail app setting. (I'm using Rhino Mocks by the way)

   1: [Test]
   2: public void SendErrorReport_UsesMailSender() {
   3:   var mailSender = MockRepository.GenerateMock<IMailSender>();
   4:  
   5:   var text = "test message";
   6:   var email = "foo@localhost";
   7:  
   8:   // need to inject the email into the app settings
   9:   ConfigurationManager.AppSettings["FeedbackMail"] = email;
  10:  
  11:   var reporter = new ErrorReporter(mailSender);
  12:   reporter.SendErrorReport(text);
  13:  
  14:   mailSender.AssertWasCalled(x=>x.Send(email, "Application error", text));
  15: }

To make the test work we need to inject the expected email address into the app settings. I personally think that this situation is awkward and does certainly not isolate the unit test around one class under test. ErrorReporter uses MySettings which again uses ConfigurationManager. For my taste the number of classes involved in this unit test is unnecessarily high.

A solution

If you've never heard of Castle DictionaryAdapter, go and read my article on it, because this little tool will improve our solution a lot.

Here's what we do:

  • Delete MySettings, we won't use it anymore
  • Create instead an interface that represents your app settings:
   1: public interface ISettings {
   2:   int MaxUsers { get; }
   3:   string FeedbackMail { get; }
   4: }
  • Create a dictionary adapter that handles all the plumbing between ISettings and AppSettings:
   1: var factory = new DictionaryAdapterFactory();
   2: var adapter = factory.GetAdapter<ISettings>(ConfigurationManager.AppSettings);
  • Use this object instead of MySettings:
   1: public class Program {
   2:   private static void Main() {
   3:     var factory = new DictionaryAdapterFactory();
   4:     var settings = factory.GetAdapter<ISettings>(ConfigurationManager.AppSettings);
   5:     var feedbackMail = settings.FeedbackMail;
   6:     var maxUsers = settings.MaxUsers;
   7:     Console.WriteLine("Feedback e-mail address: {0}", feedbackMail);
   8:     Console.WriteLine("Max users: {0}", maxUsers);
   9:   }
  10: }

Again, we have a type safe interface for our app settings. But what did we gain?

First we have to use much less code to define the interface for our app settings: ISettings is a no-brainer, just define properties with the desired type and the name matching the app settings key [see this article on DictionaryAdapter to learn how this can be configured in detail]. The DictionaryAdapter will handle all necessary lookup and conversion for you. Less code on our side is A Good Thing™.

Secondly by using an interface we have created a better abstraction of the app settings. Combine this with the power of dependency injection and you've created a basis for well testable, highly configurable code. If you don't see what I mean, read on and let me elaborate.

Why this solution rocks

First of all change ErrorReporter to accept an ISettings instance and use it instead of MySettings:

   1: public class ErrorReporter {
   2:   private readonly IMailSender mailSender;
   3:   private readonly ISettings settings;
   4:  
   5:   // Inject ISettings as well
   6:   public ErrorReporter(IMailSender mailSender, ISettings settings) {
   7:     this.mailSender = mailSender;
   8:     this.settings = settings;
   9:   }
  10:  
  11:   public void SendErrorReport(string text) {
  12:     var email = settings.FeedbackMail; // use ISettings instead of MySettings
  13:     mailSender.Send(email, "Application error", text);
  14:   }
  15: }

Two changes have taken place: I inject the ISettings dependency through the constructor and I use this object to access the email address.

ISettings in action - unit test

Here's the updated version of the unit test from above:

   1: [Test]
   2: public void SendErrorReport_UsesMailSender() {
   3:   var mailSender = MockRepository.GenerateMock<IMailSender>();
   4:  
   5:   var text = "test message";
   6:   var email = "foo@localhost";
   7:  
   8:   // create a stub for ISettings
   9:   var settings = MockRepository.GenerateStub<ISettings>();
  10:   // let this stub's FeedbackMail property return a specific value
  11:   settings.Stub(x => x.FeedbackMail).Return(email);
  12:  
  13:   // inject the settings
  14:   var reporter = new ErrorReporter(mailSender, settings);
  15:   reporter.SendErrorReport(text);
  16:  
  17:   mailSender.AssertWasCalled(x=>x.Send(email, "Application error", text));
  18: }

This approach is far superior to the old approach because we only have to stub a direct dependency of ErrorReporter (ie. ISettings). There's no need to configure an indirect dependency like ConfigurationManager.AppSettings. Furthermore we could now make an ISettings mock to check whether ErrorReporter really uses the settings object. Short, we have the full control of the behaviour of the ISettings instance.

ISettings in action - the real app

To use ISettings and ErrorReporter in a real app, we'd preferably use an IoC container like Castle Windsor to configure the ErrorReporter instance.

Here's how you could configure the container:

   1: var container = new WindsorContainer();
   2: // we'll need an implementation of IMailSender
   3: container.Register(Component.For<IMailSender>().ImplementedBy<SomeClassImplementingIMailSender>());
   4:  
   5: // create the adapter
   6: var adapter = new DictionaryAdapterFactory().GetAdapter<ISettings>(ConfigurationManager.AppSettings);
   7: // register this adapter instance as the component for ISettings
   8: container.Register(Component.For<ISettings>().Instance(adapter));
   9:  
  10: // and finally register the error reporter
  11: container.Register(Component.For<ErrorReporter>());

Whenever we need an instance of ErrorReporter now we can ask the container for it (object locator approach):

   1: var reporter = container.Resolve<ErrorReporter>();
   2: reporter.SendErrorReport("Something went horribly wrong");

Alternatively you could let the IoC container inject an ErrorReporter instance where you need it (dependency injection approach).

Both ways we'll get an ErrorReporter instance that is readily configured to access the app settings in a transparent way.

Conclusion

By using the proposed combination of

  1. an interface defining the app settings
  2. a dictionary adapter that maps between the AppSettings and the interface and
  3. an IoC container that can inject the adapter wherever we need it

we were able to completely get rid of any app settings related strings and created an architecture that is easily configurable and well testable.

By abstracting from the appSettings in the app.config file it's also easy to use a different configuration source instead. DictionaryAdapter can wrap all kinds of dictionaries and NameValueCollections. And if you come to the conclusion that you'd rather want to store the app settings in a database, it's easy to do, as well. Instead of using the DictionaryAdapter you could implement ISettings in a way that loads app settings from a database.

Posted in: C# | Patterns

Tags: , , , ,

Retrieving values from an IDataReader

September 4, 2008 at 3:57 PMAndre Loker

Despite the undoubted advantages of ORM you probably need to fetch data directly from an IDataReader from time to time. Getting values out of the data reader is easy at first glance. However, there are some issues that you should be aware of.

Basic usage

Assume we have a simple table that holds comments for a web log or something similar:

image

(The UI is German, but I guess you know what the columns mean. If not: it's "Column name", "Data type" and "Allow Nulls")

Let's query all data in the table:

   1: using (var con = new SqlConnection(connectionString)) {
   2:   con.Open();
   3:   var cmd = new SqlCommand("SELECT * FROM Comment", con);
   4:   using(var rdr = cmd.ExecuteReader()) {
   5:     while(rdr.Read()) {
   6:       var id = rdr.GetInt32(0);
   7:       var post = rdr.GetInt32(1);
   8:       var position = rdr.GetInt32(2);
   9:       var text = rdr.GetString(3);
  10:       Console.WriteLine("{0,-3} {1,-3} #{2,-3} {3}", id, post, position, text);
  11:     }
  12:   }
  13: }

Nothing fancy here, we simply query all all rows and columns and print their values.

The index problem

Look at the way we retrieve data from he reader:

   1: var id = rdr.GetInt32(0);
   2: var post = rdr.GetInt32(1);
   3: var position = rdr.GetInt32(2);
   4: var text = rdr.GetString(3);

Using indices this way is probably not the best solution, especially because we use SELECT * to retrieve all columns. If the order of the columns change in the database, your application either crashes or it will using the wrong columns (the latter can arguably be the worse situation). Errors regarding this problem what be visible until runtime, which makes the code quite hard to maintain.

If we changed the query to something like

   1: SELECT ID, Post, Position, Text FROM Comment

we could at least prevent the index related issues because we would fetch the columns in an order that is defined by our application, not by the database.

As an alternative we could use IDataReader.GetOrdinal to determine the index of the columns at runtime:

   1: var cmd = new SqlCommand("SELECT * FROM Comment", con);
   2:  
   3: using (var rdr = cmd.ExecuteReader()) {
   4:  
   5:   // determine the indices of the columns and cache them for efficiency
   6:   var idIndex = rdr.GetOrdinal("ID");
   7:   var postIndex = rdr.GetOrdinal("Post");
   8:   var positionIndex = rdr.GetOrdinal("Position");
   9:   var textIndex = rdr.GetOrdinal("Text");
  10:  
  11:   while (rdr.Read()) {
  12:     var id = rdr.GetInt32(idIndex);
  13:     var post = rdr.GetInt32(postIndex);
  14:     var position = rdr.GetInt32(positionIndex);
  15:     var text = rdr.GetString(textIndex);
  16:     Console.WriteLine("{0,-3} {1,-3} #{2,-3} {3}", id, post, position, text);
  17:   }
  18: }

Here I again used SELECT *, but it would work exactly the same way with explicit column selection.

There are more ways to achieve the same effect. You can use the indexer of the data reader to fetch the columns by name:

   1: using (var rdr = cmd.ExecuteReader()) {
   2:  
   3:   while (rdr.Read()) {
   4:     var id = rdr["ID"];
   5:     var post = rdr["Post"];
   6:     var position = rdr["Position"];
   7:     var text = rdr["Text"];
   8:     Console.WriteLine("{0,-3} {1,-3} #{2,-3} {3}", id, post, position, text);
   9:   }
  10: }

Be aware though that the indexer unlike the explicit GetXYZ() methods only returns objects. If you need the values to have the correct type you have to cast:

   1: while (rdr.Read()) {
   2:   int id = (int)rdr["ID"];
   3:   int post = (int)rdr["Post"];
   4:   int position = (int)rdr["Position"];
   5:   string text = (string)rdr["Text"];
   6:   Console.WriteLine("{0,-3} {1,-3} #{2,-3} {3}", id, post, position, text);
   7: }

(I didn't use variable type inference (var) in this example to stress the fact that we are using ints and strings instead of objects)

"OK", you say, "with this knowledge I can now master data readers easily". Maybe not yet. There are two more issues.

The data type problem

Assume that you decide that your app will never have more than a few hundred comments per post. To save space in the database you change the data type of the Position column (which describes the order of comments for a specific post) from int to smallint. If you run any of the code examples above you'll probably be surprised that they'll all (except the one that uses the string indexer without casting) fail with an InvalidCastException:

Unhandled Exception: System.InvalidCastException: Specified cast is not valid.

Why is that? In the case of GetInt32 let's look at the remarks in the documentation:

No conversions are performed; therefore, the data retrieved must already be a 32-bit signed integer.

If the data coming from the database is a 16-bit integer (aka smallint) this call will therefore fail. To make the code work again you'd need to use GetInt16 instead.

And what about the cast in  (int)rdr["Position"]? After all, a 16-bit signed integer (short) should be castable to an int. While this is true, keep in mind the indexer of the data reader returns a boxed version of the short value as an object. Unboxing a value must always be done using the type of the boxed value (or one of its interfaces). The conversion from short to int can only take place after the value has been unboxed. That is, use either this (for implicit conversion to int):

   1: int position = (short)rdr["Position"];

or this (for explicit conversion to int):

   1: var position = (int)(short)rdr["Position"];

The data type problem can be really annoying because data type mismatches just like the index problem will be visible at runtime only. It's tedious to hunt down these bugs and it makes modification to the database excessively expensive.

You can avoid this problem to great extent if you don't force a "hard" conversion of the column value with GetXYZ and casts. Instead use the "soft" conversion methods provided by the Convert class. Here's the example from above again, but this time it's more robust against data type changes.

   1: var cmd = new SqlCommand("SELECT * FROM Comment", con);
   2:  
   3: using (var rdr = cmd.ExecuteReader()) {
   4:   while (rdr.Read()) {
   5:     var id = Convert.ToInt32(rdr["ID"]);
   6:     var post = Convert.ToInt32(rdr["Post"]);
   7:     var position = Convert.ToInt32(rdr["Position"]);
   8:     var text = Convert.ToString(rdr["Text"]);
   9:     Console.WriteLine("{0,-3} {1,-3} #{2,-3} {3}", id, post, position, text);
  10:   }
  11: }

(Again, feel free to improve the code by replacing SELECT * with an explicit column list and/or use the index based indexer of the data reader instead)

The DBNull problem

There's one final issue I want to write about. In the examples above all columns are explicitly NON NULL. What if the columns contain NULL?

Let's assume for now that the columns Post, Position and Index could be NULL (ignoring the fact that it wouldn't make much sense in that context). How would our code look like? Maybe like this:

   1: int id = Convert.ToInt32(rdr["ID"]);
   2: int? post =     rdr["Post"]     == null ? (int?)null : Convert.ToInt32(rdr["Post"]);
   3: int? position = rdr["Position"] == null ? (int?)null : Convert.ToInt32(rdr["Position"]);
   4: string text =   rdr["Text"]     == null ? null       : Convert.ToString(rdr["Text"]);

(I aligned the code a bit fore readability in this example)

You'd maybe expect that rdr["Position"] returns null if the column contains NULL. Run the example and you'll see that it's not the case. This is important to now: columns that contain NULL in the database will be returned as an instance of DBNull by the data reader! Furthermore DBNull can't be converted to any other datatype (int, short etc.) with one exception: if Convert.ToString is called on a DBNull object, an empty string is returned (at least in the Sql Server implementation of IDataReader).

To check whether a column in the database contains NULL it's therefore not valid to check whether a value returned by the data reader equals null (it won't ever). Instead, check whether the returned value is a DBNull. There are basically two ways for this. Either use IsDBNull:

   1: if(rdr.IsDBNull(1 /* column index */) {
   2:   // value is NULL
   3: }

or check the type of the value directly:

   1: if(rdr["TheColumn"] is DBNull){
   2:   // value is NULL
   3: }

The example from above should therefore look something like:

   1: int id = Convert.ToInt32(rdr["ID"]);
   2: int? post     = rdr["Post"]     is DBNull ? (int?)null : Convert.ToInt32(rdr["Post"]);
   3: int? position = rdr["Position"] is DBNull ? (int?)null : Convert.ToInt32(rdr["Position"]);
   4: string text   = rdr["Text"]     is DBNull ?       null : Convert.ToString(rdr["Text"]);

(As always: using the string based indexer is just one option to retrieve values, the same is applicable in case you use indices)

While the code above is not the most efficient piece of C# ever written it covers many of the problems I mentioned in this article:

  • the code does not depend on the order of the columns in the database.
  • the code can handle a fair amount of possible data type changes made to the table
  • the code can handle NULL values

For convenience, you might want to write some helper methods that simplify the task of retrieving values from the data reader.

   1: public static int? GetInt32(IDataRecord dr, string columnName) {
   2:   var value = dr[columnName];
   3:   return value is DBNull ? (int?) null : Convert.ToInt32(value);
   4: }
   5:  
   6: public static int? GetInt32(IDataRecord dr, int columnIndex) {
   7:   return dr.IsDBNull(columnIndex) ? (int?) null : Convert.ToInt32(dr[columnIndex]);
   8: }
   9:  
  10: public static string GetString(IDataRecord dr, string columnName) {
  11:   var value = dr[columnName];
  12:   return value is DBNull ? null : Convert.ToString(value);
  13: }
  14:  
  15: public static string GetString(IDataRecord dr, int columnIndex) {
  16:   return dr.IsDBNull(columnIndex) ? null : Convert.ToString(dr[columnIndex]);
  17: }

You can then use those methods like this:

   1: int id = Convert.ToInt32(rdr["ID"]);
   2: int? post = GetInt32(rdr, "Post");
   3: int? position = GetInt32(rdr, "Position");
   4: string text = GetString(rdr, "Text");

Of course, if you're using C# 3 you could make the methods above extensions to IDataRecord. In fact, I've written those extension methods for you (download ISC licensed source here). It basically does two things:

  • Provide equivalents to all those GetXYZ methods in IDataRecord that accept a column name instead of an index. Those methods are shortcuts for casting the values of reader["ColumnName"] to the proper type, but they suffer from the same data type and NULL value problem as their index based counterparts. Use them only for non null columns of which you know the data type exactly.
  • Provide "safe" versions of those methods that don't suffer from the data type problem and the NULL problem. I called those methods GetSafeXYZ (where XYZ is the data type of course). You won't find "safe" methods that accept a column index, but with the knowledge you - hopefully - gained from this article you should be able to write them yourself.

Here's the example from above using the "safe" methods:

   1: var cmd = new SqlCommand("SELECT * FROM Comment", con);
   2:  
   3: using (var rdr = cmd.ExecuteReader()) {
   4:   while (rdr.Read()) {
   5:     int id = rdr.GetInt32("ID");
   6:     int? post = rdr.GetSafeInt32("Post");
   7:     int? position = rdr.GetSafeInt32("Position");
   8:     string text = rdr.GetSafeString("Text");
   9:  
  10:     Console.WriteLine("{0,-3} {1,-3} #{2,-3} {3}", id, post, position, text);
  11:   }
  12: }

Attachments:

DataRecordExtensions.cs (20.37 kb)

Posted in: C# | Databases | Patterns

Tags: , ,

The true meaning of readonly for value types

August 27, 2008 at 5:47 PMAndre Loker

I've been trying to create a simple and lightweight wrapper around List<T> and List<T>.Enumerator. The only thing I needed was the ability to enumerate over the items of the list. The list is supposed to be enumerated very(!) often, so I wanted the enumerator to be struct instead of a class. Using a value type enumerator avoids any heap allocation during enumerator. List<T>.Enumerator is a value type just because of the same reason.

So here's my first approach:

   1: /// <summary>
   2: /// A wrapper around an <see cref="List{T}"/> that only allows enumeration. 
   3: /// </summary>
   4: public struct ReadOnlyList<T> {
   5:   private readonly List<T> items;
   6:  
   7:   /// <summary>
   8:   /// Initializes a new instance of the <see cref="ReadOnlyList{T}"/> struct.
   9:   /// </summary>
  10:   /// <param name="list">The list.</param>
  11:   public ReadOnlyList(List<T> list) {
  12:     items = list;
  13:   }
  14:  
  15:   /// <summary>
  16:   /// Gets the enumerator.
  17:   /// </summary>
  18:   /// <returns></returns>
  19:   public Enumerator GetEnumerator() {
  20:     return new Enumerator(items);
  21:   }
  22:  
  23:   #region Nested type: Enumerator
  24:   /// <summary>
  25:   /// A light weight enumerator for <see cref="ReadOnlyList{T}"/>
  26:   /// </summary>
  27:   public struct Enumerator {
  28:     private readonly List<T>.Enumerator enumerator;
  29:  
  30:     /// <summary>
  31:     /// Initializes a new instance of the <see cref="ReadOnlyList&lt;T&gt;.Enumerator"/> struct.
  32:     /// </summary>
  33:     /// <param name="items">The items.</param>
  34:     public Enumerator(List<T> items) {
  35:       enumerator = items.GetEnumerator();
  36:     }
  37:  
  38:     /// <summary>
  39:     /// Gets the current item.
  40:     /// </summary>
  41:     /// <value>The current item.</value>
  42:     public T Current {
  43:       get { return enumerator.Current; }
  44:     }
  45:  
  46:     /// <summary>
  47:     /// Moves to the next element in the enumeration.
  48:     /// </summary>
  49:     /// <returns></returns>
  50:     public bool MoveNext() {
  51:       return enumerator.MoveNext();
  52:     }
  53:   }
  54:   #endregion
  55: }

This looks perfectly reasonable if you ask me. Here's a unit test to check that the enumerator works:

   1: [Test]
   2: public void Enumerator_CanEnumerateList() {
   3:   var list = new List<int> {0, 1, 2, 3};
   4:   var enumerator = new ReadOnlyList<int>.Enumerator(list);
   5:   var expected = 0;
   6:   while(enumerator.MoveNext()) {
   7:     Assert.AreEqual(expected, enumerator.Current);
   8:     expected++;
   9:   }
  10:   Assert.AreEqual(list.Count, expected);
  11: }

The test should pass, right? After all the Enumerator struct is a mere wrapper aroung List<T>.Enumerator. Funny thing is: it fails! Do you see why? As a hint, here's what fails: the second time the loop runs enumerator.Current is 0 although enumerator.MoveNext() has returned true. But why? It has taken me quite a while to find the reason.

To the Bat Mobile Debugger!

Of course, first thing I did was to debug the code. List<T>.Enumerator.MoveNext() looks something like this:

   1: public bool MoveNext() {
   2:     List<T> list = this.list;
   3:     if ((this.version == list._version) && (this.index < list._size)) {
   4:         this.current = list._items[this.index];
   5:         this.index++;
   6:         return true;
   7:     }
   8:     return this.MoveNextRare();
   9: }

MoveNextRare() is not important here, but what is important is that when the method returns true, index should have been increased. However, according to the debugger, the value of enumerator.enumerator.index doesn't change after the call to MoveNext(), although it returned true. Weird, huh? Somehow the fields did not get updated.

So I dug deep into the code. I opened ReadOnlyList<T>.Enumerator.MoveNext() in Reflector and here's what I got:

   1: .method public hidebysig instance bool MoveNext() cil managed
   2: {
   3:     .maxstack 1
   4:     .locals init (
   5:         [0] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!T> CS$0$0000)
   6:     L_0000: ldarg.0 
   7:     L_0001: ldfld valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> Moonbow.Util.ReadOnlyList`1/Enumerator<!T>::enumerator
   8:     L_0006: stloc.0 
   9:     L_0007: ldloca.s CS$0$0000
  10:     L_0009: call instance bool [mscorlib]System.Collections.Generic.List`1/Enumerator<!T>::MoveNext()
  11:     L_000e: ret 
  12: }

Now it became clear that my MoveNext() method created a local copy of the enumerator field and called MoveNext on the copy. This of course meant that the original fields of the List<T>.Enumerator wouldn't get updated. And now you might see where my mistake was? Right: ReadOnlyList<T>.Enumerator.enumerator is marked as readonly! My idea was that the enumerator object will not be reassigned in any method of my Enumerator, so I could as well make the field readonly. After removing the readonly modifier the IL of my MoveNext() method was much more like I expected:

   1: .method public hidebysig instance bool MoveNext() cil managed
   2: {
   3:     .maxstack 8
   4:     L_0000: ldarg.0 
   5:     L_0001: ldflda valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> Moonbow.Util.ReadOnlyList`1/Enumerator<!T>::enumerator
   6:     L_0006: call instance bool [mscorlib]System.Collections.Generic.List`1/Enumerator<!T>::MoveNext()
   7:     L_000b: ret 
   8: }

The conclusion

Here's the moral of the story:

If you declare a value type field as readonly, every call made to this field is actually made to a local copy. Any changes made in those calls are not stored in the readonly field. This is different from reference type fields where calls will be made on the field itself, potentially causing changes in the referenced object.

If this has been obvious for you: kudos, I didn't know that. Rreadonly fields are "really" readonly for value types, it means more than prohibiting assignments to the field. I did not find a word about that in the specification. The MSDN only mentions that assignments to readonly fields are only allowed in the declartion or in the constructor:

The readonly keyword is a modifier that you can use on fields. When a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class.

There is however a bug report that deals with this issue. Is has been closed as "By Design", though. It references the part in the specs that defines this behaviour: it's in section 7.4.4, function member invocation, bullet list 2, item 2, subitem 2.

If E is not classified as a variable, then a temporary local variable of E’s type is created and the value of E is assigned to that variable. E is then reclassified as a reference to that temporary local variable. The temporary variable is accessible as this within M, but not in any other way. Thus, only when E is a true variable is it possible for the caller to observe the changes that M makes to this.

By the way: it does not matter whether the type that declares the readonly value type fiels is a struct or a class by itself.

Posted in: C#

Tags: ,

Did you know that...

July 8, 2008 at 7:24 PMAndre Loker

... you can annotate an attribute class with an attribute of that very type?

   1: [ThisIsCool]
   2: public class ThisIsCoolAttribute : System.Attribute {
   3: }

Admittedly I did not.

Posted in: C# | Snippets

Tags: