Application Block Software Factory - Sample App II

I wrote earlier about my experiences using the Application Block Software Factory to create a new Application Block and Provider - it started well - and creating my first provider went fine. Putting things into production was a slightly different matter. Again the docs are thin - and it took a brief email exchange between myself, Tom Hollander and Fernando Simonazzi of Clarius Consulting to solve one problem I came unstuck with (no doubt attributed mainly to my first crack at ObjectBuilder and ABSF). The problem I ran into relates to the ProviderData classes that are created by the ABSF. ProviderData classes are created for each of your providers and contain the configuration information required for your provider (read from the .config file). ABSF will also create another class in the source file for your ProviderData class - an Assembler class - ProviderAssembler. ProviderAssembler implements Object Builder's IAssembler interface and is responsible for handing back an instance of your provider, along with feeding any strongly typed settings to the constructor of your provider as required. In broad terms - there are two ways to build classes from your application block using ObjectBuilder: IAssembler or using ObjectBuilder's generic CustomProviderAssembler method. It's not immediately obvious that there are two provider creation strategies here or that there can be issues if you mix the two. One is strongly typed - using your own Provider Assembler class. In this case any attributes you declare in your settings file.... <add name="Provider1" type="MyProvider, ProviderProject.Providers" databaseName="Test" specialProperty="Test" />

(databaseName and specialProperty) will be referred to in your ProviderData class as properties like the following...(just the databaseName attribute here)

private const string DATABASE_NAME = "databaseName";
[ConfigurationProperty(DATABASE_NAME)]
public string DatabaseName
{
get { return (string)this[DATABASE_NAME]; }
set { this[DATABASE_NAME] = value; }
}

During the call to your assembler's Assemble method - you can pass the values of these convenient and strongly typed properties into your provider's constructor.
However here's were I came unstuck.
For each of your ProviderData classes - there is also a BaseProviderData class - and at first glance this seems like correct place to place any provider properties that may be common to all your providers - with one very important exception.
The ABSF also creates a CustomProviderData class - which ALSO derives from the BaseProviderData.
CustomProviderData doesn't implement properties for configuration - it simply reads all the attributes in your settings and places them into a property bag (a name value pair collection) which will get passed into the constructor of your implemented CustomProvider. You then retrieve the settings from the NVC as you need them in your provider (casting into the required types for each attribute).
So...
<add name="Provider2" type="MyCustomProvider, ProviderProject.Providers" databaseName="Test" setting1="Test" setting2="Test" />
In this case setting1, and setting2 will appear in the NVC when received by MyCustomProvider's constructor - BUT - if the databaseName property was defined in the BaseProviderData class - it will NOT be included in the NVC. The NVC is built for 'unknown' attributes only and in the pattern of assembly provided in the ABSF - databaseName is now a 'known' configuration property (known by the BaseProviderData class) and so won't be included.
So - if you are considering offering the client the option to create their own custom providers (as opposed to pre-defined strongly typed providers in the block) - be very careful about placing common property settings in the BaseProviderData class - because if a custom provider needs an attribute of the same name - it will never see it since it won't be included in the NVC of settings during construction.

Category