bbv.Common.Bootstrapper Tutorial Part 3

Behaviors

Behaviors allow extending the bootstrapping process in an aspect oriented style. Behaviors gain access to extensions which are participating in the bootstrapper process and can therefore influence them for example by injecting additional runtime information into an extension. Behaviors must implement IBehavior<TExtension>. They automatically gain access to all extensions participating the bootstrapping process. Behaviors are executed before the corresponding extension point is called.

Let’s us look into an example. Imagine you have the following module provider interface below:

   public interface IModuleProvider : IEnumerable<IModule> { }

The behavior below demonstrates how extensions can be scanned whether they are module providers. If an extension implements IModuleProvider all provided modules are automatically collected in the module collection the behavior receives upon construction.

    public class ModuleProvidingBehavior : IBehavior<ICustomExtension>
    {
        private readonly ICollection<IModule> modules;

        public ModuleProvidingBehavior(ICollection<IModule> modules)
        {
            this.modules = modules;
        }

        public string Name { get { return this.GetType().FullNameToString(); } }

        public void Behave(IEnumerable<ICustomExtension> extensions)
        {
            extensions.OfType<IModuleProvider>()
                                .SelectMany(provider => provider, (provider, module) => module)
                                .ToList()
                                .ForEach(module => this.modules.Add(module));
        }

        public string Describe() { return "Collects all IModule's on extensions which implement IModuleProvider during bootstrapping."; }
    }

Below is a sample IModule implementation which uses a made up fluent syntax to register dependencies.

    public class CustomModule : IModule
    {
        public void Load(IContainer container)
        {
            container.Register<DependencyUsingBehavior>().ToSelf();
            container.Register<IDependency>().To<Dependency>();
            container.Register<IBehavior<ICustomExtension>>().ToMethod(ctn => ctn.Resolve<DependencyUsingBehavior>());
        }
    }

Below an extension which implements IModuleProvider and yield returns a custom module. Note:Of course the custom module could also have been added by overriding ContainerInitializing and adding the module to the collection. But the sample should demonstrate the power of behaviors.

    public class ExtensionWhichIsModuleProvider : CustomExtensionBase, IModuleProvider
    {
        public IEnumerator<IModule> GetEnumerator()
        {
            yield return new CustomModule();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        public override string Describe() { return "Extension which implements IModuleProvider"; }
    }

The DependencyUsingBehavior is a special behavior which does not consume extensions but execute an operation on a dependency. The dependency is resolved by using constructor injection. To enable constructor injection when constructing the DependencyUsingBehavior the IContainer implementation must already be built up and the required dependencies registered.

    public class DependencyUsingBehavior : IBehavior<ICustomExtension>
    {
        private readonly IDependency dependency;

        public DependencyUsingBehavior(IDependency dependency)
        {
            this.dependency = dependency;
        }

        public string Name { get { return this.GetType().FullNameToString(); } }

        public void Behave(IEnumerable<ICustomExtension> extensions)
        {
            this.dependency.Hello();
        }

        public string Describe() { "Uses IDependency and executes \"Hello()\" in the provided dependency."; }
    }

The DisposeExtensionBehavior calls Dispose on all extensions which implement IDisposable.

    public class DisposeExtensionBehavior : IBehavior<IExtension>
    {
        public string Name { get { return this.GetType().FullNameToString(); } }

        public void Behave(IEnumerable<IExtension> extensions)
        {
            foreach (IDisposable extension in extensions.OfType<IDisposable>())
            {
                extension.Dispose();
            }
        }

        public string Describe() { return "Disposes all extensions which implement IDisposable."; }
    }

Now all these pieces must be sticked together in the strategy. Let’s look how to define it in the next post of this series.Keep your RSS reader prepared 😉

About the author

Daniel Marbach

1 comment

By Daniel Marbach

Recent Posts