Wednesday, April 28, 2010

Passing external configuration data to NInject instantiated objects.

I used to be a spring.net user and was quite happy about it. To me, the xml is the best advantage and the worst pain. It's good because it's straight forward, easy to embed external data in; it's bad because it make refactoring a pain, and verbose. With Reshaper's help, the pain is a little less. But still it's less pleasant. Therefore I have been searching for replacements, and NInject (referred as NI) is one of the candidates. The biggest problem to NI is the document. It has a lot of unit test cases, but very limited documents, samples. You can only find a very un-realistic sample from the wiki pages on the website. It reveals the tip of the iceberg, but too simple to be too much usage.

Before I make a migration, I need to make sure all my usage scenarios are covered by NI. I used spring.net's mostly as a IOC container, therefore I assume NI should be able to provide most of the functions. In my case, some of my components needs some configuration data to startup, and if the configuration is wrong or invalid, the whole application should fail to start and administrators will know immediately (it's a server side app).

In real world applications, external configuration in xml, ini, yaml, json format is very common and will affect application behaviors. But I did not find any example, tutorial about that. I asked a question in stackoverflow, but no response yet. So I decide to help myself :).

The code in question is like below:

public interface IServer
{
void start();
void stop();
}

public class ServerImp
{
IDictionary _config;
public ServerImp(IDictionary theConfig)
{
_config = theConfig;
}

public void start()
{
// ... logics
}

public void stop()
{
// ... logics
}
}

The problem is, the dictionary passed to the constructor is data from an xml config file. (Actually I use a dictionary to make it difficult. Most config data in my case are just simple string or numerics.) In spring.net it's a breath to make it happen. But in NI, it turns out also a easy task:

public class ConfigData
{
public IDictionary dic;
//...
}

public class ServerModule : StandardModule
{
ConfigData _config;
public ServerModule(ConfigData data)
{
_config = data;
}

public override void Load()
{
Bind<IServer>().To<ServerImp>().WithConstructorArgument("theConfig", dic);
}
}

In startup process, I just need to read the config data by deserialize the xml and pass the data to the moduel.

// in main
ConfigData cfg = loadConfigData(); // deserialize xml.
using (IKernel kernel = new StandardKernel(new ServerModule(cfg)))
{
IServer transport = kernel.Get();
transport.start();
transport.stop();
}

And it works!

No comments:

Post a Comment