Builder Strategy Order

Topics: ObjectBuilder
May 24, 2010 at 8:32 AM

The Composite Application UI Block (CAB) uses Object Builder for dependency injection.  I faced a problem when trying to unit test certain areas of CAB as they reference concrete implementations of views and services such as the following line of code;

ISplashView splashView = WorkItem.SmartParts.AddNew<SplashView>();

Object Builder is used to create and return an instance of the SplashView.

My approach was to create a new builder strategy for Object Builder that occurred at the stage of PreCreation.  My strategy uses mappings between interfaces and concrete classes from the application configuration file in order to build the correct object – so my code now looks like the following;

ISplashView splashView = WorkItem.SmartParts.AddNew<ISplashView>();

The splash view can now be mocked and the class becomes unit testable and the assemblies less tightly coupled.

It all works fine apart from the property based dependency injection (which doesn’t work at all).  Object Builder allows you to add several attributes to properties to allow them to be set by Object Builder, for example;

[CreateNew]
public SplashViewPresenter Presenter       
{
               
    set

        {
              _presenter = value;
              _presenter.View = this;

         }
}

I'm aware that there is a strategy available out of the box called TypeMappingStrategy, however, the mapping is done in code so we still end up with non unit testable code.  It also means we need to create a policy for each type we wish to build so it would be a reasonable amount of code.

From what I understand, there is a builder strategy that is responsible for setting these properties using reflection.  This strategy is also in the PreCreation stage. 

I think that the reason its not working with my strategy is down to the order that the strategies are executed.  Mine would have to be the first one to run as it is essentially changing the type that we are trying to build.  If the strategy responsible for setting the properties ran before mine, it would be running on the interface and not the concrete class.

If that assumption is true then the simple fix would be to re-order the strategies to ensure that mine was the first to run, however, I can’t find a way to do it.

Cheers
Steve.

Oct 14, 2010 at 1:54 PM
Edited Oct 15, 2010 at 1:03 PM

I have created the following strategy:

 

    public class TypeMappingStrategyWithoutPolicyId : BuilderStrategy
    {
        /// <summary>
        /// Implementation of <see cref="IBuilderStrategy.BuildUp"/>.
        /// </summary>
        public override object BuildUp(IBuilderContext context, Type t, object existing, string id)
        {
            DependencyResolutionLocatorKey result = new DependencyResolutionLocatorKey(t, id);

            ITypeMappingPolicy policy = context.Policies.Get<ITypeMappingPolicy>(t, null);

            if (policy != null)
            {
                result = policy.Map(result);
                TraceBuildUp(context, t, id, Properties.Resources.TypeMapped, result.Type, result.ID ?? "(null)");
                Guard.TypeIsAssignableFromType(t, result.Type, t);

                return context.HeadOfChain.BuildUp(context, result.Type, existing, id);
            }

            return base.BuildUp(context, result.Type, existing, id);
        }
    }

 

The instruction :

context.HeadOfChain.BuildUp(context, result.Type, existing, id);

reinsert the mapped type in ObjectBuilder "pipeline" resolving the dependency. 

The policy for mapping is:

Builder.Policies.Set<ITypeMappingPolicy>(new TypeMappingPolicy(typeof(SplashView), null), typeof(ISplashView), null);