Saturday, February 24, 2007

What rolls down stairs, alone or in pairs?

I recently discovered that our databases in SQL Server 2005 using the Bulk Logged recovery model were not getting their logs backed up by the Log Backup maintenance plan. I did some searching to no avail and ending up posting a question to the MSDN forums. I was told this is a known bug in SQL 2005 RTM and SP1 and will be fixed in SP2. SP2 is now available and the problem is fixed... but not very well.
 
The Log Backup maintenance plan allows you to choose "all databases" when asked what to back up. In pre-SP2 it would select all databases on the server, filter out the ones with inappropriate recovery models, then execute a BACKUP LOG statement against the remaining databases. The problem was that instead of only excluding Simple recovery models databases, it excluded Bulk Logged also. I imagined the fix in SP2 would be to correct the filter. Not so.
 
Now, in SP2, the maintenance plan selects all databases on the server and attempts to execute a BACKUP LOG statement against each of them. Those with appropriate recovery models succeed, the others fail. Unfortunately the failures are then treated by SQL Agent as a job error and the maintenance plan reports as failed even though all the right databases were backed up successfully.
 
The benefit in SP2 is that the Bulk Logged databases actually get backed up now because you couldn't back them up at all with a maintenance plan previously even if you explicitly selected the Bulk Logged databases only. The downside is that I have to update my maintence plan everytime a new database is added or the recovery model changes. I appreciate that you should give more time to getting backups right on a production database, but on the development servers this is tedious.
 Tuesday, August 15, 2006

Components need good ISite

Accessing a Form from inside a Component is surprisingly convoluted in the .NET Framework. I created a new class that inherits from Component that would provide extra functionality to any Form I dropped it on. Ideally, it would search it's parent Form for various types of controls and add handlers to certain control events to provide special behaviour. Unfortunately, neither the Component.Site or .Container properties provide access to the parent Form or ContainerControl.

Some of the components included with the Framework are interacting with their parents so I know it's possible. I dropped a ErrorProvider onto a new Form and checked the designer code to see how it was instantiated. I then opened up Reflector, headed directly for the ErrorProvider component and followed this rather bizarre code path:

  1. The designer code creates a private member "components" initialised as a new ComponentModel.Container.  
  2. It then creates the ErrorProvider passing the new Container to its constructor.  
  3. The ErrorProvider constructor simply calls the Container.Add method passing itself.  
  4. The Container.Add method (the trick bit), after extensive validation and array sizing, creates a new ComponentModel.Site and assigns it to the (ErrorProvider) component's Site property.  
  5. The ErrorProvider.Site property stores a reference to the incoming Site then proceeds to request a ComponentModel.Design.IDesignerHost via a call to Site.GetService.  
  6. The ErrorProvider then retrieves the IDesignerHost.RootComponent property, casts it to a ContainerControl and assigns the value to it's own public ContainerControl property.  
  7. The designer then serializes the value of this property to the designer code of the parent Form as "Me.ErrorProvider1.ContainerControl = Me".

The ErrorProvider, and probably many other components included with the Framework, use the behaviour of the designer's code generator to ensure it will have access to it's container at run-time. This feels tightly-coupled yet fragile all at the same time with these odd interdependencies.

Sadly, a Component cannot find trace its roots any other way, so my custom component was forced to borrow this ugly technique. Like the ErrorProvider, my component too must be instantiated differently if created programmatically instead of in the Visual Studio designer.

At least now I, and hopefully you, understand how the Component, Site, and Container classes interact with each other and if you want to access the Form from your own Component, know you can.

 Sunday, August 06, 2006

Adding New

I've spent too much time in Reflector again these past weeks. One of the instigators was the BindingSource AddingNew event. If you happen to handle this event and assign your own object to e.NewObject property, don't expect the Position on the BindingSource to refer to the new item as it normally would.
 
The BindingSource explicitly checks to see if you have set e.NewObject yourself and if you have, it doesn't bother to update the Position to refer to your new item at the end of the list. You will need to set the Position property yourself too.
 Wednesday, May 03, 2006

Cold Cup(Of T)

I often wonder exactly which collection interface I should implement in a new collection class or which I should use as a method parameter. I like to choose the highest level interface that will provide access to the properties and methods I need. Instead of following the links through MSDN Library everytime I quickly created a map in Visio so I can see all the relationships between the standard framework collection interfaces and classes, including the new generic items. It probably isn't complete but I think it is good guide for getting information at a glance.
 
It was interesting to discover the significant differences between the generic and non-generic ICollection interfaces. The original non-generic ICollection provides enumeration support and a Count property. The new generic ICollection(Of T) goes further and includes support for adding and removing items, much more like IList than ICollection. It doesn't even inherit from ICollection which unfortunately means that while most of the standard implementation classes of ICollection(Of T) also implement ICollection, I can't safely pass ICollection(Of T) objects to AddRange methods or common collection constructors.

Deblector arrives

Felice Pollano has just released the first version of the new Deblector addin for debugging within Reflector. It's only alpha at the moment and has some obvious bugs but it is very promising. In the past I have looked at having a Virtual PC with a hacked rebuild of the core framework with debugging enabled. Now I can step into framework code just as easily within the familar Reflector interface. I don't have much experience with IL so I was a little confused at first when multiple lines of IL seemed to execute at once but I quickly realised they all applied to method call setup. I suspect, if possible, we may even be able step through the framework viewed in our chosen language. Keep an eye on this one.
 Monday, May 01, 2006

Role your own

I discovered an annoying limitation in the SQL Server Management Studio today. The GUI does not offer an option to add a Database Role as a member of another Database Role. In my case I wanted to add my "bigAppAdmins" role to the "bigAppUsers" role so all administrators are implicitly users also. Unfortunately I had to resort to the sp_addrolemember stored procedure to achieve this. If I didn't already know that roles could be members of other roles I might have been convinced that SQL Server didn't support it.
 Monday, April 24, 2006

Captain's Log, Stardate NULL

Today I discovered a need for a data-bound DateTimePicker to support the display and input of NULL values. I remembered reading a blog a short while ago about someone else who had already developed a solution.
 
Google helpfully pointed me to Alexander Shirshov's original solution that I had read before. However I also spotted Claudio Grazioli's solution on Code Project which apparently correct some bugs in Alexander's implementation. I downloaded the source, gave it a try and it works very neatly.
 
If anyone would like the source for the NullableDateTimePicker in VB.NET instead of C# just leave a comment.
 Sunday, April 23, 2006

Request to dock

One of the nice parts of working with the Visual Studio 2005 IDE is the very well implemented window docking system. It now looks like there is a library available to achieve the same results in our own applications:

Deblector

Lutz Roeder... you're the bomb. I've been using .NET Reflector for quite some time now and I love every bit of it. If you aren't using it yet, go get it. However, there is one thing I've always wanted to do with Reflector, use it to debug code. As I recently discovered on Mike Stall's excellent debugging blog someone is working on integrating debugging into Reflector. That someone is Felice Pollano and hopefully Deblector will soon become one of my primary development tools too.
 Saturday, April 22, 2006

Mapping the web

Discovered recently that Windows XP has really good support for WebDAV. This command will map an unused drive letter to a folder shared via HTTP:

net use * http://webdavserver/webdavfolder

It's that easy. Hosting a WebDAV folder is also really easy on any machine with IIS. Just add a virtual directory, point it to your chosen local path and make sure it is browsable.

Bound and gagged

I haven't used much of the built in data binding in .NET yet, preferring to keep things under my own control. However, the current project is using it heavily and I really should get up to speed before it's too late. Here is a small tip that was easy to miss on some of the project's earlier code:

"Try using myBindingSource.ResetCurrentItem instead of myBindingSource.ResetBindings when you need to propagate small data changes throughout an application. It can be much more efficient when you are dealing with big lists."

Scan ahead

In my current project we expect to need to integrate scanning documents into our database. I thought I should do a quick preliminary search on how to control a scanner from a .NET WinForms application. Here are a few links other may find useful: