Total votes: 3
Category: Design Patterns
Print: Print Article
Please login to rate or to leave a comment.
Published: 30 Jul 2007
Download Sample Code
Since the previous article didn't show much of the features offered by Castle Windsor Container, I will resume the previous discussion extending the requirements of the former example to show how IoC deals with changes and what is its real potential.
In the previous article I introduced the concepts of Inversion of Control and Dependency Injection, and showed how to benefit from their use when developing a simple application. Although that naive example didn't take advantage of IoC and DI as much as a real life application would, it was meaningful in order to let developers new to these concepts start thinking in the right direction.
Inversion of Control/Dependency Injection Series
IOC/DI - Part I This article introduces Inversion of Control/Dependency Injection in a simple and affordable fashion, with a real example which evolves step by step to take advantage from IoC and DI, leveraging the features offered by an open source framework called Castle Project.
IOC/DI - Part II In the previous article I introduced the concepts of Inversion of Control and Dependency Injection, and showed how to benefit from their use when developing a simple application. In this article I will resume the previous discussion extending the requirements of the former example to show how IoC deals with changes and what is its real potential.
IoC/DI - Part III In this article I conclude the discussion about the core features of Windsor
Container while evolving the simple example that accompanied you through the whole series of these articles. The
next article will tackle more advanced topics.
IoC/DI - Part IV In this article I introduce the missing core features I didn't tackle before. They require a little more knowledge of Windsor, which I hope I've been able to hand down so far.
In the previous article I didn't show much of the features offered by Windsor Container. This time I'm going to introduce small incremental changes to the requirements of the sample application to show how Windsor can deal with them.
So far, you've seen how you can instruct the container to retrieve and instantiate components, as well as resolve dependencies on the constructor. Here's what the signature of the constructor of the
HtmlTitleRetriever class looked like:
HtmlTitleRetriever class had dependencies on two references to objects implementing
ITitleScraper interfaces (services) to be satisfied in order to be instantiated. With a canonical approach, you have to create these references and then supply them to the constructor. By using Windsor you could use the configuration file and resolve them in the following way:
Constructor injection and compulsory dependencies
When an instance of the
HtmlTitleRetriever class was required using the snippet above, the container was able to infer that, in order to instantiate the class, it needed to supply its dependencies to the constructor. The instantiation was successful because those dependencies were satisfied by the other two components registered in the configuration file. If just one of them wasn't registered, the container wouldn't have been able to resolve them and would have thrown a
As you may guess, the dependencies on the constructor are compulsory, because you can't instantiate an object if you don't supply all of them. The operation of resolving and supplying constructor dependencies is called constructor injection in terms of IoC, and it's one of two ways of supplying dependencies to components.
You should rely on constructor injection whenever it makes sense for a component to compulsorily require a dependency in order to work. In other cases, you might want to provide a default implementation for a service or a general dependency, thus making it optional. This concept will make sense shortly.
Setter injection and optional dependencies
In order to illustrate how to deal with optional dependencies, let's make a small change in the requirements of the sample application. The
GetTitle method of the
HtmlTitleRetriever class should return a string containing the title of the HTML document supplied as input parameter (as before); but now prefixed by a descriptive message, which can be a custom or a default one. You can think of satisfying this requirement by introducing a property called
AdditionalMessage with a backing field whose value defaults to
Title:, which can be changed using the setter of the property. The changes are shown in the following snippet:
Of course this change in the code of the class doesn't require any modifications to the configuration file of the container. The application will work fine since if no value is provided, the getter of the property will return the value set on the backing field during instantiation.
Now, what if you want to change the default message returned by the
GetTitle method along with the title of the document? Remember, the responsibility to instantiate the
HtmlTitleRetriever class is no longer yours, but the container's.
For this and other purposes Windsor offers a lot of configuration options, which I will try to illustrate in the remainder of this article and in the next one.
Going back to the new requirement, you want to be able to supply a different value for the
AdditionalMessage property; other than the default value hard coded in the class. This can be accomplished via configuration parameters for components, which can be specified in the configuration file.
The snippet below shows how the configuration for the
HtmlTitleRetriever component changes to satisfy the requirement, by setting the
AdditionalMessage property to
Notice the syntax used to specify the value of the property. Inside the component element you have inserted a child element called
parameters, whose child is another element with the same name as the property you want to set. The mechanism of specifying dependencies by using properties is called setter injection.
Differently from constructor injection, setter injection has to do with optional dependencies, since the only constrain which needs to be satisfied when instantiating an object is that all the parameters accepted by its constructor must be supplied. Optional dependencies, instead, don't prevent the container from instantiating the component. They are usually assigned a default value which can be changed by specifying a new value in the configuration.
Another thing to note is that the syntax used above in the configuration file is valid for both setter and constructor injection. In this case, the constructor of the
HtmlTitleRetriever class can be resolved automatically by the container because those are dependencies on other components registered in the configuration file. In case I make the dependency on the
AdditionalMessage property compulsory by modifying the constructor and adding a third parameter of type string called
additionalMessage, the syntax of the configuration file would be the same as above (the
AdditionalMessage element in the xml file should be
additionalMessage for coherence, to reflect the name of the parameter, but the container is case insensitive, so you can even write it all lowercase), with the only difference that this time the dependency would be compulsory. If not provided in the configuration file, an exception would be thrown by the container.
Back to setter injection. Upon component request, Windsor realizes that you have specified a configuration parameter which maps to a property of the class endowed with a setter (hence setter injection) and thus assigns to the property the value you specified after an instance is created. Remember: If no value is specified in the configuration file, no operation would be performed by the container on the property, and the backing field would keep its default value. Therefore, to avoid incurring in null references or incoherent values, always give a default value to optional dependencies.
Now on to something more interesting. While reading the last paragraph, you may have noticed the difference between the string parameter/property dependency-that you could specify by giving it a value in the configuration file-and the dependencies on other components, like the ones the
HtmlTitleRetriever class has on the
ITitleScraper services. Suppose you need to retrieve files via the FTP protocol instead of HTTP. You'd need to create another class implementing the
IFileDownloader interface and register it in the configuration file as a new component. Let's see how it's done:
Now you might be asking: how do I switch from one implementation to the other? There's obviously a way to explicitly specify a particular component. In case of no explicit configuration and multiple components implementing the same service, Windsor should choose the first component registered in the configuration file.
I said should because I noticed that there's a little subtlety (read, issue) that needs to be taken into account. At the time of writing, it looks like the expected first registered-first chosen behavior can be achieved only as long as the IDs of the components stay below the 8 characters in length. Otherwise, the choice seems unpredictable.
This is a good reason to show you how to explicitly switch implementations at runtime using Windsor configuration. The syntax to accomplish this task differs from the one used to specify dependencies on explicit values like strings, numbers, dates and so on. Otherwise, the container would be unable to infer what you want to do. The syntax used to specify components as parameters uses the
id} format. Let's see an example. Having registered the
FtpFileDownloader component, you can choose to use it when resolving the
HtmlTitleRetriever class by simply adding a new configuration parameter to the
HtmlTitleRetriever component, as shown in the following snippet.
Notice how the new syntax is inserted in the parameters section just like you did before with a simple string parameter. Now you can switch between the two implementations of the
IFileDownloader service just by referencing their IDs. The xml item is called downloader because it matches the name of the constructor parameter, like you did before with the
Working with arrays, lists and dictionaries
At the moment the
HtmlTitleRetriever class is not very useful when it comes to downloading files with different protocols or stored in different locations. Each time you'd have to change the configuration file to reference a specific component for that protocol. Let's try resolving this issue.
Note: actually, the WebClient class is able to retrieve files via FTP, so there would be no real need for a new class. The redundant class is implemented for educational purposes only.
HtmlTitleRetriever class should be able to deduce how the file supplied to the
GetTitle method needs to be retrieved. It should be able to retrieve the file if it can rely on a component created for that purpose. In order to do this, let's first change the contract of the
IFileDownloader service to provide a method called
This method will need to be implemented by inheritors to return a Boolean values indicating if they are able to download a file with that specific schema. So here's how the
FtpFileDownloader classes change.
With this trick, each component providing the
IFileDownloader service has knowledge about its capability to download a specific file. You will see shortly why this makes sense.
Going back to our not-very-useful HtmlTitleRetriever class; in order to let it download files with different protocols it needs references to several implementations of the
IFileDownloader service, each for a supported protocol/location. This can be accomplished in several ways; let's see how to supply multiple components using arrays. The constructor of the class now accepts an array of IFileDownloaders, as shown in the following snippet.
The body of the
GetTitle method has changed. Now it iterates through the array of downloaders and checks if it can find one suitable for downloading the file. Once it finds one, it downloads the file and scrapes the title as done before. If no suitable downloader is found, an empty string is returned. So far nothing new, but you need to change the configuration to let Windsor understand that you want the class populated with an array of downloaders. Here's how the configuration file takes advantage of this feature.
The code is pretty simple to understand, so I will not delve deeper into it. As for the parameters element, the array element can accept any parameter-be it a string, Boolean, DateTime or a reference to a component. The only difference is in the syntax used to specify the component, which requires its ID surrounded by brackets and preceded by the dollar
Just like arrays, you can pass lists and dictionaries to constructors and properties. The syntax is similar and is shown in the following snippets. The two snippets below show how to achieve the same result using lists instead of arrays.
The following snippets show how to use dictionaries.
Note that by using dictionaries I could have omitted the
SupportsUriScheme method, since I could have specified the name of the supported protocol as the key of the dictionary entry and then retrieved it by key in the
In this article you've seen how to deal with more sophisticated requirements using Windsor container configuration. In particular, I've talked about optional and compulsory dependencies, and how they map respectively to properties and constructors, as well as how to switch service implementations using a specific syntax offered by Windsor. Finally, I've given a quick overview of how to work with arrays, lists and dictionaries. In the next article I will talk about more configuration options and introduce advanced concepts like decorators and lifestyles.
Sorry, no bio is available
This author has published 10 articles on DotNetSlackers. View other articles or the complete profile here.
Other articles in this category
Introduction to StructureMap
Have you heard of StructureMap, generally know what it’s for, and want to know how to get started qu...
DI Patterns: Constructor Injection
In this article, an excerpt from the book "Dependency Injection in .NET", we will take a detailed lo...
The Command Pattern
In this article I will provide a quick refresher on what the command pattern is used for, how it wor...
Brian Mains discusses how to implement the Arrange-Act-Assert pattern in TypeMock.
Key Process Patterns
This article, based on chapter 2 of Specification by Example, presents effective patterns for softwa...
Please login to rate or to leave a comment.