Category Archives: WCSF

Builders in WCSF

Expect more details about mini-DI in WCSF. Be sure to read previous posts before this one.

WCSF has a two builders (i.e. builders that instantiate the requested objects), they are identical objects (and use identical type and service mappings), but have one crucial difference – singleton policy:

  • ApplicationBuilder – Builder used by the modules and thus in Module Initializers (MI). Its singleton policy is such, that created singletons are stored in the ILocatior. When MI adds a service to the module (e.g. using a container.ServicesNew<SomeService,ISomeService>()), the application builder is used and real singleton service is created. The service is available to all objects in the module and all child modules (unless they overwrite service mapping).
  • PageBuilder – Used by the pages and web controls. WCSF has a lot of slightly tailored WebControls in Microsoft.Practices.CompositeWeb.Web.UI that are subclasses from System.Web.UI, so with WCSF you use the Microsoft.Practices.CompositeWeb.Web.UI.Page instead of System.Web.UI.Page. The singleton policy is such that objects created by this builder are never added to the ILocator thus are never singletons.

Why is there a PageBuilder? The reason is simple, the PageBuilder is used only by the WCSF WebControls to build up the properties of the WebControls. The WCSF WebControls themselves are not instantiated by the ObjectBuilder, but by ASP.NET. The ObjectBuilder comes into a play using the a code in the event methods of the WCSF WebControls (that is the reason why they are there). The WCSF is using PageBuilder to populate the properties of a page using ObjectBuilder, e.g. in OnPreInit method of Page object, OnInit method of MasterPage and so on.

The WebControls themselves are never singletons thus the singleton policy of the PageBuilder and ApplicationBuilder differ.

Crucial difference

Just because PageBuilder doesn’t store singletons doesn’t mean that it always created a new service instance for services. Thanks to default order of the strategies and common ILocator, if it finds a [ServiceDependency], it will locate the service in the ILocator (populated in ModuleInitializer) and uses already existing instance!

The difference in singleton policy is only if created instance is stored in ILocator or not. If there already is an instance, the WCSF will use it.

Basically they tried to work around the problem of how to build up a page we haven’t instantiated. They build it up (=fill public [CreateNew]/[ServiceDependency] properties) in the OnPreInit/OnInit methods of WebControls.

How to use

You use PageBuilder automatically when you use WCSF WebControl. If you really need to use it, call static method WebClientApplication.BuildItemWithCurrentContext(objectToBeBuild).

The ApplicationBuilder property is in Global.asax (the page is derived from the WebClientApplication). To use application builder, follow the code of the BuildItemWithCurrentContext. Basically you need

IModuleContainerLocatorService – WCSF service to locate module from the URL of the page. Use the current URL and get a CompositionContainer of a module.

From CompositionContainer get ILocator and call

webApp.ApplicationBuilder<TypeToBeBuild>(locator, idToBuild, nullOrExistingObject);

For more info, just dive into the source (or not.. I would rather not).

ObjectBuilder in WCSF

I have described how does the ObjectBuilder work in the previous post. The reason why I even started to investigate the internals of a dead project is because of the WCSF – another dead project.

Since OB is a framework for building DI, the WCSF has created its own simple DI with two ways to build up objects – either as singletons or new objects. The depending objects can be inserted either through constructor or through properties.

The WCSF has its own builder of objects – the WCSFBuilder class derived from WCSFBuilderBase. It should be noted that when you diff the WCSFBuilderBase from the WCSF and BuilderBase from OB, they are quite similar and there was no reason to reimplamenetcopy&edit the base builder class.

The gist of WCSF are four strategies:

Strategies.AddNew<TypeMappingStrategy>(WCSFBuilderStage.PreCreation);
Strategies.AddNew<SimplifiedSingletonStrategy>(WCSFBuilderStage.PreCreation);
Strategies.AddNew<BuildPlanStrategy>(WCSFBuilderStage.Creation);
Strategies.AddNew<BuilderAwareStrategy>(WCSFBuilderStage.PostInitialization);

Policies.SetDefault<ICreationPolicy>(new DefaultCreationPolicy());
Policies.SetDefault<IBuildPlanPolicy>(new BuildPlanPolicy());
Policies.SetDefault<IPlanBuilderPolicy>(CreatePlanBuilder());

private static IPlanBuilderPolicy CreatePlanBuilder()
{
  BuilderStrategyChain chain = new BuilderStrategyChain();
  chain.Add(new CallConstructorStrategy());
  chain.Add(new SetPropertiesStrategy());
  chain.Add(new CallMethodsStrategy());

  PolicyList policies = new PolicyList();
  policies.SetDefault<IConstructorChooserPolicy>(new AttributeBasedConstructorChooser());
  policies.SetDefault<IPropertyChooserPolicy>(new AttributeBasedPropertyChooser());
  policies.SetDefault<IMethodChooserPolicy>(new AttributeBasedMethodChooser());

  return new DynamicMethodPlanBuilderPolicy(chain, policies);
}

As you can see, the OB has four chained strategies that are chained.

 

TypeMappingStrategy

This is strategy that preprocess the buildup request before passing it to the rest of chain, it doesn’t actually build the object. Its task is to change requested type to the type we actually to build up, in most cases it maps interfaces to concrete classes, e.g. ITimeService to NetworkTimeProtocolService. The precise mapping is defined by ITypeMappingPolicy.

SimplifiedSingletonStrategy

This strategy is quite simple:

  • If locator contains an instance of requested object with id&type -> Return instance
  • Otherwise build up the object using rest of chain, insert it to locator and return it.

The startegy checks and respects ISingletonPolicy of builder. If the policy says no to singletons, new instance is not injected into locator.

BuildPlanStrategy

This is a candidate for The Daily WTF. When I go through all the stuff and dependency, it seems to create a specialmethod using ILGenerator just for creation. We actually have things like il.Emit(OpCodes.Ldarg_2);. Generating assembler at runtime… In 2008.

This strategy uses DynamicMethodPlanBuilderPolicy that basically for each type creates a dynamically created method (using ILGenerator and opcodes) for building an object of the type. The strategy then calls the method to create the object and passes the created object to the next link of the chain.

The interesting part is DynamicMethodPlanBuilderPolicy.CreatePlan – the method returns dynamic method “BuildUp_” + typeToBuild that will be executed on typeToBuild class.

The code of method is generated sequentially by the chain from CreatePlanBuilder from code snippet above:

// Code used to create a method that will build up the typeToBuild in the DynamicMethodPlanBuilderPolicy used by BuildPlanStrategy
ILGenerator il = buildMethod.GetILGenerator();
// In this chain is the CallConstructorStrategy, SetPropertiesStrategy and CallMethodsStrategy
context.HeadOfChain.BuildUp(context, typeToBuild, il, idToBuild);
il.Emit(OpCodes.Ret);

The CallConstructorStrategy check if existing object is null, if not, it builds up parameters of constructor and calls it.

  • The SetPropertiesStrategy builds up and sets objects for all marked properites ([CreateNew]/[ServiceDependency]).
  • The CallMethodsStrategy – It will call all methods of the object that have the [InjectionMethod] attribute with build up parameters.

Aaaargh! Is there any reason to do this instead of three link of build starategy chain, where

  • first link creates an instance using constructor and passes it to the second one
  • second link builds up and assigns instances to the [CreateNew]/[ServiceDependency] properties of the object
  • third calls all [InjectionMethod] methods of the existing object.

UPDATE: Somebody probably thought so too, because there are three unused strategies that do exactly that: ConstructorReflectionStrategy, PropertyReflectionStrategy and MethodReflectionStrategy.

Once the method creates the existing object, is is passed to the last strategy:

BuilderAwareStrategy

Post initialization task, this strategy checks if passed existing object is an instance of IBuilderAware and if it is, the OB will call OnBuiltUp method of the existing object.

I think this strategy is used only in tests of WCSF, e.g. if WCSF did build up a WCSF UserControl.