Wednesday, May 13, 2009

Dependency Injection and StructureMap (3)

SM uses Fluent Interface(FI) to describe dependency mapping relationships. The FI description is to read and straightforward. You may find out various ways to describe the dependency mapping(DM) relationships. Personally, I prefer to use FI in the following format:

[For a required type].[Use a cache mechanism].[Map to a specific type]

The first part is normally for an interface type, but it can be concrete class type. The caching method is an enum type. It covers almost all the cases such new instance per request, singleton, one instance within a thread, HttpContext, HttpSession and more, see SM's documentation on Scroping and Lifecycle Management for detail information.

For the example case as described in the previous blog, here are the codes to describe ILog dependency mapping:

public class SMRegistry : Registry
{
public SMRegistry (
Configuration config)
{
ForRequestedType<ILog>().
CacheBy(StructureMap.Attributes.InstanceScope.Singleton).
TheDefault.Is.OfConcreteType<Logtofile>().
WithCtorArg(LogToFile.CtorArgFile).EqualTo(config.FileName).
WithCtorArg(LogToFile.CtorArgLogFlags).EqualTo(config.LogFlags);
...
}
}

Where config is an instance of Configuration class. This instance contains configuration (loaded from xml file) to be passed to concrete instances.

ILog interface is mapped to class LogToFile. This class CTOR takes two primitive string parameters one for file name and another as log flags. Here you can specify the primitive parameters using WithCtorArg(...).EqualTo(...) pattern. Notice that the parameter name in WithCtorArg has to be exactly as same as the one used in the CTOR and it is case-sensitive. I prefer to define a public const in CTOR's class.

I want to skip the dependency mappings for IDataReader, IDataProcessor and IDataWriter. You can image continuing to do similar mappings for them. I'll discuss how to use SM's Registry to do mappings in a structured chain manor.

Now let's look at how to define DM for IProcessControl to a concrete class in the SMRegistry' CTOR:

    ForRequestedType<IProcessController>().
CacheBy(StructureMap.Attributes.InstanceScope.Hybrid).
TheDefault.Is.OfConcreteType<ProcessController>().
WithCtorArg(ProcessContoller.CtorArgID).EqualTo(config.ID);

That's it. Recall that ProcessController's CTOR has five parameters, but only one is primitive type. Other four are instances as interface types. Those interfaces can be defined in a similar way as ILog. As a result, SM has the knowledge to inject concrete instances for those interface parameters. As I said before, you don't need to create instances in your application, you just tell SM the DMs and how. SM will inject instances for you.

If a CTOR's parameter has one concrete class parameter, you can still implement the similar way to do DM. I'll explain it later.

0 comments: