left-icon

Prism 4 Succinctly®
by Eric Stitt

Previous
Chapter

of
A
A
A

CHAPTER 5

Dependency Injection And The Prism 4 Bootstrapper

Dependency Injection And The Prism 4 Bootstrapper


Dependency Injection (DI), tends to be one of the most confusing concepts in programming. Are DI and Inversion Of Control (IoC) the same? Is DI simply an enhanced factory design pattern? Is DI a Service Locator? Are DI and Dependency Injection Containers (DIC) the same? At what times do I use DI?  At what times don't I use DI?

We are going to address these and more questions about DI in this chapter. We'll also show how DI and DICs integrate into Microsoft Prism 4. We'll talk about some strategies that will help when working with DI in Prism 4. And we'll look at how to use DI with some of the Gang Of Four  (GoF) Design Patterns.

Let's take a look at each of the above questions to see if any are valid.

Is Dependency Injection and Inversion of Control (IoC) the Same?

No. IoC refers to a broad range of programming styles where a framework controls program flow. DI is included in this definition as a subset, but not as IoC. So it is more accurate to think of DI as one aspect of IoC.  

Is DI Simply an Enhanced Factory Design Pattern?

No. See is DI a Service Locator?

Factories simply create single objects, they could be enhanced to do more, but why to so when we have DI?. DI is designed to create object graphs. What this means is that when an object is created, any needed dependences (entities that the object needs to do its work), are created without the parent object specifically requesting them. In most cases the dependent entities are injected into the parent entity when it is created. 

Is DI a Service Locator?

No. Service locators are general purpose factories that supply services to a requesting entity. DI on the other hand, provides a means to transparently insure that an entity is supplied with its necessary services. The entity should not find it necessary to ask for a collaborating entity, it should simply be supplied.

Are DI and Dependency Injection Containers (DIC) the same?

No. DI is the technique that is needed to create loosely coupled code. This can be done without a DIC. A DIC simply encapsulates the DI functionally into a library such as Unity. While DI can be implemented as needed, a DIC makes things a lot easier.

At What Times Do I Use DI?

DI should be used when volatile dependencies are introduced to your solutions. Volatile dependencies are entities in your code that are not stable. A good example is when a relational database is used with your solution. You don't really have control over the database that your clients use. In fact, there is nothing stopping clients from starting with one database (Microsoft Access or Oracle), and changing to another (SQL Server). Another scenario is that your clients want to have both relational and cloud based data repositories.

In the previous cases it's important to build loosely coupled entities. It's also important to consider that these entities may need to use late binding. These are just two examples where DI would be useful.       

At what times don't I use DI?

We don't need DI (in most cases), when stable dependences are introduced into our solutions. When we talk about stable dependencies, we mean that we are using libraries that are not going to change. These are mostly libraries that reside in stable frameworks such as the .NET framework. Most classes in this framework have deterministic code that will not change over time.

It is important to insure that the code in these frameworks are stable. Using libraries such as ADO .NET or Entity Framework are exceptions where it is better to use DI even though they are a part of a stable framework. 

What Is Dependency Injection?

Now that we have a pretty good idea of what DI isn't, let's take a look at what it is. The main reason for DI is to help enforce loose coupling in your code. There are other aspects that are important such as testability, extensibility, parallel development, late binding and maintainability. But Loose coupling really encompasses all of the above items with the exception of testability.

What do we mean by loosely coupled code? Loosely coupled code tends to adhere to the SOLID principals. The SOLID principals define five methods that help in designing well architected solutions.

S: The Single responsibility principal.

A class should be atomic. It should focus on a single task only.

O: The Open / closed principal.

Software entities should be open to extensibility and closed to modification.

L: The Liskov substitution principal.

Classes should be designed with contracts (abstractions) so that concrete implementations that use the abstractions, (interfaces or abstract classes) can be easily changed without adverse reactions.

I: Interface segregation principal.

Program to fine grained interfaces and not to general (course grained) interfaces.

D: Dependency inversion principal. 

Program to abstractions and not to concrete implementations. Dependency Injection uses this principal.

Why Use Dependency Injection? Object Composition:

DI allows us to defer object creation to the DIC of choice, this is called Object Composition. This gives us the ability to create objects in an almost transparent manner. In the Virtual Calculator solution a number of services are registered with the Unity DIC. Constructor injection is then used to instantiate the objects when the parent object is created. This allows for the creation of object graphs that take responsibility for the creation of all dependent objects associated with a parent object. Unlike factories which are designed to create a single object, DI not only creates the parent entity but also resolves any dependent entities.

Refactoring and extending code becomes easier because changes only need to be made in a single location. As long as the new code inherits from a base class or implements the same interface, concrete classes can be changed as needed.   

DI is also important because substituting classes becomes much easier. This is particularly important when working with Test Driven Development (TDD), because it is easy to substitute mock classes with the actual classes that are used in the solution when testing.

Object Lifetime:

DICs also have the ability to manage object lifetime. Instance or singleton objects can be created by simply adding code when registering the class.

 Listing 5: Using the Container Controlled Lifetime Manager to Create a Singleton Class.

Container.RegisterType<ICalculatorExceptionController,

                CalculatorExceptionController>

                (new ContainerControlledLifetimeManager());

Listing 5 shows an example of creating a singleton CalculatorExceptionController with the Unity DIC. A new ContainerControlledLifetimeManager is passed to the  RegisterType method of the Container class. The unity DIC creates instance objects as a default, these objects are created and destroyed by the garbage collector when the enclosing entity goes out of scope. Singletons on the other hand once created persist as a single entity for the lifetime of the application.

Dependency Injection Containers:

There are a number of DICs that either work out of the box or that can be configured to work with Prism 4. Here is a list of some of these DICs:

  • Unity *
  • Managed Extensibility Framework (MEF) *
  • Autofac
  • Spring .NET
  • Castle Windsor
  • Structure Map

* Works with Prism 4 without the need to create a custom bootstrapper class.

What Is the Bootstrapper Class:

The bootstrapper class is the startup class for Prism 4 solutions. It exposes a number of methods that allow for the initialization of Prism 4 solutions. The rest of this chapter will be devoted to explaining how this class works and how the Unity DIC integrates with the class.

  Listing 6: The Main Bootstrapper Class Definition.

public class MainBootstrapper : UnityBootstrapper

{

}

Listing 6 shows an example of the MainBootstrapper class definition. Notice that the class inherits from the UnityBootstrapper class. This class has a number of override methods that are used to initialize Prism 4 solutions.  The Unity DIC is used in all example code in this book.

To use the MainBootstrapper class with other DICs simply Inherit from a class that is associated with the DIC. Microsoft provides two DIC bootstrapper base classes that are ready to use. Classes are provided for Unity and MEF.

If you are familiar with another DIC other than these two (Unity and MEF), you can write a base class for your DIC of choice.

The Bootstrapper CreateShell Method:

As we saw earlier in the Hello World solution, the CreateShell method is used to create and show the shell form in Prism 4 solutions. The shell form that was created in the Hello World solution was designed to be as simple as possible. It only used a single label control. You'll find that the shell forms in this solution include quite a bit more functionally. We'll go into more detail in chapter 6.

For now, let's look at the code that creates the shell forms.

Listing 7: The Main Bootstrapper CreateShell Method.

        Private Window ShellForm;

        Private byte ShellSelector = 0;

        protected override System.Windows.DependencyObject CreateShell()

        {

            //Register services and objects with the Dependency Injection Container.

            CreateServices();

            //Create and show the Prism 4 shell form:           

            ShellForm = CreateShellForm(ShellSelector);

            return ShellForm;

        }

Unlike the single shell form in the Hello World solution, the Virtual Calculator solution has two shell forms. One form has logos at the top and the other has logos located on the bottom of the form.

A class level member of the type byte, named ShellSelector is used to determine which form is shown. A value of zero displays the logo top form and a value of one displays the logo bottom form. See figures 8 and 9 to see examples of the forms. A byte type was used to reduce the complexity of adding more than two shell forms if necessary.

We'll talk about the call to the create services method later in this chapter.

The CreateShellForm Method:

The CreateShellForm method is used to instantiate one of the two shell forms when the solution starts. The ShellSelector value is passed as an argument to the method and a Window control is returned. Here is an example of the CreateShellForm code.

Listing 8: The Main Bootstrapper CreateShell Method.

private Window CreateShellForm(byte ShellSelector)

{

   if (ShellSelector == 0)

   {              

      var ShellConverter = Container.Resolve<ICreateShellForm>();

      return ShellForm = ShellConverter.CreateShellForm();

   }

   else

   {               

      var ShellConverter = Container.Resolve<ICreateShellForm>("LogoBottom");

      return ShellForm = ShellConverter.CreateShellForm();

   }

}

The CreateShellForm method could be refractored to eliminate the conditional code (if- then -else). This would reduce the amount of code that is needed to extend the functionally. 

This code is interesting because the strategy design pattern is used to create the shell forms. Rather than create and call methods in the bootstrapper class or hardcode the shell creation code into the CreateShellForm method, an interface was created ICreateShellForm. Classes were then created for each of the two forms. These classes implement the ICreateShellForm Interface. Here is an example of the ICreateShellForm code.

Listing 9: The ICreateShellForm Interface.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

namespace PRISM4.MAIN.CLASSES

{

    public interface ICreateShellForm

    {

        Window CreateShellForm();

    }

}

As you can see, the ICreateShellForm interface has one method CreateShellForm. This method returns a Window control.

The two classes CreateShellLogoTop and CreateShellLogoBottom actually create the forms. Here is an example of the CreateShellLogoTop code,

Listing 10: The CreateShellLogoTop Class.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using Microsoft.Practices.Unity;

using Microsoft.Practices.Prism.UnityExtensions;

using PRISM4.MAIN.FORMS;

namespace PRISM4.MAIN.CLASSES

{

    public class CreateShellLogoTop : ICreateShellForm

    {

        private Window Shell;

        public CreateShellLogoTop(ShellLogoTop Shell)

        {

            if (Shell != null)

            {

                this.Shell = Shell;

                CreateShellForm();

            }

        }       

        public Window CreateShellForm()

        {

            Shell.Show();

            return Shell;

        }

    }

}

The class of course implements ICreateShellForm. The interesting code is the constructor of the class. Notice that a type of ShellLogoTop is passed to the constructor. Constructor injection is being used to inject the correct window type into the class. Now what this means to us is that the only difference between the ShellLogoTop and ShellLogoBottom class is the valut thats being passed to the constructor.

If we go back and look at the CreateShellForm Method in the bootstrapper, you may notice that neither of the two constructors pass a type. In fact one of the constructors passes no value at all!

Listing 11: The Main Bootstrapper CreateShell Method.

private Window CreateShellForm(byte ShellSelector)

{

   if (ShellSelector == 0)

   {              

      var ShellConverter = Container.Resolve<ICreateShellForm>();

      return ShellForm = ShellConverter.CreateShellForm();

   }

   else

   {               

      var ShellConverter = Container.Resolve<ICreateShellForm>("LogoBottom");

      return ShellForm = ShellConverter.CreateShellForm();

   }

}

So, what's going on? To understand how this code works we need to take a look at the CreateServices Method.

The CreateServices Method:

The CreateServices method is used to register services with the Unity DIC. Once these services are registered the container can then resolve the entities. When we talk about resolving entities in Unity we mean Instantiate.

Listing 12 shows a partial view of the CreateServices Method.

Listing 12: The Main Bootstrapper CreateServices ICreateShellForm Code.

private void CreateServices()

{

  ...

  //Setup the Strategy Design Pattern for the shell form:

  Container.RegisterType<ICreateShellForm,

  CreateShellLogoTop>();

   Container.RegisterType<ICreateShellForm,

   CreateShellLogoBottom>("LogoBottom");

   ...

}

Each line of code uses the DIC to register types of ICreateShellForm. The first line registers a concrete entity of type CreateShellLogoTop. The second line registers a concrete entity of type CreateShellLogoBottom. Each of the concrete types corresponds to the two classes that were created in conjunction with the ICreateShellForm interface.

If you look closely at the code you'll see that the two lines of code are not identical. The first line passes no value to the container's RegisterType method. In the case of the second line of code, the "LogoBottom" string is passed. Let's talk about why we do things in this manner.

If we look at the strategy design pattern we see that the intent of the pattern is to allow for extensibility in code. In other words we want to make it as easy as possible to add new shell forms to our solution. We also want to adhere to the SOLID Open / Closed principal. We want our code to be open for extensibility and closed to modification.

So, why the different code? When we register a single concrete class that implements an interface with Unity, that object is associated with the interface. So when the interface is resolved, Unity knows to use the associated concrete class. 

But what is the case when multiple concrete objects are implemented with a single interface? If we were to create say three objects using the first line of code in Listing 12, only the last object registered would be resolved by Unity. The first two registered objects would be discarded.

So, how do we resolve multiple entities that use the same interface? We have two choices, the first choice is to make one entity the default entity by leaving the RegisterType name argument blank. Each additional entity that is associated with the interface or abstract class would pass a unique name to RegisterType method. Listing 12 shows an example of a default and named shell form that uses the same interface. The ShellFormTop window is the default entity, a name is not passed to the method. The ShellFormBottom window on the other hand does pass a name to the method (LogoBottom). This unique name differentiates the default logo top entity from the logo bottom entity,  

The second method of registering multiple concrete entities with a single abstraction is to name each entity that is registered.   

Note: Keep in mind that if you name all entities that use the same interface, there is no default entity and if you try to resolve a no argument entity Unity will raise an exception.

Now it becomes clear why in the first case in the CreateShellForm method we pass no name, while the second line of code passes the "LogoBottom" instance name.

Later we'll see how to resolve named instances in code when they do not reside in the bootstrapper.

You may find it interesting that the CreateServices method is the only code in the solution that registers entities with the Unity DIC. In fact, the only place where we explicitly resolve entities is in the CreateShellForm method. We'll go into details about why we do things this way later.

The last thing that we do in the CreateShell method is to assign the returned window to the class level member and return the window from the method.

The Bootstrapper CreateModuleCatalog Method:

The CreateModuleCatalog method is used to load modules at runtime. There are a number of methods that can be used to load modules with Prism 4. In this solution we use the configuration file (App.config) to load modules. Here is the code for the bootstrapper CreateModuleCatalog method in the Virtual Calculator solution.

Listing 13: The Main Bootstrapper CreateModuleCatalog Method.

protected override IModuleCatalog CreateModuleCatalog()

{

  ConfigurationModuleCatalog configurationCatalog = new ConfigurationModuleCatalog();

  return configurationCatalog;

}

In this case we simply Instantiate the class and return it.

We will defer going into more detail about modules in this chapter, chapter 9 is dedicated to this subject.

The Bootstrapper ConfigureRegionAdapterMappings Method:

The ConfigureRegionAdapterMappings method is used to add Region Adapters to the Prism 4 RegionAdapterMappings class. Here is an example of the method from the Virtual Calculator solution.

 Listing 14: The Main Bootstrapper ConfigureRegionAdapterMappings Method.

protected override RegionAdapterMappings ConfigureRegionAdapterMappings()

{

   RegionAdapterMappings mappings = base.ConfigureRegionAdapterMappings();

     if (mappings != null)

     {

        mappings.RegisterMapping(typeof(TabControlExt),

        this.Container.Resolve<SyncfusionTabCtrlRegionAdapter>());

     }

    return mappings;

}

We will defer going into more detail about regions and region adapters in this chapter, chapter 8 is dedicated to this subject.

The Composition Root:

The composition root of a solution is the point where program execution starts. The composition root varies depending on the type of solution that is being built. In WPF solutions the default composition root is located in the App.xaml file. You'll recall that we changed where the solution started in the Hello World solution from the App.xaml to the App.xaml.cs file. In Microsoft Prism 4 solutions this is where the composition root resides. For our purposes this is not exactly true.

You may be wondering why I'm suddenly talking about the composition root and how it relates to Prism 4. Well its actually quite important when working with Prism 4 and Dependency Injection.

One issue that comes up when working with DICs is that once you choose a DIC, your solution is tightly coupled to that container. You may have noticed that any tight coupling when it comes to programming is considered a bad practice! If we add DIC code throughout our solutions, it becomes difficult to change DICs. In other words when we commit to a DIC, the syntax that we use is coupled to that container and if it is used throughout the solution, it's very difficult to change DICs. How can we reduce the impact of using a DIC in our solutions?

That's where the Composition root comes into play. If you look at all of the code in the Virtual Calculator solution you'll find that there is not one place outside of the bootstrapper where Unity code is used.

So, why is this important? When the DIC code is restricted to the composition root, your solution comes as close as possible to being DIC agnostic. If you remember earlier when I said that the App.xaml.cs file is not exactly the composition root for our purposes, this is why. The bootstrapper class in Prism 4 solutions is considered to be the composition root because it is where the DIC is created. 

Now what are the advantages to using the composition root for all of our DIC code.

  • All DIC Code is in one place. If changes are necessary for the DIC you know where to go.
  • If for some reason the DIC needs to be changed, all of the changes can be done in the composition root. The solution only knows that constructor, property, or method injection is being used to resolve entities.
  • Specific DIC code syntax is limited to the composition root.

In the bootstrapper class of the Virtual Calculator, the CreateServices method is used to register services. here is the full code for that method:

Listing 15: The Main Bootstrapper CreateServices Method.

private void CreateServices()

        {

            Container.RegisterType<IValidateInteger,

                Validate32BitSignedInteger>();

            Container.RegisterType<IValidateInteger,

                Validate64BitSignedInteger>("IntegerLong");

            Container.RegisterType<IntegerValidationResult>();

            //Setup the Strategy Design Pattern for the shell form:

            Container.RegisterType<ICreateShellForm,

                CreateShellLogoTop>();

            Container.RegisterType<ICreateShellForm,

                CreateShellLogoBottom>("LogoBottom");

            Container.RegisterType<ICalculatorExceptionController,

                CalculatorExceptionController>

                (new ContainerControlledLifetimeManager());

          

            Container.RegisterType<ExceptionResult>();           

            Container.RegisterType<IStatus,

                OkStatus>();

            Container.RegisterType<IStatus,

                CalculatingStatus>("CalculateStatus");

            Container.RegisterType<IFormula,

                AddFormula>();

            Container.RegisterType<IFormula,

                SubtractFormula>("SubtractFormula");

            Container.RegisterType<IConvertInteger,

                ConvertInteger>();

            Container.RegisterType<ICalculate,

                AddIntegers>();

            Container.RegisterType<ICalculate,

                SubtractIntegers>("Subtract");

            Container.RegisterType<IDescription,

                Description>();           

            Container.RegisterType<IUpdateUIState,

                TextboxOneAndTwoBlankOrClearState>();

            Container.RegisterType<IUpdateUIState,

                TextboxOneExceptionState>

                ("TextBoxOneException");      

    

            Container.RegisterType<IUpdateUIState,

                TextboxTwoExceptionState>

                ("TextBoxTwoException");

            Container.RegisterType<IUpdateUIState,

                TextboxOneAndTwoExceptionState>

                ("TextBoxOneAndTwoException");

            Container.RegisterType<IUpdateUIState,

                TextboxOneHasValueState>

                ("TextBoxOneHasValue");  

        

            Container.RegisterType<IUpdateUIState,

                TextboxOneAndTwoHasValueState>

                ("TextBoxOneAndTwoHaveValues");

            Container.RegisterType<UpdateUserInterface>();

            Container.RegisterType<UpdateSubtractionUserInterface>();   

            Container.RegisterType<Signed32BitIntegerConversionResult>();

            Container.RegisterType<Signed64BitIntegerConversionResult>();

            Container.RegisterType<IDescription,

                Description>();

            Container.RegisterType<DescriptionResult>();

        }

Without the Prism 4 bootstrapper class it would be necessary to resort to calling forms from the App.xaml file or writing initialization code from scratch. The bootstrapper exposes a number of methods that can be used to configure Prism 4 solutions at runtime.

So, What's Next?

In this chapter we spoke about DI and the Prism 4 bootstrapper class. We talked about the different DICs and looked in detail at the Unity DIC. We talked about why DI and DICs are important and looked at how DICs are integrated into Prism 4 bootstrapper classes. We saw how to configure a DIC when using the strategy design pattern and learned that we have options when doing so.

We also spoke about the composition root and why it is important when using DICs. We also spoke briefly about the different kinds of injection types that are used to resolve entities and why this method of entity resolution is desired.

In the next chapter we'll take a look at the Prism 4 shell form and get our first detailed look at XAML markup.


Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.