Pages

Wednesday, September 1, 2010

Set ComponentMetaData.Version in ProvideComponentProperties

This post is for a fairly small audience (perhaps only myself) and applies to those creating custom components for SQL Integration Services.  The SSIS API provides a reasonably nice way of handling upgrades to components through the PerformUpgrade method.  If you're not sure how to do that, I suggest reading Using PerformUpgrade.
However, there's one issue that I constantly run into that I didn't mention in that post.  For whatever reason, when you drop a completely new component onto the design surface, SSIS does not save the correct version information into the DTSX.  To be clear, we're talking about an internal versioning system here.  This has nothing to do with assembly versioning.  We're talking about how two version numbers interact - what I call the "runtime" version number, and the "metadata" version number. 
The Runtime Version
The runtime version number is the version number that's encoded inside your custom component's assembly - it's the number you've hardcoded in the DtsPipelineComponentAttribute at the top of your custom component's class. This version number corresponds to the way your component reads and writes properties to ComponentMetaData's CustomPropertyCollection.  "Version 1" of your component will expect a different set of properties, or a different way of interpreting the information in those properties that isn't compatible with what you expected in "version 0."
The Metadata Version
The metadata version number is the version number stored in the DTSX file.  This version number gets written by SSIS when it saves your component's custom properties.  This version number should correspond to the stored format of the custom properties, and indicate that a component of the same version can interpret them properly.
The Versioning Process
When you create a brand-new custom component, you'll likely start off with a version number of zero in your DtsPipelineComponentAttribute.  Placing a component on the design surface will result in a version of zero being written to the DTSX.  Everything works well.
As you work on your component, the time will come when you need to alter how it stores information in its custom properties.  If you simply change how your component expects these properties to look without coding a PerformUpgrade, your existing packages will almost surely break, and you'll have to open them up, delete all instances of your component, add them back to the data flow, and configure them from scratch.  If you implement a PerformUpgrade, you should be able to "read in" the old properties, interpret them, and "write back" the new format to ComponentMetaData such that the current version of your code will understand them.
The Problem
Unfortunately, a nice feature was missed - so much so that I'd call it a bug. 
If your code currently has its DtsPipelineComponentAttribute set to a non-zero version, and you have a PerformUpgrade override, you'll see something you probably don't expect when you drop an instance on the data flow and attempt to edit it.
Attach a debugging session to BIDS and place a breakpoint on PerformUpgrade.  Drop a new component on the data flow and edit it.  What just happened?  Yes - you hit that breakpoint.  Why?  There's no upgrade necessary, is there?  According to SSIS, there is.  If you examine the ComponentMetaData.Version property, you'll see it's set to zero - not to the value you've set on your DtsPipelineComponentAttribute.
The Workaround
No, I didn't file this on Connect like I should have - but I have brought it to the team's attention.  Whether it gets fixed or not based on that lame communication is on me - sorry about that.  Here's what you need to do... add the following code to ProvideComponentProperties for every custom component you make:

DtsPipelineComponentAttribute componentAttribute
=
  (DtsPipelineComponentAttribute)Attribute.GetCustomAttribute(this.GetType(),
    typeof(DtsPipelineComponentAttribute), false);
ComponentMetaData.Version = componentAttribute.CurrentVersion;


This code explicitly writes your "current" version number to the DTSX.  If you watch your code with the debug session again, you'll now see that SSIS doesn't call PerformUpgrade when you edit a brand-new component anymore.

1 comment: