Topics.Core Dependency Injection

If you have been building software for a while, you may be familiar with the two very popular design patterns: Dependency Injection (DI) and Inversion of Control (IoC) widely credited to Martin Fowler. These patterns allow for “late-binding” of functionality through well-known interfaces. IoC implies that there is a system framework that calls methods on implementations provided by applications. DI is a form of IoC, where implementations are passed (“injected”) into an application object through constructors or setters. The application ‘depends’ on an implementation to do a specific task. Perhaps an example of this would be source control integration for Visual Studio (VS). VS may ship with Team Foundation System (TFS) as a default source control plugin, but it also allows one to inject a different implementation, that perhaps implements an interface to Git. Nonetheless, if VS is going to have access to source control, it depends on some plugin for the implementation.

The Topics Platform uses DI extensively for injecting all sorts of functionality including messaging binding, service hosts as well as document definitions for WPF MVVM. The current version of Topics uses the Spring DI framework which is an Open Source package available at: http://www.springframework.net/. There are several others to choose from, including Castle, Unity and Ninject to name a few. I predict there will be more choices in DI framework for Topics in the very near future.
For the time being, we are going to stick with Spring. So let’s take a look at an example. If you haven’t downloaded the source code yet, it can be found at Github. I’ve put together a collection of functional tests in the Tests folder in the Topics.Core solution. Take a look at the project:

Topics.Core->Development->Tests->Messaging->Topics.Core.Messaging.InProcessUnitTests

The purpose of this example is to demonstrate InProcessMessaging, but we’re going to see how Topics.Core uses the Spring.Net Framework and to point out some common practices. Now, the TestMethods contained in MessagingTests.cs depend on an implementation of ITopicBus in order to send and receive messages. It does not matter which implementation of ITopicBus it uses, as long as it implements the required methods. In this sample, we are injecting an instance of Topics.Core.Messaging.InProcessTopicsBus which just happens to implement that interface in terms of a Producer/Consumer concurrent queue. The first thing we have to do is create some Spring Configuration metadata that identifies the specific classes that will be used. That metadata is contained in the Config folder of the project in a file named Messaging.xml.

<objects xmlns="http://www.springframework.net"
         xmlns:nms="http://www.springframework.net/nms">

  <alias name="InProcessTopicBus" alias="DefaultTopicBus"/>

  <object id="InProcessTopicBus" singleton="true"  type="Topics.Core.Messaging.InProcess.InProcessTopicBus, Topics.Core">
    <property name="MessageConverter" ref="SimpleMessageConverter"/>
    <property name="MessageListenerFactory" ref="ActionMessageListenerFactory"/>
    <property name="ReplyTimeout" value="3000"/>
  </object>

  <object name="SimpleMessageConverter" type="Topics.Core.Messaging.SimpleMessageConverter, Topics.Core">
  </object>

  <object name="ActionMessageListenerFactory" type="Topics.Core.Messaging.ActionMessageListenerFactory, Topics.Core">
  </object>

</objects>

This metadata identifies 3 objects. The first, InProcessTopicBus, contains several properties, two of which are assigned a reference to another object in the metadata. When the DI container is asked for an object with the Id of “InProcessTopicBus” the object is created with a parameter-less constructor, as are any referenced classes contained in the metadata. InProcessTopicBus  can also be accessed by its alias, “DefaultTopicBus”. There is a way to express constructor parameters if there is a need. The “singleton” attribute tells the DI container to create one and only one instance of this object.

For the more “static” types of configuration metadata, like the metadata in this file, it is common practice to include it as an embedded resource. The Topics Platform follows this convention of storing static configuration metadata in xml streams. Spring has API as well as other metadata elements that can then reference this information as an embedded resource. For example, the TestInitialize() method uses the api to load an instance of InProcessTopicBus by passing the uri of the embedded resource to the constructor of XmlApplicationContext.

        [TestInitialize]
        public void TestInitialize()
        {
            IApplicationContext ctx = new XmlApplicationContext(
            "assembly://Topics.Core.Messaging.InProcess.UnitTests/Topics.Core.Messaging.InProcess.UnitTests.Config/Messaging.xml");
            _topicBus = (ITopicBus)ctx.GetObject("DefaultTopicBus");
        }

This can also be accomplished through your app.config instead. Here is an equivalent way of loading the XmlApplicationContext. First, we add the configSection for Spring.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <sectionGroup name="spring">
      <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
      <section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core" />
      <section name="typeAliases" type="Spring.Context.Support.TypeAliasesSectionHandler, Spring.Core" />
    </sectionGroup>
  </configSections>

  <spring>
    <context>
      <resource uri="~/Config/Messaging.xml" />
    </context>
  </spring>
  
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
    </startup>
</configuration>

Inside the context element, we just provide the uri to the embedded resource. This shorthand method assumes that the resource is part of the main assembly where the XmlApplicationContext will be constructed. Otherwise, you can provide a fully qualified uri as we did in the case of the functional test.

When using the app.config method to provide Spring metadata, the context needs to be created once the application is loaded, as in:

   IApplicationContext ctx = ContextRegistry.GetContext();

Any Topics Platform assembly references the Topics.Core nugget package will automatically depend on the Spring.Core nugget package. If your application does not already reference that package, you can pull in the Spring.Core package using NuGet. Open the Package Manager Console window and at the prompt, enter

PM> Install-Package Spring.Core –Version 1.3.2

This will go to the nuget.org source and download and install the Spring.Core package and add a reference to Spring.Core to your project. If you have not used NuGet before, you will also notice a new file added to your project, packages.config. This contains a entry for each package you’ve added as well as any dependent packages. Do not edit this file unless you are very sure as to what you are doing.

So far we’ve introduce how Spring DI container is used in Unit and Functional Tests. There are two other types of projects that also rely heavily on Spring DI, Service Hosts and WPF MDI Clients. In addition, the other TopicBus implementations have their own messaging bindings that are expressed as metadata xml. There will be follow-on articles covering each of those elements as they are released.

What we have covered in this article is:

  • Core uses Spring.Core Dependency Injection container.
  • Classes are expressed in Spring Configuration metadata xml
  • Static configurations are typically stored in embedded resources
  • Core can use an api or app.config file to reference configuration metadata
  • Core nuget package depends on Spring.Core 1.3.2
0 votes

BECOME A COMMENTERS?

You must be logged in to post a comment.