Single implementation only w/ the ABSF

Topics: Building and extending application blocks
Nov 1, 2007 at 3:47 PM
Edited Nov 1, 2007 at 3:52 PM
I'm implementing the provider pattern in my project using the application block software factory.

Among my provders, I have a few that should only ever have a single implementation.

I cannot figure out how to create an ApplicationBlockSettings object that enforces this restriction and works with implementations of the block.

Originally, I had a required configuration property that returned an ApplicationBlockData object. This worked fine, but implementations would always get the base Data object and not the derived Data object, thus causing an invalid cast during the creation process.

Converting this property to a NameTypeConfigurationElementCollection<ApplicationBlockData,ApplicationBlockData> would return the correct type of ApplicationBlockData for implementors (say, MyProviderImplementationData), but multiple implementations could be configured simultaneously, thus breaking my requirement of a single implementation only.

My question is: How do I create a configuration property in the ApplicationBlockSettings class that will return the correct derived class for my provider's implementors?

Non-working code follows:

// Always returns an AuthorizationLayerData object
[ConfigurationProperty(_authorizationLayerProperty, IsRequired = true)]
public AuthorizationLayerData AuthorizationLayerData
{
get { return (AuthorizationLayerData)base[_authorizationLayerProperty]; }
set { base[_authorizationLayerProperty] = value; }
}

<?xml version="1.0" encoding="utf-8" ?>
<!-- app.config for the above method; always returns the AuthorizationLayerData object -->
<configuration>
<configSections>
<section name="AuthorizationLayerConfiguration" type="Prototype.AuthorizationLayerBlock.Configuration.AuthorizationLayerSettings, Prototype.AuthorizationLayerBlock"/>
</configSections>
<AuthorizationLayerConfiguration>
<AuthorizationLayer name="lol my implementation" type="Prototype.Authorization.MyAuthorizationLol, Prototype"/>
</AuthorizationLayerConfiguration>
</configuration>


Working code follows:

// Will return the correct derived class
[ConfigurationProperty(_authorizationLayerProperty, IsRequired=true)]
public NameTypeConfigurationElementCollection<AuthorizationLayerData, AuthorizationLayerData> AuthorizationLayer
{
get
{
return (NameTypeConfigurationElementCollection<AuthorizationLayerData, AuthorizationLayerData>)base[_authorizationLayerProperty];
}
}

<?xml version="1.0" encoding="utf-8" ?>
<!-- This returns the correct type, but you can 'add' more AuthorizationLayers -->
<configuration>
<configSections>
<section name="AuthorizationLayerConfiguration" type="Prototype.AuthorizationLayerBlock.Configuration.AuthorizationLayerSettings, Prototype.AuthorizationLayerBlock"/>
</configSections>
<AuthorizationLayerConfiguration>
<AuthorizationLayer>
<add name="AuthorizationManager" type="Prototype.AuthorizationManager, Prototype" />
</AuthorizationLayer>
</AuthorizationLayerConfiguration>
</configuration>
Nov 1, 2007 at 5:48 PM
Had an idea to implement my Data object as the configuration section. In other words, I won't use an AppBlockSettings object to retrieve my AppBlockData element, I'll simply place my configuration information into properties of the configuration section itself. The section definition thusly determines what type the AppBlockData object will be at runtime, meaning that I can set the type to the implementation's Data object.

This seems like it should work, however the object assembly process has choked on me. The error I get is:

Test method Prototype.Tests.AuthorizationLayerBlock.AuthorizationLayerFactoryTest.CreateAuthorizationLayerTest threw exception: System.InvalidOperationException: The assembler configured for type Prototype.AuthorizationLayerBlock.Configuration.AuthorizationLayerData has type Prototype.AuthorizationLayerBlock.Factory.AuthorizationLayerAssembler which is not compatible with type Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.IAssembler`2Prototype.AuthorizationLayerBlock.IAuthorize,Prototype.AuthorizationLayerBlock.Configuration.AuthorizationLayerData..

I have no idea what "is not compatible with type" means, as it compiles perfectly fine. I'm currently trying to figure out exactly what "type" it is "compatible with". Hints are always welcome.
Nov 1, 2007 at 5:55 PM
Hi,

What does the AuthorizationLayerAssembler class look like?

Fernando
Nov 1, 2007 at 8:30 PM
Solved. In my base provider implementation I had implemented IAssember<AppBlock,AppBlockData>. the builder was looking for IAssembler<IAppBlock,AppBlockData>. It works like a charm now.

TL;DR version:
If you only want ONE implementation of your provider used within your application, your ApplicationBlockData class should extend directly from SerializableConfigurationSection
Nov 1, 2007 at 8:31 PM
public class AuthorizationLayerAssembler : IAssembler<IAuthorize,AuthorizationLayerData>
{
/// <summary>
/// Builds an instance of the subtype of <typeparamref name="Prototype.AuthorizationLayerBlock.AuthorizationLayerBase"/> type the receiver knows how to build, based on
/// an a configuration object.
/// </summary>
/// <param name="context">The <see cref="T:Microsoft.Practices.ObjectBuilder.IBuilderContext"/> that represents the current building process.</param>
/// <param name="objectConfiguration">The configuration object that describes the object to build.</param>
/// <param name="configurationSource">The source for configuration objects.</param>
/// <param name="reflectionCache">The cache to use retrieving reflection information.</param>
/// <returns>
/// A fully initialized instance of the <typeparamref name="Prototype.AuthorizationLayerBlock.AuthorizationLayerBase"/> subtype.
/// </returns>
public virtual IAuthorize Assemble(IBuilderContext context, AuthorizationLayerData objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
{
return new AuthorizationLayerBase( objectConfiguration );
}

}