Chapter 12. Spring.NET

Menu

  • Introducing Spring.NET
  • Managing lifetime
  • Working with multiple components
  • Configuring difficult APIs

In the previous chapters, you saw how to map the principles and patterns from parts 13 to Castle Windsor and StructureMap. In this chapter, we’ll do the same with the Spring.NET DI CONTAINER.

Together with Castle Windsor and StructureMap, Spring.NET belongs to the set of “first generation” DI CONTAINERS on .NET. It appeared in 2006, and even today it still offers basic support for .NET 1.1. It’s a port of the Java version of the Spring Framework, which is a big and comprehensive application framework that addresses many different aspects of software—not only OBJECT COMPOSITION. The DI CONTAINER is one of the many components available in the framework, but it can perfectly well be used as a stand-alone component without the need to reference any of the other Spring.NET components.

In this chapter, we’ll focus on the Spring.NET DI CONTAINER while ignoring the rest of the application framework. As in the previous chapters and in those to follow, we’ll examine how Spring.NET can be used to apply the principles and patterns set out in parts 13. Figure 12.1 shows the structure of the chapter.

Figure 12.1. This chapter is divided into four sections. The first section introduces the Spring.NET container API and should be considered a prerequisite for the next three sections. Each of these can be read independently of each other.

The first section provides an overall introduction to Spring.NET and demonstrates how to configure and resolve objects. The next three sections each deal with usage patterns that require a bit of extra attention; you can read them all in order, or you can skip some and read only the ones that interest you.

This chapter should enable you to get started, as well as deal with the most common issues that may come up as you use Spring.NET on a daily basis. It isn’t a complete treatment of Spring.NET—that would take several more chapters or perhaps a whole book in itself. In any case, the entire Spring.NET framework is beyond the scope of this book—only the Spring.NET DI CONTAINER pertains to the topic at hand, so when I use the name Spring.NET, I am specifically referring to the container.

You can read the chapter in isolation from the rest of part 4 to learn specifically about Spring.NET, or you can read it together with the other chapters in part 4 to compare DI CONTAINERS. The focus of this chapter is to show how Spring.NET relates to and implements the patterns and principles described in parts 13.

12.1. Introducing Spring.NET

In this section, you’ll learn where to get Spring.NET, what you get, and how you start using it. You’ll also look at common configuration options. Table 12.1 provides fundamental information that you’re likely to need to get started.

Table 12.1. Spring.NET at a glance

Question

Answer

Where do I get it? Go to www.springframework.net/download.html and download the latest release. From Visual Studio 2010 you can also get it via NuGet. The package name is Spring.Core unless you also want the INTERCEPTION features—in that case, you need the Spring.Aop package.
What’s in the download? A .zip file that contains everything you need: compiled binaries, the source code, example code and documentation.
Which platforms are supported? All .NET versions from .NET 1.1 are supported, although future versions will target only .NET 2.0 and above.
How much does it cost? Nothing. It’s open source.
Where can I get help? You can get commercial support from SpringSource, which is the organization behind Spring.NET. Other than commercial support, Spring.NET is still open source software with a thriving ecosystem, so you’re also likely (but not guaranteed) to get help in the official forum at http://forum.springframework.net.
On which version is this chapter based? 1.3.1.

Using the Spring.NET DI CONTAINER is a three-step process, as illustrated by figure 12.2.

Figure 12.2. The overall usage pattern of Spring.NET involves three steps: first, we define how objects are configured and composed in an XML file. Second, we load that XML configuration into a container instance. In the third and final step, we can resolve objects from the container instance.

When you’re done with this section, you should have a good feeling for the overall usage pattern of Spring.NET, and you should be able to start using it in well-behaved scenarios where all components follow proper DI patterns, such as CONSTRUCTOR INJECTION. We’ll start with the simplest scenario and see how to resolve objects using a Spring.NET container.

12.1.1. Resolving objects

The core service of any DI CONTAINER is to compose object graphs, and Spring.NET is no exception. Because it’s such a central feature, it’s the most natural place to start when introducing the API, so this is what I’ll do here.

In the previous chapters about Castle Windsor and StructureMap, you saw how those DI CONTAINERS take different approaches to whether it’s necessary to configure components before we can resolve them. Castle Windsor requires us to explicitly configure every single component, whereas StructureMap can work with concrete types without configuration. But both of these DI CONTAINERS, as well as all of the DI CONTAINERS we’ll cover in the next chapters, operate on types: we ask the container to resolve a type for us.

Spring.NET is different because its core query mechanism isn’t based on types, but on names. Instead of requesting a particular type, we ask Spring.NET for a named object. Similar to Castle Windsor, all objects must be configured before they can be served.

Configuration for Spring.NET is done in XML, so even the simplest scenario involves a piece of XML and some .NET code. As an example, to resolve the concrete SauceBéarnaise class, you must first define the object in XML configuration:

<objects xmlns="http://www.springframework.net">
  <object id="Sauce"
          type="Ploeh.Samples.MenuModel.SauceBéarnaise,
          Ploeh.Samples.MenuModel" />
</objects>

In Spring.NET, every configured object must appear in an object element. The element may have an id attribute that names the object, as well as a type attribute that defines the .NET type of the object. The name is used when you wish to resolve the object.

To resolve a SauceBéarnaise instance, you must load the XML configuration into a container instance. Using an XmlApplicationContext, you can load XML from several different sources, including embedded resources and the application configuration file; but this example uses a stand-alone XML file named sauce.xml:

var context = new XmlApplicationContext("sauce.xml");
SauceBéarnaise sauce = (SauceBéarnaise)context.GetObject("Sauce");

To resolve a SauceBéarnaise instance, you invoke the GetObject method with the Sauce ID you provided for the object in the XML configuration. The ID can be any string, but Spring.NET recommends Pascal casing as a naming convention.

Because the GetObject method returns a weakly typed System.Object instance, you need to cast the return value to the expected type in order to use it.

Notice how Spring.NET doesn’t explicitly distinguish between concrete and abstract types. Whereas other DI CONTAINERS require us to provide a mapping from ABSTRACTIONS to concrete types, Spring.NET is exclusively based on mappings from names to concrete types. As this chapter will demonstrate, Spring.NET is still able to resolve requests for ABSTRACTIONS into concrete instances, but the mechanism is more implicit than what other DI CONTAINERS use.

The GetObject method is defined by the IObjectFactory interface, which is one of the fundamental interfaces defined by Spring.NET. As the name implies, it focuses on creating objects, and it contains no methods that enable us to configure the container. Rather, this is the responsibility of higher-level types like the XmlApplicationContext.

The GetObject method is one among several that we can use to resolve objects. However, because all of them are weakly typed, we must always explicitly cast the return value to the type upon which we wish to work. With the GetObject method, we can only request objects based on names instead of types, so how do we address situations where a type is all we have?

Resolving type requests

Sometimes we don’t have a name, but rather a Type instance that we need to resolve to an instance of that type. You saw an example of that in section 7.2, where we discussed ASP.NET MVC’s DefaultControllerFactory class. The relevant method is this one:

protected internal virtual IController GetControllerInstance(
    RequestContext requestContext, Type controllerType);

Given only a type instead of a name, we might be tempted to define and maintain an explicit map of types to names, but that would be redundant work. A slightly better option would be to use a naming convention that enables us to deterministically derive a name from a Type instance. But the IListableObjectFactory interface, which derives directly from IObjectFactory, defines a method called GetObjectsOfType that can be used to get all objects that match a given type. Assuming that the requested controllerType is unique in the Spring.NET configuration, you can implement the GetControllerInstance method like this:

IDictionary controllers =
    this.context.GetObjectsOfType(controllerType);
return controllers.Values.OfType<IController>().Single();

The context field is an instance of IListableObjectFactory that you can query for all objects that match the controllerType. Although you get back a dictionary, you care only about the values, and you expect that each requested controller will be unique in the underlying XML configuration.

Although Spring.NET doesn’t provide any generic APIs, you can easily encapsulate the previous query into an extension method:

public static T Resolve<T>(this IListableObjectFactory factory)
{
    return factory.GetObjectsOfType(typeof(T))
        .Values.OfType<T>().Single();
}

This would enable you to resolve a type like this:

SauceBéarnaise sauce = context.Resolve<SauceBéarnaise>();

The GetObjectsOfType method returns all configured objects that match the requested type. Because SauceBéarnaise implements the IIngredient interface, you can also resolve IIngredient from the context:

IIngredient ingredient = context.Resolve<IIngredient>();

A typical ASP.NET Controller, and any other application code that we’re likely to write, will have a complex hierarchy of DEPENDENCIES. To enable Spring.NET to compose objects from loosely coupled services, we must provide proper configuration.

12.1.2. Configuring the container

As we discussed in section 3.2, there are several conceptually different ways you can configure a DI CONTAINER. Figure 12.3 reviews the options and how Spring.NET fits in.

Figure 12.3. Spring.NET mainly supports XML configuration out of the three possible options outlined in chapter 3. CODE AS CONFIGURATION is only marginally supported and AUTO-REGISTRATION isn’t available at all, so these options are shown in grey.

Like other DI CONTAINERS with a long history, Spring.NET started out with XML as the major configuration source, but contrary to the evolution of both Castle Windsor and StructureMap, Spring.NET has remained focused on XML—perhaps because of its strong ties to the Java Spring framework.

 

CODE AS CONFIGURATION with Spring.NET

When I wrote this chapter, Spring.NET didn’t have support for CODE AS CONFIGURATION. However, literally days before I turned in the final manuscript for the book, SpringSource released Spring CodeConfig, which provides CODE AS CONFIGURATION support for Spring.NET.

Unfortunately, this happened so late that I didn’t have time to rewrite the chapter.

 

In this chapter, the focus will be exclusively on XML configuration.

Working with .NET types in XML

Spring.NET works on configuration based on XML. That XML can come from a variety of sources. Most of the time, we’ll be loading XML from a file.

In section 12.1.1, you already saw a simple example of Spring.NET’s XML configuration:

<objects xmlns="http://www.springframework.net">
  <object id="Sauce"
          type="Ploeh.Samples.MenuModel.SauceBéarnaise,
          Ploeh.Samples.MenuModel" />
</objects>

It’s no secret that XML is a verbose language in itself, but when it comes to identifying .NET types, it becomes extra verbose. To properly identify a .NET type by a string, we must resort to assembly qualified names. Even in the cases where we can omit Culture, Version, and PublicKeyToken, the type will often be identified by a long string with a lot of repeated information. This hurts both readability and maintainability.

Readability is impacted because the relevant part of the type name (Sauce-Béarnaise) is buried between a namespace and an assembly name. Maintainability suffers because it becomes harder to rename namespaces or assemblies. Every time we rename anything, we must edit a potentially large set of type definitions.

Granted, these issues apply to all frameworks where types must be defined as XML, but this is also the reason why all other DI CONTAINERS have moved on to other ways of configuring the container. This is also the reason why I generally recommend against XML configuration unless it’s mandated by the usage scenario. However, when it comes to Spring.NET, XML is the most prevalent option.

To make it easier to work with .NET types in XML, SpringSource provides tools such as XML schemas and a Visual Studio add-in with type and property completion. The framework itself also enables us to define a set of type aliases, which are shorthand names that we can define for types. This is also done in XML. The type alias for the SauceBéarnaise class might look like this:

<alias name="SauceBéarnaise"
       type="Ploeh.Samples.MenuModel.SauceBéarnaise,
       Ploeh.Samples.MenuModel" />

The name can be anything, but I find it most intuitive and easy to remember to pick the simple name of the type as the name of the alias.

This type alias enables us to rewrite the previous example, like this:

<object id="Sauce" type="SauceBéarnaise" />

This feature can be particularly helpful when we need to refer to the same type multiple times in the same XML file; in any case, it makes the configuration much more readable. In the rest of this chapter, I’ll use type aliases. With this notation, the object element begins to look like what it is: a map from a name to a concrete type.

In this simple form, this is all the object element does. When the objects have DEPENDENCIES, you must tell Spring.NET how to resolve them.

Explicitly configuring dependencies

The SauceBéarnaise class is easy to create because it has a default constructor; no DI CONTAINERS need a lot of help to create such types. This changes when there’s no default constructor. As an example, consider this Mayonnaise constructor:

public Mayonnaise(EggYolk eggYolk, OliveOil oil)

Although the mayonnaise recipe is a bit simplified, both EggYolk and OliveOil are concrete classes with default constructors. However, because the Mayonnaise class has no default constructor, you must tell Spring.NET how to resolve it. One option is to explicitly wire the types together:

<object id="EggYolk" type="EggYolk" />
<object id="OliveOil" type="OliveOil" />
<object id="Mayonnaise" type="Mayonnaise">
  <constructor-arg ref="EggYolk" />
  <constructor-arg ref="OliveOil" />
</object>

The EggYolk and OliveOil types are configured the way you saw previously, but the Mayonnaise element now contains two constructor-arg elements. Each of those elements references a named object in order to define the parameters for the Mayonnaise constructor. The ref attribute identifies another configured object by name, so the EggYolk reference refers to the EggYolk name—not directly to the EggYolk type.

In the previous example, the order of the constructor-arg elements is important because you didn’t explicitly refer to the parameter names; that’s also possible.

Whereas we can always explicitly configure DEPENDENCIES in this way, we don’t gain the benefits that AUTO-WIRING can provide. Contrary to other DI CONTAINERS, with Spring.NET we must explicitly ask it to use AUTO-WIRING, and even so it only works in certain cases.

Auto-wiring dependencies

Spring.NET supports limited AUTO-WIRING, but we must explicitly turn it on using an XML attribute. Instead of the explicitly wired Mayonnaise specified previously, you could’ve configured it like this:

<object id="EggYolk" type="EggYolk" />
<object id="OliveOil" type="OliveOil" />
<object id="Mayonnaise" type="Mayonnaise"
        autowire="autodetect" />

The optional autowire attribute can be used to turn on AUTO-WIRING for a given object. In this example, we use the autodetect value which tells Spring.NET to figure out exactly how matching objects are found. Other available options enable us to indicate that matching objects should be found by name, type, or other means.

If we expect to use AUTO-WIRING for all objects, we can enable it for an entire block of configured objects instead of writing out the autowire attribute for each and every object element:

<objects xmlns="http://www.springframework.net"
         default-autowire="autodetect">
  <object id="EggYolk" type="EggYolk" />
  <object id="OliveOil" type="OliveOil" />
  <object id="Mayonnaise" type="Mayonnaise" />
</objects>

The default-autowire attribute defines a default AUTO-WIRING strategy for all objects within the objects element. This is a much easier way to turn on AUTO-WIRING once and for all—but you should be aware that it won’t always work.

The support for AUTO-WIRING in Spring.NET relies on uniqueness. For the Mayonnaise class, Spring.NET examines the constructor and determines that it needs instances of EggYolk and OliveOil. To satisfy the EggYolk DEPENDENCY, it searches through all other configured elements to find one that can satisfy that requirement (and it does the same for the OliveOil DEPENDENCY).

In the previous example, there’s only one object that satisfies the EggYolk DEPENDENCY, so there’s no ambiguity. However, had there been more than one object that could satisfy the requirement, an exception would have been thrown. That goes for both concrete EggYolk elements, but also any derived types.

 

Note

In Spring.NET, AUTO-WIRING only works when the DEPENDENCIES can be uniquely resolved. This is different from other DI CONTAINERS.

 

The advantage of requiring distinctness to support AUTO-WIRING is that the contract with the container is clear and explicit. AUTO-WIRING is only possible when there’s no ambiguity regarding resolved types, so the risk of misconfiguration is much smaller. On the other hand, this design makes it harder to work with multiple objects that implement the same ABSTRACTION.

We’ve looked at some basic configuration options for Spring.NET. Although it’s certainly possible to write one big block of unstructured XML, it’s better to modularize configuration. Spring.NET supports this by enabling XML to be loaded from more than one source.

12.1.3. Loading XML

It’s sometimes desirable to package configuration into reusable groups; and even when reuse itself isn’t our top priority, we may want to provide a bit of structure if we have a big and complex application to configure.

With Spring.NET, we can package configuration into separate XML elements that are defined in different resources. Table 12.2 lists the supported resource types. They’re easy to use, but I’ll briefly discuss each of them to give you an impression.

Table 12.2. XML resource types

Resource type

Uri syntax

Description

FileSystemResource file://<filename> The file:// moniker is optional. XML configuration is defined in files.
ConfigSectionResource config://<path to section> XML configuration is defined in the application configuration file.
UriResource Standard .NET URI syntax is supported. XML configuration is read from standard System.Uri protocols, such as HTTP and HTTPS.
AssemblyResource assembly://<AssemblyName>/
<NameSpace>/<ResourceName>
XML configuration is embedded in an assembly.
InputStreamResource Not supported. XML configuration is read from a System.IO.Stream.

Some of the resource types support URI syntax, where we can use a moniker to indicate the resource type as part of a string-encoded address. If no moniker is supplied, the resource is assumed to be a file.

Using XML files

So far, you’ve only seen examples of loading XML configuration from a single file. This example loads the entire configuration from the file sauce.xml:

var context = new XmlApplicationContext("sauce.xml");

Because no explicit path information is given, the sauce.xml file is assumed to be located in the working folder of the running process. A full path can also be used.

In this example, no moniker was supplied so Spring.NET defaults to the FileSystemResource. Alternatively, you could’ve chosen to explicitly use the file://moniker like this:

var context = new XmlApplicationContext("file://sauce.xml");

This is equivalent to the previous example. It’s often intuitive to work with XML as files, so in most cases it makes sense to dispense with the file:// moniker and instead write the file path directly.

In addition to defining XML configuration in text files, we can also integrate it in the standard application configuration file.

Using application configuration files

If we prefer to integrate Spring.NET configuration with the rest of the application’s configuration, we can also use the standard .NET application .config file.

Because the .NET application configuration system expects custom configuration sections to be explicitly registered, we must also register Spring.NET’s configuration sections when we wish to use the .config file. There are various configuration sections that you can register, but to use the objects element you’ve been using so far, it’s necessary to register Spring.NET’s default section handler:

<configSections>
  <sectionGroup name="spring">
    <section name="objects"
             type="Spring.Context.Support.DefaultSectionHandler,
             Spring.Core" />
  </sectionGroup>
</configSections>

This enables you to define objects directly in the .config file, as you’ve previously been doing in stand-alone XML files:

<spring>
  <objects xmlns="http://www.springframework.net">
    <object id="Sauce" type="SauceBéarnaise" />
  </objects>
</spring>

Using the config:// moniker, you can now load the Spring.NET configuration from the .config file into an XmlApplicationContext instance, like this:

var context = new XmlApplicationContext("config://spring/objects");

The context instance can now safely resolve the Sauce name.

In many ways, integrating Spring.NET configuration into the standard .NET application configuration file format is a special case of using an XML file, because .config files are also XML files; but we can also view files as a special case of XML loaded from any URI.

Loading XML from URIs

When we load XML from files, we use the file:// moniker as we would a URI scheme delimiter. Spring.NET can download XML files from other URIs than files, such as HTTP, HTTPS, and FTP. It’s a simple as this:

var context = new XmlApplicationContext("http://localhost/sauce.xml");

In this example, the sauce.xml file is hosted by the local machine’s web server, but any publicly available resource can be used.

In all the previous cases we can change the configuration without recompiling the application. This isn’t possible with the next option.

Using embedded resources

In .NET, we can compile resources into assemblies. If we embed XML configuration in an assembly, Spring.NET can load it.

The advantage of embedded XML files is that operations staff can’t accidentally change configuration values when they’re compiled into the assembly. Only files with parameters that might need to be adjusted by operations staff should be exposed outside the assembly on the file system where they can be edited on a deployment-by-deployment basis.

If you embed the sauce.xml file into an assembly, you can load it into an XmlApplicationContext, like this:

var context = new XmlApplicationContext(
    "assembly://Ploeh.Samples.Menu.SpringNet/
    Ploeh.Samples.Menu.SpringNet/sauce.xml");

To load from an embedded resource, we can construct the resource string from the assembly:// moniker, followed by the assembly name, the namespace, and the name of the embedded resource itself. Table 12.2 shows the required format for referencing an embedded resource.

AssemblyResources enable us to load Spring.NET configuration from embedded resources in addition to the externally defined XML files and URIs. If we keep XML configuration in other places, we might need to resort to reading from streams.

Using streams

Until now, we’ve looked at loading XML from static resources such as files, application configuration, web resources, and embedded resources. At times, we need to load XML from other sources, or perhaps we need to dynamically build the XML configuration. One way to do that is to load the configuration directly from a stream.

Because a stream isn’t a static resource, Spring.NET doesn’t support identifying it by a string. We can’t use the XmlApplicationContext class at all but must instead resort to one of Spring.NET’s many other context classes:

var resource = new InputStreamResource(stream, "");
var context = new XmlObjectFactory(resource);

The InputStreamResource serves as an Adapter[1] around a System.IO.Stream object. The stream object contains the XML configuration that you wish to load. We can load the XML into the stream from many different sources, including a string, or by building up the XML model using LINQ to XML. The empty string supplied to the InputStreamResource constructor is a description. We can supply a proper description, but it isn’t required.

1 Erich Gamma et al., Design Patterns: Elements of Reusable Object-Oriented Software (New York: Addison-Wesley, 1994), 139.

Given the resource (or any implementation of IResource), we can now create an instance of XmlObjectFactory. This class offers functionality equivalent to XmlApplicationContext but loads configuration directly from an IResource instance, instead of from strings representing static resources.

The IResource interface is a common interface for all the XML resources we reviewed. We can also provide a custom implementation of IResource and use it in the same way we used the InputStreamResource, or we can register it with its own moniker—but that’s beyond the scope of this chapter.

So far, you’ve seen how to load a single XML configuration from a single resource, but to achieve modularity, we’d often prefer to organize parts of a big application’s configuration in different modules.

Combining XML resources

A big application will require a lot of XML configuration code. To keep the configuration more maintainable, we might want to split it into several smaller documents. Perhaps we even want to keep these in separate places; some in XML files, some in the .config file, and some as embedded resources.

The XmlApplicationContext makes it possible to combine several different resources because it receives each of the resource strings as part of a parameter array. Here’s the signature of the constructor you’ve been using all along:

public XmlApplicationContext(params string[] configurationLocations)

Notice that the configurationLocations parameter is defined as a parameter array. So far, you’ve only been supplying a single resource at a time, like this:

var context = new XmlApplicationContext("sauce.xml");

However, you can supply an arbitrary number of strings to the constructor to combine several resources into a single context:

var context = new XmlApplicationContext(
    "config://spring/objects",
    "meat.xml",
    "file://course.xml");

This example combines three different resources that each defines a piece of the greater whole. Part of the configuration is defined and loaded from the application’s configuration file, while the two other parts are loaded from XML files—one using the implicit syntax for file names and the other explicitly using the file:// moniker. Together, they form a complete set of configuration that defines the XmlApplicationContext.

Another way to combine multiple resources is via the import element in an XML file:

<objects xmlns="http://www.springframework.net">
  <import resource="config://spring/objects" />
  <import resource="meat.xml" />
  <import resource="file://course.xml" />
</objects>

This configuration is identical to the previous example.

As you’ve seen, there are several different ways in which we can load XML configuration into Spring.NET. Because we can load and combine configuration from more than one resource, this gives us a degree of modularity, which we sorely need for maintainability reasons.

But we shouldn’t forget that, overall, XML configuration isn’t the most attractive way to configure a DI CONTAINER. It’s brittle, verbose, and hard to troubleshoot. Until CodeConfig came along, Spring.NET offered few other options.

This section introduced the Spring.NET DI CONTAINER and demonstrated the fundamental mechanics: how to configure the container with XML and subsequently use it to resolve objects. Resolving objects is done with a single call to the GetObject method, so the complexity involves configuring the container. Until now, we’ve only looked at the most basic API; there are more advanced areas we have yet to cover. One of the most important topics is how to manage component lifetime.

12.2. Managing lifetime

In chapter 8, we discussed LIFETIME MANAGEMENT, including the most common conceptual lifetime styles, such as SINGLETON and TRANSIENT. Spring.NET supports a few different lifestyles and enables us to configure the lifetime of all objects. The lifestyles shown in table 12.3 are available as part of the package.

Table 12.3. Spring.NET lifestyles

Name

Comments

Singleton This is the default lifestyle.
Prototype Spring.NET’s name for TRANSIENT. Instances aren’t tracked by the container.
Request Spring.NET’s name for WEB REQUEST CONTEXT. Only valid in the context of a web-aware IApplicationContext.
Session One instance is created per HTTP session. Use with caution. Only valid in the context of a web-aware IApplicationContext.
Application Scopes a single object definition to the lifecycle of a web application. Only valid in the context of a web-aware IApplicationContext.

 

Note

The Spring.Net documentation refers to lifestyles as object scopes.

 

Spring.NET’s implementations of SINGLETON and TRANSIENT are equivalent to the general lifestyles described in chapter 8, so I won’t spend much time on them in this chapter.

 

Note

The default lifestyle in Spring.NET is SINGLETON. This is different from many other containers. As discussed in chapter 8, SINGLETON is the most efficient, although not always the safest, of all object scopes; Spring.NET prioritizes efficiency over safety.

 

The three web-aware scopes (Request, Session, and Application) are all closely coupled with particular IApplicationContexts and don’t work with the XmlApplicationContext or the XmlObjectFactory we’ve been looking at so far. The currently available implementations are so closely coupled to ASP.NET Web Forms that even getting them to work with ASP.NET MVC is difficult. To be frank, it’s a mess and not usable, so we won’t cover the web-aware scopes in this chapter. Expect future versions of Spring.NET to have a more streamlined story in this space.

Here, I’ll show you how to configure object scopes with the SINGLETON and TRANSIENT object scopes. Because Spring.NET doesn’t support custom object scopes, this is going to be a short section. When we’re done, you should be able to use object scopes with Spring.NET.

12.2.1. Configuring object scopes

Object scopes are configured as part of configuring objects in XML.

To configure an object as TRANSIENT you set the singleton attribute to false:

<object id="Sauce" type="SauceBéarnaise" singleton="false" />

Changing the value to true instead configures the object as a SINGLETON:

<object id="Sauce" type="SauceBéarnaise" singleton="true" />

The singleton attribute is optional, and because SINGLETON is the default, omitting it implicitly configures a SINGLETON. This is what you’ve been doing so far in this chapter.

Preventing memory leaks

Like any other DI CONTAINER, Spring.NET creates object graphs. However, it doesn’t track the created objects for us. It may keep track of those objects for its own purposes, but that depends on the object lifetime. As an example, to implement the SINGLETON scope, it must keep a reference to the created instance. On the other hand, the TRANSIENT object scope doesn’t keep track of the objects that Spring.NET creates. As you saw in listings 8.7 and 8.8, object instances are created and returned with no internal tracking. This has some advantages and disadvantages.

Because Spring.NET doesn’t hold on to instances, the risk of inadvertent memory leaks is much smaller. With a container like Castle Windsor, memory leaks are guaranteed if you forget to call the Release method for all resolved object graphs. This isn’t the case with Spring.NET, because objects will automatically be garbage-collected as they go out of scope.

The disadvantage is that disposable objects can’t be deterministically disposed of. Because we can’t explicitly release an object graph, we can’t dispose of any disposable objects. This means that it becomes even more important to wrap disposable APIs in non-disposable services, as discussed in section 6.2.1.

In short, Spring.NET is well behaved and allows objects to be garbage-collected when they go out of scope in our own code—but the requirement is that our own classes must also be as well behaved. Because we can’t rely on the container or the calling code to dispose of any services, we must keep usage of disposable objects within single methods.

This chapter has provided a remarkably short tour of object scopes in Spring.NET; there isn’t a lot to say. The only universally available object scopes are SINGLETON and TRANSIENT, whereas a couple of other scopes rely on particular implementations of IApplicationContext. When we configure objects, we can configure some as SINGLETONS and some as TRANSIENTS, and this is even true if we configure multiple implementations of the same ABSTRACTION. We have yet to look at how to work with multiple components, so let’s now turn our attention in that direction.

12.3. Working with multiple components

DI CONTAINERS thrive on distinctness but have a hard time with ambiguity. When using CONSTRUCTOR INJECTION, a single constructor is preferred over overloaded constructors because it’s evident which constructor to use when there’s no choice. This is also the case when mapping from ABSTRACTIONS to concrete types. If we attempt to map multiple concrete types to the same ABSTRACTION, we introduce ambiguity.

Despite the undesirable qualities of ambiguity, we often need to work with multiple implementations of a single interface. This can be the case in these situations:

  • Different concrete types should be used for different consumers.
  • DEPENDENCIES are sequences.
  • Decorators are in use.

We’ll look at each of these cases and see how Spring.NET addresses each one in turn. When we’re done, you should be able to configure and resolve components even when multiple implementations of the same ABSTRACTION are in play.

As you saw in section 12.1.2, contrary to most other DI CONTAINERS, AUTO-WIRING isn’t the default behavior for Spring.NET. Fine-grained control of wiring is an equally valid option and can be used to select among multiple candidates.

12.3.1. Selecting among multiple candidates

AUTO-WIRING in Spring.NET is convenient, but requires that services are distinct. As long as we have only one object that matches a particular ABSTRACTION we have no problems, but as soon as we introduce more implementations of the same interface, ambiguity rears its ugly head.

To deal with that ambiguity, we can use the explicit wiring of DEPENDENCIES that you’ve already seen in several examples.

Configuring multiple implementations of the same abstraction

Until now, you’ve been configuring named objects—but objects don’t have to have names. You can configure multiple objects without providing a name:

<objects xmlns="http://www.springframework.net">
  <object type="SauceBéarnaise" />
  <object type="Steak" />
</objects>

The SauceBéarnaise and Steak classes are both configured without a name. Because you haven’t explicitly provided names for the SauceBéarnaise and Steak objects, Spring.NET assigns an automatically generated name for each. If you knew the algorithm that Spring.NET uses to generate a name, you could request the objects using the GetObject method; but it might turn out to be a somewhat brittle solution. Instead, you can use the GetObjectsOfType method which was also introduced in section 12.1.1. As soon as we configure a type in Spring.NET, we can retrieve it using any of the types from which it derives.

To get an instance of the concrete Steak class, for example, you can mix the GetObjectsOfType method with a couple of LINQ extension methods:

var meat = context.GetObjectsOfType(typeof(Steak))
    .Values
    .OfType<Steak>()
    .FirstOrDefault();

You request the Steak type from the GetObjectsOfType method. Spring.NET will find all configured objects that match the requested type (whether they’re named or not) and return them as a dictionary. The keys in this dictionary are the object names, but because you don’t know the names, you’re only interested in the values.

The Values property is an instance of the non-generic ICollection interface, so, to use LINQ, we must somehow cast it to a generic sequence. One possibility is to use the Cast<T> method, but a slightly safer option is to use the OfType<T> filter. Although the Cast method might throw an exception if there’s an element that can’t be cast to the desired type, the OfType method filters the sequence. Finally, we get the object from the sequence. In this case, we used FirstOrDefault, but a stronger constraint can be introduced by using the Single extension method.

The SauceBéarnaise and Steak classes both implement the IIngredient interface. When we configure objects, Spring.NET places no restrictions on how many objects we can configure of a given interface, but it still enables us to resolve them using the GetObjectsOfType method:

var ingredients = context.GetObjectsOfType(typeof(IIngredient));

Given the previous configuration, the returned ingredients dictionary will contain instances of both SauceBéarnaise and Steak, and we can use LINQ queries like we did in the previous example to retrieve particular elements that might interest us.

Although we can configure several IIngredient objects without names, we can still give them names if we want to:

<objects xmlns="http://www.springframework.net">
  <object id="Sauce" type="SauceBéarnaise" />
  <object id="Meat" type="Steak" />
</objects>

This enables us to resolve each of the objects by their names:

var meat = context.GetObject("Meat");
var sauce = context.GetObject("Sauce");

This doesn’t preclude us from using the GetObjectsOfType method, so all of the previous examples would still apply.

Given that we should always resolve services in a single COMPOSITION ROOT, we should normally not expect to deal with such ambiguity on this level—but we can use named objects to select among multiple alternatives when configuring DEPENDENCIES for a given consumer.

Configuring named dependencies

Wiring objects with named objects is a central feature in Spring.NET, although we also get limited AUTO-WIRING. Even though we should prefer AUTO-WIRING when possible, there are times when we need to address an ambiguous API. As an example, consider this constructor:

public ThreeCourseMeal(ICourse entrée,
    ICourse mainCourse, ICourse dessert)

In this case, we have three identically typed DEPENDENCIES that each represents a different concept. In most cases, we want to map each of the DEPENDENCIES to a separate type. The following listing shows how we could choose to configure the ICourse and the ThreeCourseMeal objects.

Listing 12.1. Wiring a list of dependencies
<object id="Entrée" type="Rillettes" />
<object id="MainCourse" type="CordonBleu" />
<object id="Dessert" type="MousseAuChocolat" />
<object id="Meal" type="ThreeCourseMeal">
  <constructor-arg ref="Entrée" />
  <constructor-arg ref="MainCourse" />
  <constructor-arg ref="Dessert" />
</object>

The three ICourse implementations are configured as named objects. When we configure the ThreeCourseMeal object, we can refer to the names when wiring the constructor arguments. The constructor-arg element also takes optional name or index attributes that we can use to identify exactly which parameter we’re referring to; but in this example we’re listing them all in the appropriate order.

Explicitly mapping constructor arguments to named objects is a universally applicable solution. We can do this even if we configure the named objects in one XML resource and the constructor in a completely different resource, because the only identification that ties a named object together with an argument is the name. This is always possible but can be brittle if we have a lot of names to manage.

When the original reason prompting us to abandon AUTO-WIRING is to deal with ambiguity, a better solution is to design the API to get rid of that ambiguity. This often leads to a better overall design.

In the next section, you’ll see how you can use the less ambiguous and more flexible approach, where you allow any number of courses in a meal. To this end, you must learn how Spring.NET deals with lists and sequences.

12.3.2. Wiring sequences

In section 10.3.2, we discussed how to refactor an explicit ThreeCourseMeal class to the more general-purpose Meal class with this constructor:

public Meal(IEnumerable<ICourse> courses)

You can configure Spring.NET to wire up Meal instances with appropriate ICourse DEPENDENCIES, and I’ll show you how. When we’re done, you should have a good idea of the options available to you when you need to configure instances with sequences of DEPENDENCIES.

Auto-wiring sequences

Spring.NET understands arrays well, but not other types of sequences. If we need an array of a particular ABSTRACTION and want to use all those configured, AUTO-WIRING just works. As an example, imagine that the Meal class offers this constructor overload:

public Meal(params ICourse[] courses)

If we want all configured ICourse objects to be injected into Meal, we can provide this configuration:

<object id="Entrée" type="Rillettes" />
<object id="MainCourse" type="CordonBleu" />
<object id="Dessert" type="MousseAuChocolat" />
<object id="Meal" type="Meal" autowire="autodetect" />

The Meal object is configured to AUTO-WIRE, and, because Spring.NET inherently understands arrays, it finds all objects that implement the ICourse interface and provides them to the Meal constructor. Array-based DEPENDENCIES are AUTO-WIRED out of the box.

Now, imagine that the constructor overload that takes an array of ICourse doesn’t exist; you have only the constructor that takes an IEnumerable<ICourse>. Although AUTO-WIRING doesn’t work in this case, you can take advantage of the built-in understanding of arrays by defining a simple Decorator[2] that must be initialized with an array. The following listing shows a generic implementation. Recall that taking IEnumerable<T> in a constructor indicates a statically typed request for that particular DEPENDENCY. What you must do is as simple as translating this request into a request for an array of the same type.

2 Erich Gamma et al, Design Patterns: Elements of Reusable Object-Oriented Software (New York: Addison-Wesley, 1994), 175.

Listing 12.2. Translating requests for a sequence into requests for arrays

The ArrayEnumerable<T> implements IEnumerable<T> so that it satisfies every constructor that requires such a sequence. On the other hand, it requires an array of the same type . Because Spring.NET inherently knows how to deal with arrays, it can satisfy a closed ArrayEnumerable by providing it with all the objects that match the item type T.

To properly wire up the Meal class with all ICourse objects, you can now configure the context like this:

<object id="Entrée" type="Rillettes" />
<object id="MainCourse" type="CordonBleu" />
<object id="Dessert" type="MousseAuChocolat" />
<object id="Courses"
        type="ArrayEnumerable&lt;ICourse>"
        autowire="autodetect" />
<object id="Meal" type="Meal" autowire="autodetect" />

You define Courses as an ArrayEnumerable<ICourse> with AUTO-WIRING turned on. Because its only constructor requires an array of ICourse, Spring.NET automatically AUTO-WIRES it with all the ICourse implementations it can find: Rillettes, CordonBleu, and MousseAuChocolat.

The Meal class requires an IEnumerable<ICourse> and is also configured to be AUTO-WIRED. When you ask Spring.NET to resolve the Meal object, it will search for a configured object that implements IEnumerable<ICourse> and find the Courses object. All three ICourse objects will be injected into the Meal object via the Courses object.

The ArrayEnumerable<T> class is a little hack that fills in a small gap in Spring.NET. It’s a pure infrastructure component which could be packaged into a reusable library.

Spring.NET automatically handles arrays, and, with a little help from ArrayEnumerable<T>, it also handles other requests for sequences by resolving them to sequences of objects that implement the requested type. The only thing you need is to configure an ArrayEnumerable of the appropriate item type. Only when you need to explicitly pick only some components from a larger set do you need to do more than that. This is possible with more explicit configuration.

Picking only some objects from a larger set

When we use Spring.NET’s ability to resolve arrays, all objects are injected into consumers. This is often the correct policy. However, as figure 12.4 shows, there may be cases where we want to pick only some components from the larger set of all registered components.

Figure 12.4. In the situation on the left, we wish to explicitly select only certain DEPENDENCIES from the larger list of all configured objects. This is different from the situation to the right, where we indiscriminately want them all.

When we previously let Spring.NET AUTO-WIRE all configured objects, it corresponded to the situation depicted on the right side of figure 12.4. If we want to configure an instance like the left side, we must explicitly define which objects should be used.

This is easy to do with named objects, because it’s more or less the idiomatic way to configure Spring.NET, which provides a special list XML element to address this particular scenario. The following listing shows an example.

Listing 12.3. Injecting named objects into a sequence

The list element can be used to indicate that the following elements are items in a list. When Spring.NET wires up the list, it creates an array of the type indicated by the element-type attribute. The list element can contain many different child elements; the ref element is used to refer to other named objects.

When you resolve the Meal object, you’ll get a Meal instance with Rillettes, CordonBleu, and MousseAuChocolat as the contained courses, while the LobsterBisque won’t be used.

Once more, you see that Spring.NET natively works with arrays. Although support for other sequence types is missing, you can work around this limitation by wrapping sequences in a class like ArrayEnumerable<T>.

Consumers that rely on sequences of DEPENDENCIES may be the most intuitive use of multiple instances of the same ABSTRACTION, but before we leave this subject, we need to look at yet another case where multiple instances come into play.

12.3.3. Wiring Decorators

In section 9.1.2, we discussed how the Decorator design pattern is extremely useful when implementing CROSS-CUTTING CONCERNS. By definition, Decorators introduce multiple types of the same ABSTRACTION. At the very least, we have two implementations of an ABSTRACTION: the Decorator itself and the decorated type. If we stack the Decorators, we may have even more.

This is another example of having multiple objects that implement the same ABSTRACTION. Unlike the previous sections, these objects aren’t conceptually equal, but rather DEPENDENCIES of each other. I’ll show you two different ways to configure Spring.NET to deal with this pattern.

Decorating with named objects

Throughout this chapter, you’ve seen plenty of examples of how to reference named objects as constructor arguments. You can also use this idiomatic approach to configure Decorators.

The Breading class is a Decorator of IIngredient; it uses CONSTRUCTOR INJECTION to receive the instance it should decorate:

public Breading(IIngredient ingredient)

To make a Cotoletta, you would like to decorate a VealCutlet (another IIngredient) with the Breading class. Because you already know how to connect named objects with constructor arguments, it should feel natural to do something similar to this:

By now, this approach should be familiar to you. You use a reference to a named object to wire the Breading object with the Cutlet object. Because Spring.NET doesn’t explicitly deal with mappings from ABSTRACTIONS to concrete type, each of these two elements represents an object like any other object element would. That they both implement the IIngredient interface does in no way impact how you configure them.

When you resolve the Breading name, you get a Breading instance that decorates a VealCutlet.

This is a universally applicable way to decorate a component, but when you don’t otherwise care about the decorated component, you can use a more implicit method.

Decorating with inline objects

If you never need to resolve the decorated component directly, you can use a more implicit way to decorate it. Imagine that you never expect having to resolve the VealCutlet directly as an IIngredient; when you want an IIngredient, you always want to get the Cotoletta.

In such cases, there’s no need to explicitly configure the VealCutlet as an independent object. Instead, you can take advantage of Spring.NET’s inline object syntax:

<object id="Breading" type="Breading">
  <constructor-arg>
    <object type="VealCutlet" />
  </constructor-arg>
</object>

Spring.NET enables you to define objects as nested elements. Instead of referring to a named object, the constructor-arg element can contain full object configurations. Because you don’t expect to have to refer to a VealCutlet object from anywhere else in the configuration, you can provide an unnamed object element with the correct type attribute. When nested within the constructor-arg element, the VealCutlet type will be resolved as the first constructor argument to the Breading class.

There are a few variations available to us when configuring Decorators. Unlike Castle Windsor, Spring.NET has no implicit understanding of Decorators, which may be a bit surprising because, like Windsor, it offers the ultimate support for the Decorator pattern: INTERCEPTION.

12.3.4. Creating Interceptors

In section 9.3.3, you saw an example of how to add error handling and a Circuit Breaker[3] to a WCF client with Castle Windsor’s dynamic INTERCEPTION capability. To demonstrate Spring.NET’s INTERCEPTION capability and compare it to Castle Windsor and Unity, I’ll walk you through the same familiar example, but now implemented with Spring.NET.

3 Michael T Nygard, Release It! Design and Deploy Production-Ready Software (Raleigh, NC: Pragmatic Bookshelf, 2007), 104.

As figure 12.5 shows, adding an aspect to Spring.NET is a pretty simple process.

Figure 12.5. The simple overall process of adding an aspect in Spring.NET.

The bulk of the work involves developing the interceptor itself, but once we’ve done that, we must add it to the container. This is done in XML configuration, like everything else.

However, we can’t configure the interceptors before we implement them, so the first step is to write some code for the error handling and Circuit Breaker interceptors. Once they’re completed, we can configure the container with both.

Implementing an exception handling interceptor

Implementing an interceptor for Spring.NET requires us to implement the IMethodInterceptor interface. The following listing shows how to implement the exception handling strategy from chapter 9. This particular implementation for Spring.NET corresponds to listing 9.8 for Castle Windsor and listing 14.13 for Unity.

Listing 12.4. Implementing an exception handling IMethodInterceptor

The ErrorHandlingInterceptor class implements the IMethodInterceptor interface, which only defines the single Invoke method . This is where you must define the INTERCEPTION logic. The only argument to the method is an instance of the IMethodInvocation interface; with its Proceed method, you attempt to invoke the decorated method and return the result . However, because the purpose of this interceptor is to handle known exceptions, the call to the Proceed method is wrapped in a try block.

If the Proceed method (or rather the decorated method that Proceed invokes) throws one of the known exceptions, the interceptor catches it and alerts the user about the error . In this example, the set of known exceptions is hard-coded into the interceptor itself, but a more general-purpose implementation could decide to suppress or rethrow exceptions based on an injected Specification.[4]

4 Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software (New York: Addison-Wesley, 2004), 224.

Because the Invoke method must return an object, it returns null in the cases where an exception was caught and suppressed. This is already the correct value to return in all the cases where the decorated method returns void, but for a method with real return values, this can be problematic because it can easily lead to NullReferenceExceptions. However, we can create another interceptor that assigns appropriate default values for different return types. This would be more correct than trying to guess the correct default value from within the ErrorHandlingInterceptor, which is a general-purpose interceptor that can be used to intercept any interface; it would also be true to the spirit of the SINGLE RESPONSIBILITY PRINCIPLE.

The ErrorHandlingInterceptor takes care of handling certain exceptions from a decorated component. This component can itself be another interceptor in the form of a Circuit Breaker.

Implementing a Circuit Breaker interceptor

The Circuit Breaker interceptor is a bit more complex because it requires the ICircuitBreaker DEPENDENCY, but as the following listing shows, we address this by applying standard CONSTRUCTOR INJECTION. When it comes to composing the class, Spring.NET treats it like any other object, so as long as it can resolve the DEPENDENCY, all is well.

Listing 12.5. Implementing a Circuit Breaker IMethodInterceptor

The CircuitBreakerInterceptor needs to delegate its actual implementation to an ICircuitBreaker instance. Because Spring.NET can AUTO-WIRE an interceptor like it does any other object, you can use standard CONSTRUCTOR INJECTION to inject the ICircuitBreaker.

In the Invoke method, you need to implement the Guard-Succeed/Trip idiom you already saw in listings 9.4 and 9.9. As in listing 12.4, you invoke the decorated method by calling the Proceed method , but instead of returning the value right away, you need to assign it to the local result variable so that you can indicate success to the Circuit Breaker . Recall that this can close an otherwise open breaker.

Any exception which might be thrown by the decorated method is rethrown unmodified by the Proceed method, so you can catch it and Trip the breaker as you would normally do.

With both ErrorHandlingInterceptor and CircuitBreakerInterceptor implemented, it’s time to configure the container to make them decorate an IProductManagementAgent object.

Configuring interception

What we really want to do is to intercept an IProductManagementAgent object with both Circuit Breaker and error handling so that when an exception happens during communication with the web service, the Circuit Breaker is opened and the exception is handled, giving the application a chance to recover once the web service or the network is back online.

Configuring INTERCEPTION in Spring.NET is easy. The first thing you need to do is to configure the interceptors themselves:

<objects xmlns="http://www.springframework.net"
         default-autowire="constructor">

  <object id="ErrorHandlingInterceptor"
          type="ErrorHandlingInterceptor" />
  <object id="CircuitBreakerInterceptor"
          type="CircuitBreakerInterceptor" />

</objects>

Being particularly unimaginative, I gave the objects the same id as their type. Notice that CONSTRUCTOR INJECTION–based AUTO-WIRING is switched on by default. Whereas the ErrorHandlingInterceptor has a default constructor, the CircuitBreakerInterceptor uses CONSTRUCTOR INJECTION to request an ICircuitBreaker. AUTO-WIRING works for both, as well as most other objects in the configuration, so switching it on by default is the easiest thing to do.

Now that you have the interceptors in place, the only thing left is to configure the IProductManagementAgent object with the desired interceptors. Figure 12.6 shows the configuration you’re aiming for.

Figure 12.6. The IProductManagementAgent should be decorated by the Circuit Breaker interceptor so that when an exception is thrown by the agent, the circuit’s opened for a while. Because the Circuit Breaker only registers exceptions, but doesn’t handle them, this is the responsibility of the error handling interceptor, which must be outermost to be able to handle exceptions from both the agent as well as the Circuit Breaker.

As the following listing demonstrates, this is done with the configuration XML syntax and a special namespace and classes that Spring.NET provides for this purpose. The general concept of configuring INTERCEPTION involves decoupling what to do from where to do it. We must still answer both of these questions, but we do it separately and then tie them together.

Listing 12.6. Configuring interceptors

In the previous code, you registered the interceptors—but you also need to register the classes to be intercepted . In this example it’s a single class, but you could intercept many different classes with the same set of interceptors if you’d like.

To specify which classes or methods to intercept, you must define something called a Pointcut, which is a fancy name for a rule that defines what to intercept. If you recall the original introduction of INTERCEPTION back in chapter 9, this corresponds to the Castle Windsor IModelInterceptorsSelector implemented in listing 9.10. Like Castle Windsor, Spring.NET allows you to write imperative code that defines a Pointcut, but in addition to that it also provides some declarative Pointcuts. One such static Pointcut is the RegularExpressionMethodPointcut , which you can use to define the matching rule with a regular expression. For each method call it will attempt to match the full name of the method with the regular expression. In this particular case you only want to match members on the WcfProductManagementAgent class.

Finally, you need to bind the Pointcut to the interceptors you previously registered. This is done with a series of advisor elements that declare the interceptors and the order in which they’re composed. Notice that because you list ErrorHandlingInterceptor first, it becomes the outermost interceptor, itself intercepting the CircuitBreakerInteceptor.

The final thing you need to do to configure the application with robust out-of-process communication management is to make sure that all DEPENDENCIES can be satisfied. Because CircuitBreakerInteceptor requires an ICircuitBreaker, you must also configure this object:

<object type="CircuitBreaker" autowire="no">
  <constructor-arg value="00:01:00" />
</object>

The CircuitBreaker constructor requires a timeout in the form of a TimeSpan instance, and you prefer to define this primitive value inline. To do that, you must disable the default AUTO-WIRING setting to explicitly set the timeout to one minute.

To be effective at all it’s important that there’s only one Circuit Breaker instance (at least per out-of-process resource), but because the default object scope is SINGLETON, you don’t need to explicitly express that.

The example demonstrated how to utilize dynamic INTERCEPTION with Spring.NET. In my personal opinion, I find the complexity comparable with Castle Windsor’s and Unity’s INTERCEPTION support. While not entirely trivial, the potential benefit is great.

INTERCEPTION is a dynamic implementation of the Decorator pattern, and the Decorator pattern is itself a combined application of multiple objects of the same type. Spring.NET lets us work with multiple components in several different ways. We can configure them as alternatives to each other, as peers resolved as sequences, as hierarchical Decorators, or even as interceptors. When it comes to arrays, Spring.NET will figure out what to do, but we can often map other sequence types into arrays using an adapter such as the ArrayEnumerable<T> class. This also enables us to explicitly define how services are composed if we need more explicit control.

This may also be the case when we need to deal with APIs that deviate from CONSTRUCTOR INJECTION. So far, you’ve seen how to configure objects, including how to specify object scopes and how to deal with multiple objects, but until now we’ve allowed the container to wire DEPENDENCIES by implicitly assuming that all components use CONSTRUCTOR INJECTION. This isn’t always the case, so in the next section we’ll review how to deal with classes that must be instantiated in special ways.

12.4. Configuring difficult APIs

Until now, we’ve considered how to configure components that use CONSTRUCTOR INJECTION. One of the many benefits of CONSTRUCTOR INJECTION is that DI CONTAINERS such as Spring.NET can easily understand how to compose and create all classes in a dependency graph.

However, this becomes less clear when APIs are less well behaved. Here I’ll show you how to deal with primitive constructor arguments, static factories, and PROPERTY INJECTION. These all require special attention. We’ll start by looking at classes that take primitive types, such as strings or integers as constructor arguments.

12.4.1. Configuring primitive Dependencies

As long as we inject ABSTRACTIONS into consumers, all is well. But it becomes more difficult when a constructor depends on a primitive type, such as a string, number, or enum. This is often the case for data access implementations that take a connection string as a constructor parameter, but it’s a more general issue that applies to all strings and numbers.

Conceptually, it doesn’t make much sense to register a string or number as a component in a container, and with Spring.NET, it isn’t possible to register the value of a primitive type as an object.

Consider, as an example, this constructor:

public ChiliConCarne(Spiciness spiciness)

In this example, Spiciness is an enum:

public enum Spiciness
{
    Mild = 0,
    Medium,
    Hot
}

 

Warning

As a rule of thumb, enums are code smells and should be refactored to polymorphic classes.[5] However, they serve us well for this example.

5 Martin Fowler et al., Refactoring: Improving the Design of Existing Code (New York: Addison-Wesley, 1999), 82.

 

You need to explicitly supply the value of the spiciness constructor parameter as part of configuring the ChiliConCarne object:

Spring.NET comes with several type converters that convert text representations into instances of the desired types. One of the built-in type converters converts text to enums, which enables us to supply the text Hot as the value of the constructor-arg element . Spring.NET looks at the type of the constructor parameter for the ChiliConCarne class, determines that it’s an enum, and uses the appropriate type converter to convert the text Hot into the value Spiciness.Hot.

This feature of Spring.NET addresses situations where we need to supply primitive values as arguments. The ChiliConCarne example supplied the argument to a constructor, but sometimes a class has no public constructor.

12.4.2. Configuring static factories

Some classes can’t be instantiated through a public constructor. Instead, we must use some sort of factory to create instances of the type. This is always troublesome for DI CONTAINERS because, by default, they look after public constructors.

Consider this example constructor for the public JunkFood class:

internal JunkFood(string name)

Even though the JunkFood class is public, the constructor is internal. Obviously, instances of JunkFood should be created through the static JunkFoodFactory class:

public static class JunkFoodFactory
{
    public static IMeal Create(string name)
    {
        return new JunkFood(name);
    }
}

From Spring.NET’s perspective, this is a problematic API because there are no unambiguous and well-established conventions around static factories. It needs help—and you can provide this when you configure the object:

<object id="Meal"
        type="JunkFoodFactory"
        factory-method="Create">
  <constructor-arg value="chicken meal" />
</object>

As always, the configuration of the object is expressed within an object element, but rather than defining the type of the object itself, you define the type of the factory. You must also configure that the name of the factorymethod is Create. Notice that even though the Create method isn’t a constructor per se, you still use the constructor-arg element to define the value of the name argument for the Create method.

Even though the type attribute is defined as the factory type instead of the resulting type, Spring.NET is clever enough to understand that the return type of the Create method is JunkFood. This means that you can dispense with the id attribute and create an unnamed object, as you did in section 12.3.1, and you would still be able to resolve a JunkFood object with the GetObjectsOfType method.

The last common deviation from CONSTRUCTOR INJECTION we’ll examine is PROPERTY INJECTION.

12.4.3. Wiring with Property Injection

PROPERTY INJECTION is a less well-defined form of DI because we’re not forced by the compiler to assign a value to a writable property. Even so, Spring.NET understands and works with PROPERTY INJECTION in an intuitive way. If we enable AUTO-WIRING it tends to just work, but it will also work with explicit wiring.

Consider this CaesarSalad class:

public class CaesarSalad : ICourse
{
    public IIngredient Extra { get; set; }
}

It’s a common misconception that a Caesar Salad includes chicken; this isn’t true. A Caesar Salad is a salad, but it tastes great with chicken, so chicken is often offered as an extra ingredient. The CaesarSalad class models this by exposing a writable property named Extra.

If you configure only the CaesarSalad without explicitly addressing the Extra property, the property won’t be assigned. You can still resolve the instance, but the property will have the default value that the constructor assigns to it (if any).

Explicitly wiring properties

There are several ways you can configure the CaesarSalad so that the Extra property will be appropriately populated. One is to explicitly wire the property to a named object:

<object id="Course" type="CaesarSalad">
  <property name="Extra" ref="Chicken" />
</object>
<object id="Chicken" type="Chicken" />

The property element identifies that the name of the property is Extra and that it should be assigned with the named object Chicken. Instead of using a reference to a named object, you can also use an inline object:

<object id="Course" type="CaesarSalad">
  <property name="Extra">
    <object type="Chicken" />
  </property>
</object>

You can always explicitly wire properties with the property element, but because the property is identified by its name, this approach tends to be brittle. If you later rename the property, most refactoring tools won’t identify and change the value of a name attribute in various XML files. This may cause runtime errors.

A better option is to AUTO-WIRE objects.

Auto-wiring properties

As you may recall from section 12.1.2, you must explicitly enable AUTO-WIRING in Spring.NET, but once you do that, PROPERTY INJECTION just works. If the DEPENDENCY can’t be satisfied, the property is ignored:

<objects xmlns="http://www.springframework.net">
  <object id="Course" type="CaesarSalad"
          autowire="autodetect" />
</objects>

In this example, the Course object is the only object configured for the container. Although it’s configured to be AUTO-WIRED, the Extra property will never be assigned because there’s no available IIngredient object. An exception isn’t thrown; the property is simply ignored.

This changes as soon as an IIngredient object becomes available:

<object id="Course" type="CaesarSalad"
        autowire="autodetect" />
<object type="Chicken" />

Now, when you resolve the Course object, you’ll receive an instance of CaesarSalad with Extra Chicken.

Using AUTO-WIRING is more robust because we can rename properties without fearing that the Spring.NET configuration will break at runtime.

You saw how to use Spring.NET to deal with more difficult creational APIs. In general you can always explicitly configure wiring using the XML configuration, but you also saw that PROPERTY INJECTION can be configured with AUTO-WIRING.

12.5. Summary

Among the DI CONTAINERS covered in this book, Spring.NET is unique in the sense that it’s the only container which is implemented as a port from Java. Nowhere is this more apparent than in Spring.NET’s strong reliance on XML configuration.

Most of the older .NET DI CONTAINERS started out with a strong focus on XML, but while others have moved on, Spring.NET has not.

Although future versions of Spring.NET may get stronger support for CODE AS CONFIGURATION and perhaps even CONVENTION-BASED CONFIGURATION, the current idiomatic usage involves lots of XML.

Perhaps the weakest area is the limited support for LIFETIME MANAGEMENT. One thing is that, like StructureMap, Spring.NET has no explicit support for releasing object graphs—this can be viewed as much as a design decision as a lack of a feature. Another thing is that there’s no support for custom object scopes.

Whereas the LIFETIME MANAGEMENT features are weak, Spring.NET is one of the few DI CONTAINERS to offer built-in INTERCEPTION.

Spring.NET is still based on .NET 1.1, which may be a benefit for some people. We get comprehensive documentation and the option of purchasing commercial support, so although the overall impression may be slightly outmoded, it’s also one of a professional package.

We may regard Spring.NET as an old-but-trusted framework. In contrast, the next chapter presents one of the most modern DI CONTAINERS: Autofac.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.212.217