Monday, April 18, 2005

P&P Enterprise Library, VB, and Data Access Application Block Bugs

Microsoft's patterns & practices group (PAG) released an updated version of seven Application Blocks for the .NET Framework 1.1 in mid-January. The new Enterprise Library (EntLib) Application Blocks are based on the Avenade Connected Architecture for .NET (ACA.NET). Avenade Inc is a joint-venture software consulting company formed by Accenture and Microsoft in 2000. I had created a sample VS 2005 front-end to the earlier (Microsoft-only) version (2.0) of the Data Access Application Block (DAAB) for the book's "Best Practices" chapter, and I expected the new EntLib blocks to be similar to their predecessors. Instead, I discovered that the source code for all new blocks was C# only. (The earlier blocks had C# and VB implementations, and I had no problems compiling them with VS 2005 May 2004 CTP.) The missing EntLib VB implementations have evoked the expected howls of protest from the developer community. As an example, vice-president of the Microsoft Developer Division S. "Soma" Somasegar's "Enterprise Library" blog post of 3/13/2005 (from India) drew several comments regarding the missing VB block source code. Michael Kropp, who runs the PAG team, replied to Bill McCarthy's complaint with the following promise:

While we made a decision not to provide all the application blocks in multiple languages we intentionally did a number of things to specifically help VB developers successfully use Enterprise Library (API Reference documentation, code samples, quickstarts and documentation). Going forward, we plan to make additional investments in Enterprise Library to include end-to-end reference implementations in both VB and C#.

Hopefully, VB block implementations will be included in the promised upgrade for the upgrade to .NET 2.0 and VS 2005. Attempts to build the EntLib source code with VS 2005 February CTP failed as a result of Upgrade Wizard errors. In addition, the architectural changes caused the new blocks to be totally incompatible with their predecessors. So, I compiled the EntLib DAAB source code with VS 2003, upgraded the DataAccessQuickStart.sln client project to .NET 2.0, added the .NET 1.1 Common.dll, Configuration.dll, and Data.dll assemblies as references, created the sample database in SQL Server 2005 February CTP, and attempted to run the client. I had to make a minor modification to the app.config file (removing the <keyalgorithmstorageprovider nil="true"> element) to eliminate a runtime error when creating a new abstract Database object. At first glance all seven test buttons delivered the expected results. A second look at the Update a Database Using a DataSet button's result ("2 rows were affected") piqued my curiosity. The SalesData class's UpdateProducts function includes a Dim rowsAffected As Integer = db.UpdateDataSet(productsDataSet, "Products", insertCommandWrapper, updateCommandWrapper, deleteCommandWrapper, UpdateBehavior.Standard) instruction that executes three commands and should return "3 rows were affected." Inspecting the underlying Products table last row(s) indicated that the deleteCommandWrapper command didn't behave as the Microsoft developers had expected. They had expended large amounts of energy on unit tests for the block code but didn't even run cursory tests on all functions of the QuickStart client code. The basic problem was an attempt to add and delete the same record in a single operation. The required @ProductID identity value for the DeleteProduct stored procedure isn't available until the the AddProduct stored procedure executes and updates the Products DataTable. The DataRowVersion.Current parameter value of the cwDelete.AddInParameter("@ProductID", DbType.Int32, "ProductID", DataRowVersion.Current) instruction always is DbNull.Value. The moral of this story is that developers who thoroughly test only the "interesting" parts of their projects end up with egg on their faces.