Rich Newman

August 5, 2007

Dependency Injection and the Composite Application Block (Introduction to CAB/SCSF Part 5)

Introduction

In part 1 of this series of articles I described a simple CAB application. This had three Windows Application C# projects with no references to each other. In spite of this, with some very simple code we could get all three to launch their individual screens. That very simple application didn’t have the projects interacting in any other way, however.

Part 2 of the series described WorkItems, which can be thought of as containers for code, and how we could add a WorkItem to each of our projects in a hierarchy.

Part 3 introduced dependency injection as a way of structuring our code so that our class structure was loosely coupled and behaviour could be easily changed by changing which class was ‘injected’ into another.

In this article I will bring all of these ideas together and explain how dependency injection works in the CAB.

The Problem

We want to get our three projects from part 1 (Red, Blue and Shell) to interact with each other without having them reference each other. As discussed in part 2, WorkItems are designed to allow us to do this: we can put a WorkItem in each project, put code into their various collections, share the WorkItems and thus share the code.

But how does one project know about the WorkItem from another project? Bear in mind that there are no direct references between the projects. This could be done manually in code using reflection, of course. But the CAB framework gives us a much cleaner way to do this.

Dependency Injection and the CAB

The answer is we can use dependency injection to inject a WorkItem from one project or ‘module’ into another.

This is clearly an appropriate thing to do here: we want loose coupling between our modules and flexibility to change how they interact. As I’ve discussed in another article, in extreme cases we might have different development teams responsible for different modules, with different release cycles. Using dependency injection one team could change a class that’s injected and thus change the behaviour of another module without that module needing to be re-released.

However, unlike in my example in part 3, dependency injection in the CAB doesn’t use configuration files to specify which class should be used. Instead attributes are used to tell the code that a dependency needs to be injected.

Example

This is most easily seen with an example. We have already seen that a root WorkItem is created in our CAB application at start up. We have also seen that all modules listed in the ProfileCatalog.xml file will get loaded at the start up of a CAB application, and that a Load() method in a ModuleInit class gets called in each module.

We want a reference to the root WorkItem in a module that is not the shell. We can achieve this by putting a setter for a WorkItem in our ModuleInit class for the module, along with an attribute:

        private WorkItem parentWorkItem;
 
        [ServiceDependency]
        public WorkItem ParentWorkItem
        {
            set { parentWorkItem = value; }
        }

As you can see we decorate the setter with the attribute ‘ServiceDependency’. This tells the CAB framework that when it is loading this module it should look for an appropriate WorkItem to ‘inject’ into this setter.

If we put this code into the RedModuleInit class in our example, and put a breakpoint in the setter we can see that the root WorkItem is being passed into here at start up and stored in the parentWorkItem variable.

How is this Working (1)?

You may wonder how the CAB knows what to inject and where to inject it here. After all there may be multiple WorkItems in our project: which one should it choose? Furthermore we can inject different types (i.e. not WorkItems) in a similar way. If we have several instantiated classes of the same type how do we inject a specific one? And how does the CAB find the ServiceDependency attribute? Does it scan all classes in all modules?

I’m going to leave these issues for now: just accept that the root WorkItem gets injected in this case. I’ll return to this later in this article.

Red and Blue Forms Application

So we can get a reference to the root WorkItem as above. In our naïve CAB application from part 1 we’d quite like to tell the red and blue forms in the modules to load as MDI children into the shell form.

We can do this by firstly adding the shell form to the Items collection of the root WorkItem. Then if the root WorkItem is available in our Red and Blue projects we can access the shell form through the Items collection.

There’s an AfterShellCreated event of the FormShellApplication class that we can override in our program class to add the shell form to the Items collection:

    public class Program : FormShellApplication<WorkItem, Form1>
    {
        [STAThread]
        static void Main()
        {
            new Program().Run();
        }
        protected override void AfterShellCreated()
        {
            base.AfterShellCreated();
            this.Shell.IsMdiContainer = true;
            RootWorkItem.Items.Add(this.Shell, "Shell");
        }
    }

Note that the shell gets a name in the Items collection (“Shell”). Note also that we’re making the shell form into an MDIContainer here, accessing it via the Shell property of the FormShellApplication class.

In the Load method of our modules we can now retrieve the shell form and set it to be the MDIParent of our red and blue forms. So our ModuleInit class looks as below:

    public class RedModuleInit : ModuleInit
    {
        private WorkItem parentWorkItem;
 
        [ServiceDependency]
        public WorkItem ParentWorkItem
        {
            set { parentWorkItem = value; }
        }
 
        public override void Load()
        {
            base.Load();
            Form shell = (Form)parentWorkItem.Items["Shell"];
            Form1 form = new Form1();
            form.MdiParent = shell;
            form.Show();
        }
    }

If we now run the application our red and blue forms will appear as MDI children of the main shell.

The code for this is available. By the way you should know that there are better ways of setting up an MDI application in the CAB: this example is intended to just show the basic concepts of dependency injection.

How is this Working (2)?

Earlier in this article I posed several questions about how all this could be working. I’ll attempt to answer those questions now.

As discussed earlier, WorkItems are generic containers for code to be passed between modules, and are capable of being arranged in a hierarchy. But in addition they are actually ‘Inversion of Control containers’ or ‘Dependency Injection containers’. I mentioned these in part 4 of this series of articles. However, I’ve rather glossed over them up until now. Note that both Spring and PicoContainer use containers to control their dependency injection.

WorkItems as Dependency Injection Containers

These containers work in the CAB as follows. Suppose we want to inject object A into object B. The dependency injection only happens when object B is added into an appropriate collection on a WorkItem. This can be on creation of the object if we create object B with the AddNew method, or it can happen with an existing object if we use the Add method to add it to a WorkItem collection.

Furthermore normally the injection can only work if object A is already in an appropriate collection of the same WorkItem. The exception is if we are using the ‘CreateNew’ attribute (see below). In this case object A will be created and added to the Items collection of the WorkItem before being injected.

As you can see, in a way dependency injection in the CAB is ‘scoped’ to a WorkItem.

Types of Dependency Injection in the CAB

There are three attributes that can be attached to setters and used for dependency injection in the CAB:

  1. ComponentDependency(string Id)
    This attribute can be used to inject any object that already exists in a WorkItem’s Items collection. However, because we can have multiple objects of the same type in this collection we have to know the ID of the item we want to inject (which is a string). We can specify an ID when we add our object into the collection. If we don’t specify an ID the CAB assigns a random GUID to the item as an ID. Note that if the object does not exist in the appropriate Items collection when we try to inject it then the CAB will throw a DependencyMissingException.
  2. ServiceDependency
    We’ve seen this attribute already. An object must be in the WorkItem’s Services collection to be injected using this attribute. The Services collection can only contain one object of any given type, which means that the type of the setter specifies the object uniquely without the need for an ID. I will discuss Services further in part 6 of this series of articles.
  3. CreateNew
    A new object of the appropriate type will be created and injected if this attribute is attached to a setter. The new object will be added to the WorkItem’s Items collection.

As usual this is best seen with an example.

Example

We set up a CAB project with two component classes. Component1 is just an empty class, whilst Component2 has two private Component1 member variables that will be injected. One will be injected by name (and so needs to be created and added to the WorkItem’s Items collection prior to injection). One will be injected by being created:

    public class Component2
    {
        private Component1 component11;
        [ComponentDependency("FirstComponent1")]
        public Component1 Component11
        {
            set { component11 = value; }
        }
 
        private Component1 component12;
        [CreateNew]
        public Component1 Component12
        {
            set { component12 = value; }
        }
    }

To use this we put the following code in the AfterShellCreated method of our FormShellApplication class:

        protected override void AfterShellCreated()
        {
            RootWorkItem.Items.AddNew<Component1>("FirstComponent1");
            Component2 component2 = new Component2();
            RootWorkItem.Items.Add(component2);
            DisplayRootItemsCollection();
        }

Notice the syntax of the AddNew command for the Items collection. It’s a generic method. Remember that a generic is simply a way of providing a type (in this case a class) at runtime. Here we are providing the type “Component1” to the AddNew generic method. A generic method can do anything it likes with the type provided. Here AddNew will instantiate that type and add it to the items collection.

As you can see, we create a Component1 object with ID “FirstComponent1” and add it to the Items collection. We then create a Component2 object using the ‘new’ keyword. We would usually do this using AddNew, but I want to demonstrate that we don’t have to do this. Next we add the Component2 object to the Items collection.

At this point the “FirstComponent1” object will be injected into component2 in the setter marked with the “ComponentDependency” attribute. Also another Component1 object will be created and injected into component2 in the setter marked with the “CreateNew” attribute.

Finally in this code we call a routine called DisplayRootItemsCollection:

        private void DisplayRootItemsCollection()
        {
            System.Diagnostics.Debug.WriteLine("ITEMS:");
            Microsoft.Practices.CompositeUI.Collections.ManagedObjectCollection<object> coll = RootWorkItem.Items;
            foreach (System.Collections.Generic.KeyValuePair<string, object> o in coll)
            {
                System.Diagnostics.Debug.WriteLine(o.ToString());
            }
        }

This just dumps out all the objects in the Items collection to the debug window. The results are as below:

ITEMS:
[4e0f206b-b27e-4017-a1b2-862f952686da, Microsoft.Practices.CompositeUI.State]
[14a0b6a2-12a4-4904-8148-c65802af763d, Shell.Form1, Text: Form1]
[FirstComponent1, Shell.Component1]
[4c7e0a20-90b7-42c6-8912-44ecba40523f, Shell.Component2]
[c40a4626-47e7-4324-876a-6bf0bf99c754, Shell.Component1]

As you can see we’ve got two Component1 items as expected, one with ID “FirstComponent1” and one with ID a GUID. And we have one Component2 item as expected. We can also see that the shell form is added to the Items collection, as well as a State object.

The code for this is available, and if you single-step through it you can see the two Component1 objects being injected into component2.

Where Was All This in the Original Example?

Note that in the original example in this article the root WorkItem was injected into a ModuleInit class apparently without the ModuleInit class being added to any WorkItem. This seems to contradict the paragraphs above that say that we can only inject into objects that are put into WorkItems. However, the CAB framework automatically adds ModuleInit classes into the root WorkItem when it creates a module, so we don’t need to explicitly add them ourselves for the dependency injection to work.

Futhermore, the root WorkItem that was injected as a ServiceDependency even though it had not been explicitly added to any Services collection. Again this seems to contradict the statements above that any object being injected must be in an appropriate collection. But the code works because any WorkItem is automatically a member of its own Services collection.

You can see this if you download and run this example. It is an extension of the original example that allows you to output both the Items collection and the Services collection to the output window via a menu option. If you do this after the application has loaded you get the output below:

ITEMS:
[336ad842-e365-47dd-8a52-215b951ff2d1, Microsoft.Practices.CompositeUI.State]
[185a6eb5-3685-4fa7-a6ee-fc350c7e75c4, Shell.Form1, Text: Form1]
[10d63e89-4af8-4b0d-919f-565a8a952aa9, Shell.MyComponent]
[Shell, Shell.Form1, Text: Form1]
[21ac50d7-3f22-4560-a433-610da21c23ab, Blue.BlueModuleInit]
[e66dee6e-48fb-47f0-b48e-b0eebbf4e31b, Red.RedModuleInit]
SERVICES:
[Microsoft.Practices.CompositeUI.WorkItem, Microsoft.Practices.CompositeUI.WorkItem]
…(Complete list truncated to save space)

You can see that both the BlueModuleInit and RedModuleInit objects are in the Items collection in spite of not being explicitly added by user code, and the WorkItem is in the Services collection.

ObjectBuilder

To understand and use the Composite Application Block you don’t need to understand in detail its underlying code. It’s intended to be used as a framework after all. However, it’s useful to know that the dependency injection here is all done by the ObjectBuilder component.

When we call AddNew or Add on a collection of a WorkItem it’s the ObjectBuilder that looks at the dependency attributes on the class we’re adding and injects the appropriate objects.

The ObjectBuilder is a ‘builder’ in the classic design patterns sense. The builder pattern ‘separates the construction of a complex object from its representation so that the same construction process can create different representations’.

Note that this pattern is often called a ‘factory pattern’, although factories in the Gang of Four ‘Design Patterns’ book are slightly different things (we’re not creating families of objects (Abstract Factory) or ‘letting ‘the subclasses decide which class to instantiate’ (Factory Method)).

WorkItems in a Hierarchy and Dependency Injection of Items

As discussed previously, one of the strengths of WorkItems is that multiple instances can be instantiated in different modules, and they can all be arranged in a hierarchy. This is because each WorkItem has a WorkItems collection. However, you should be aware that dependency injection only works for items in the current WorkItem. If you attempt to inject an object in a different WorkItem in the hierarchy into an object in your WorkItem you will get a DependencyMissingException.

We can see this by modifying the AfterShellCreated event of our FormShellApplication in the example using Component1 and Component2 above:

        WorkItem testWorkItem = null;
        protected override void AfterShellCreated()
        {
            testWorkItem = RootWorkItem.WorkItems.AddNew<WorkItem>();
            RootWorkItem.Items.AddNew<Component1>("FirstComponent1");
            // The next line throws an exception as the testWorkItem
            // container doesn't know about FirstComponent1, and Component2
            // is asking for it to be injected.
            testWorkItem.Items.AddNew<Component2>();
            DisplayRootItemsCollection();
        }

Here we add a new WorkItem to our RootWorkItem. We add an instance of Component1 with ID “FirstComponent1” to our RootWorkItem as before. Then we add an instance of Component2 to our testWorkItem.

Remember that Component2 asks for a Component1 object with ID “FirstComponent1” to be injected when it is created. Because the testWorkItem knows nothing about such an object we get an exception thrown.

We can fix the code by adding our Component1 into the testWorkItem instead of the RootWorkItem:

testWorkItem.Items.AddNew<Component1>("FirstComponent1");

The code for this example is available.

WorkItems in a Hierarchy and Dependency Injection of Services

Services behave differently to the example given above.

We can make Component1 a service by adding it to the Services collection of the RootWorkItem instead of the Items collection, and telling Component2 it’s a ServiceDependency and not a ComponentDependency. Then the code will work. This is because the CAB includes a service locator that looks in all parent WorkItems of the current WorkItem to see if a given service is available. I will discuss this in more detail in part 6.

Conclusion

Dependency injection in the CAB is a powerful tool. It enables us to share code between modules in a loosely-coupled way.

In part 6 of this series of articles I discuss how we can use the CAB to do constructor injection. Part 7 of the series will investigate the Services collection of a WorkItem in some detail.

About these ads

18 Comments »

  1. Thanks so much for your CAB postings. I have searched the web trying to find a clear explanation for CAB. You are the only one that has provided it that I have found. I look forward to future installments.

    Comment by Terry — August 14, 2007 @ 7:37 pm

  2. Thank you for this series of posts on CAB. I’m finally going to be using CAB/SCSF and have found your posts very useful indeed. Keep them coming!

    Comment by Anthony Mason — August 22, 2007 @ 8:46 am

  3. Thanks Newman, Excellent articles n CAB,slowly introducing the concepts.

    Comment by Kumaresan — August 30, 2007 @ 3:31 pm

  4. Thanks Newman, I am now beginning to understand CAB, your postings have helped me a good level. Keep up the good work.

    Comment by Abel Goodman — October 3, 2007 @ 7:06 pm

  5. What are the areas in which the object buider comes in.Does it have a performance penalty

    Comment by NG — October 9, 2007 @ 6:33 pm

  6. Nice series, Rich.
    In your next session you discuss some of the problems with Constructor injection … and missed an important one; I’ll save my comment for that one.
    Here you have a section entitled “Types of Dependency Injection in the CAB” … which describes the attributes. This may confuse people. The usual coverage of this topic observes that CAB supports 3 types of injection: constructor, property, method. You show property injection in this session and constructor injection in the next session.
    I didn’t see you touch on method injection which happens to be my favorite for reasons I hope to explain in comments to session 6.
    Keep up the great work

    Comment by Ward Bell — October 25, 2007 @ 6:56 pm

  7. Oops. I see you DID cover two of the CAB injection types in session 3. Excuse me for skipping ahead. You passed on Method injection about which I’ll say a few words in comments to Session 6.
    P.S.: To be clear, method injection is not the same as interface injection; CAB does not offer an interface injection mechanism as far as I know.

    Comment by Ward Bell — October 25, 2007 @ 8:58 pm

  8. Hi Rich
    Your articles are very easy to understand . It is like reading a thriller story book. You are the only person who could explain CAB in such a great way. I just read till part 5, and continue to read the remaning. Thank you very much.

    Comment by Sujith — May 29, 2008 @ 11:07 am

  9. Rich, you can explain these complex CAB concepts in such a simple way. Really amazing!
    I can’t wait to continue reading your articles!

    Thanks a lot!

    Comment by Jowan — June 12, 2008 @ 8:33 am

  10. [...] package all poorly constructed and even poorer explained. The answers I was looking for I found in this excellent blog of Rich Newman where I found out how exactly does module initialization [...]

    Pingback by Reinis blog » Composite UI Application Block: Modules explained — November 28, 2008 @ 1:41 pm

  11. HI Rich,

    I am very much impressed with this article on CAB, it is the best article available online on CAB and Dependency Injection specially for people who are new to these concepts.
    Keep doing this good work.

    Thanks a lot.

    Comment by Schaffer — January 20, 2009 @ 10:08 pm

  12. I am new to this; hence my reading of these articles. However I am really not getting it. To me it seems that there is a lot of work and abstraction going on to “decouple” and the objects still need to know about one another. Component2 needs to know about component1 so that it can be injected (the attribute references the name and an object of type component1 is created) and the Shell has to know about the components to “type” the generic as it adds them.

    Admittedly, I have never really worked with attributes or (obviously) CAB, so I am certain of my ignorance, but I don’t know what I don’t know. Moreover, I truly appreciate all the effort you have gone through explaining this. But sadly, thus far, I am too dense to get it. Can you dumb it down for this ignorant soul?

    Comment by Jason — January 21, 2009 @ 11:13 pm

  13. I haven’t found any other article on the internet which is as simple and understandable as this. I used to struggle with these frameworks and its concepts, but now everything looks very easy to me after reading your articles.

    Comment by Pradeep — May 7, 2009 @ 9:06 am

  14. Rich,

    Your articles are great! Easy to read and understand.

    My only suggestion is a better way to navigate from article to article in a series. In general I found it hard to get around without having to go back to the table of contents. It’s not going to keep me from reading your blog, but I figured you would like the feedback.

    Comment by Dustin — June 12, 2009 @ 1:26 pm

  15. Hey Rich,

    You’re undoubtedly a RICH source of CAB! You rock!

    Comment by Akash — May 30, 2010 @ 4:30 pm

  16. Каждому Доброе утро! Заходите на Супер дискографии и качайте море дискографий!

    Comment by kalendula196Р — February 22, 2011 @ 5:46 am

  17. Previously I have studied hundred of articles on CAB architecture. This completely different than anyone. Really you are awesome. Till i now I assumed CAB very complex architecture and given up also. Now after reading this articles, got a very good understanding and getting much interest also. This world need people like you. I am really thankful to you. you are Guru of CAB.

    Comment by Krishna — November 10, 2011 @ 2:57 pm

  18. Very useful article. Excellent job explaining the key parts of the framework unlike most of the ones I’ve seen on the interenet including even msdn postings.

    Comment by Anonymous — June 3, 2013 @ 2:58 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Shocking Blue Green Theme. Create a free website or blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 80 other followers

%d bloggers like this: