CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

David Hayden [MVP C#]

         .NET Tutorials, Patterns, and Practices

Factory Method Support in Castle Windsor and Spring.Net

Factory Method Support in Castle Windsor and Spring.Net

by David Hayden

 

Most of the time when using Windsor I simply map a service provider to a service contract as such programmatically or in a configuration file:

 

<components>
    <component
        id="CustomerRepository"
        service="Sample.ICustomerRepository, Sample"
        type="Sample.CustomerRepository, Sample"
        lifestyle="singleton" />
</components>

 

and request the service as follows:

 

ioc.Resolve<ICustomerRepository>();

 

which will then just return the type mapped to ICustomerRepository which in this case is the CustomerRepository Class. This works because I know the service provider ahead of time, CustomerRepository, and add it to the configuration file.

However, what if it isn't that easy? What if CustomerRepository won't always be the service provider for ICustomerRepository? What if the chosen service provider is based on other runtime factors that need to be taken into consideration during runtime? This is when we use the Factory Method support in Windsor and Spring.NET.

 

Factory Method

When service or object instantiation is

  1. A little more complicated than calling new
  2. Based on a number of runtime factors
  3. Volatile and you want to loosely-couple creation from the caller

a Factory Method is a pretty decent choice of hiding object creation behind a method call.

Here is a defintion from Design Patterns in C#

"When you develop a class, you usually provide class constructors to let clients of you class instantiate it.  There are times, though, when a client that needs an object does not or should not know which of several possible classes to instantiate. The FACTORY METHOD pattern lets a class developer define the interface for creating an object while retaining control of which class to instantiate. [Design Patterns in C#, Steven John Metsker, p. 171]"

Enterprise Library, for example, is smothered in Factory Methods, because it is based on a provider model and the actual provider chosen is determined at runtime by configuration settings in a configuration file. Here is an example from the Data Access Application Block:

 

Database db = DatabaseFactory.CreateDatabase();

 

Database is an Abstract Class and several classes, like SqlDatabase and OracleDatabase, could be returned by DatabaseFactory.CreateDatabase() depending on whether your configuration settings specify you want to connect to SQL Server or Oracle. Instantiation details are hidden behind the CreateDatabase Factory Method because the actual provider returned is based on runtime configuration settings.

 

Using Factory Method Support in Castle Windsor

As mentioned above, Castle Windsor will normally provide you a service provider based on the type mapped to a service contract, but you have the option of specifying a Factory Method in your code to instantiate the service provider.

Instead of mapping the CustomerRepository Class to ICustomerRepository in the Windsor Configuration, I will instead create a Factory Method on a class that returns an ICustomerRepository:

 

public class CustomerRepositoryFactory

{

    public ICustomerRepository Create()

    {

        return new CustomerRepository();

    }

}

 

Here I have just hardcoded new CustomerRepository(), but in reality I would be interrogating various runtime configuration and context settings to determine the actual provider for ICustomerRepository Services.

In my Windsor Configuration File, I can now tell Windsor to call the Create Method ( Factory Method ) on CustomerRepositoryFactory and return its results when the application requests ICustomerRepository. Notice the FactorySupport Facility which extends the container to provide Factory Method Support. Also notice that on the CustomerRepository Component we now have factoryid and factoryCreate options which specify which type and method to call to instantiate the ICustomerRepository Provider.

 

<facilities>

    <facility
        id="factory.support"
        type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.MicroKernel"
    />
    
</facilities>

<components>

    <component
        id="CustomerRepositoryFactory"
        type="ConsoleApplication2.CustomerRepositoryFactory, ConsoleApplication2"
    />

    <component
        id="CustomerRepository"
        service="ConsoleApplication2.ICustomerRepository, ConsoleApplication2"
        type="ConsoleApplication2.CustomerRepository, ConsoleApplication2"
        factoryId="CustomerRepositoryFactory"
        factoryCreate="Create"
    />
    
</components>

 

You can also pass dependencies into the Factory Method. Let's change the CustomerRepositoryFactory Create Method to require an external service and pretend we actually use it to determine which ICustomerRepository to instantiate:

 

public class CustomerRepositoryFactory

{

    public ICustomerRepository Create(IExternalService service)

    {

        return new CustomerRepository();

    }

}

 

All we have to do is add the dependency into the Windsor Configuration File and it will provide it to the method:

 

<facilities>

    <facility
        id="factory.support"
        type="Castle.Facilities.FactorySupport.FactorySupportFacility, Castle.MicroKernel"
    />
    
</facilities>

<components>

    <component
        id="ExternalService"
        service="ConsoleApplication2.IExternalService, ConsoleApplication2"
        type="ConsoleApplication2.ExternalService, ConsoleApplication2"
    />

    <component
        id="CustomerRepositoryFactory"
        type="ConsoleApplication2.CustomerRepositoryFactory, ConsoleApplication2"
    />

    <component
        id="CustomerRepository"
        service="ConsoleApplication2.ICustomerRepository, ConsoleApplication2"
        type="ConsoleApplication2.CustomerRepository, ConsoleApplication2"
        factoryId="CustomerRepositoryFactory"
        factoryCreate="Create"
    />
    
</components>

 

Pretty slick. The use of a Factory Method does not change the interface for requesting services via Castle Windsor. The following works as expected in my sample:

 

WindsorContainer ioc = new WindsorContainer("../../Windsor.config");

ICustomerRepository repository = ioc.Resolve<ICustomerRepository>();

repository.Add(new Customer());

 

Using Factory Method Support in Spring.NET

Spring.NET supports the Factory Method as well. We just have changes in the configuration file and client code, and the CustomerRepositoryFactory stays the same.

The configuration file is as follows. Notice the factory-object and factory-method options to specify the type and factory method that will be called to instantiate the service. Also notice the constructor-arg for providing the IExternalService to the method.

 

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

    <object
        id="ExternalService"
        type="ConsoleApplication2.ExternalService, ConsoleApplication2"
    />
    
    <object
        id="CustomerRepositoryFactory"
        type="ConsoleApplication2.CustomerRepositoryFactory, ConsoleApplication2"
    />
    
    <object
        id="CustomerRepository"
        factory-method="Create"
        factory-object="CustomerRepositoryFactory">
            <constructor-arg name="service"  ref="ExternalService"/>
    </object>
    
</objects>

 

 and the client code I used for my sample is:

 

IResource input = new FileSystemResource("../../Spring.config");

IObjectFactory factory = new XmlObjectFactory(input);

ICustomerRepository repository = (ICustomerRepository)factory.GetObject("CustomerRepository");

repository.Add(new Customer());

 

Very cool!

 

Conclusion

Both Caste Windsor and Spring.NET have wonderful support for Factory Methods when service instantiation needs to be delegated to a factory method in your application. For those of you using the Policy Injection Application Block, one might consider calling PolicyInjection.Wrap<ICustomerRepository>(...) in the factory method for a bit of AOP Services Enterprise Library style. This is just one option of course to get the Policy Injection Application Block to work with these containers. Of course, Windsor and Spring.NET have AOP services as well.

 


Published Dec 13 2007, 10:55 AM by David Hayden
Filed under: ,

Comments

Sean Feldman said:

Thank you for showing this. I was wondering how to do it and also was too lazy to dig the documentation.

# December 13, 2007 5:02 PM

CB said:

Do you have a quick real world example?  I always come up with needed context info about the user to drive this scenario.. any others?

# December 14, 2007 11:23 AM

David Hayden said:

Another example would be B2B Service Availability.

I use this approach when a web application is dependent on a web service from a 3rd party provider. When the preferred provider goes down or is loaded with requests, we can check its status / availability and switch to a backup provider or strategy on demand.

# December 14, 2007 11:59 AM

SteveG said:

Thanks David.

Question, suspose the following:

public class CustomerRepositoryFactory

{

   public ICustomerRepository Create(string repositoryCustomerId)

   {

       return ioc.Resolve<ICustomerRepository>("component.repository1")

   }

}

In other words, your using the factory to determine which CustomerRepository.  ie. you have two customerrepository objects in your windsor config  with id's of "component.repository1" and "component.respository2"

Would you provide something perhaps like this in order to keep object creation in the container:

ICustomerRepository repository = ioc.Resolve<ICustomerRepository>("component.repository1");

or

ICustomerRepository repository = ioc.Resolve<ICustomerRepository>("component.repository2");

Is this wise?

# December 14, 2007 3:07 PM

David Hayden said:

Steve,

Great point. It sounds very wise to me as it should offer better maintainability and more consistency. I haven't been doing that when the object I create doesn't have other dependencies, but I should probably be doing it all the time when I am in control of object creation.

The only time you couldn't do that is when using various objects from frameworks that come with their own facades and factories for object creation. In those cases, I have to call their factory or facade and then wrap the object using the adapter design pattern if necessary.

Thanks for the excellent comment!

# December 15, 2007 10:01 AM
Check out Devlicio.us!

This Blog

Syndication

News

CodeBetter.Com Home