Specify contructor arguments

Dec 10, 2012 at 3:43 PM

Hi, SimpleInjector is very nice Ioc/DI container!

Is the way to specify contructor arguments by name? For example service class:

 

public class Service : IService
{
    public Service(IOtherService service, string someText)
    {
        ...
    }
}

I would like to register IService with specifing "someText" argument for creating Service instance. Is the way to do this?

Thanks!

 

Coordinator
Dec 10, 2012 at 10:01 PM

There is no built-in way to mix automatic constructor injection and manual constructor dependencies in Simple Injector. There are ways to do this though, but you might want to review your design first. Although there are very legitimate reasons to want this, often the application is missing an abstraction somewhere.

Compared to injecting interfaces, injecting primitives is rather problematic for a DI container. A DI container likes to map types and primitive types such as Int32 and String tend to be ambiguous. When you have multiple services that take a dependency on string, it is unlikely that each service need to have the same piece of text injected. It is very likely that some types need a connection string, while others need some sort of path, etc. It is therefore impossible to register that piece of text once and let that single value be resolved any time a string type is needed by some service in the application.

Because of this ambiguity it’s impossible to make a single registration for this string type. What you will end up with is some custom registration on a per service basis. Each DI framework has its own way of ‘overriding’ this dependency on a per-service basis. But no matter what framework you pick, you’ll end up with a DI configuration that is much harder to understand, and harder to maintain. When you have many services in the system that take a dependency on a primitive type, it is time to look closely at the design.

For instance, when you have many services in the system that need a connection string; you are probably missing an abstraction. Say for instance you have repository interfaces such as IUserRepository, ICustomerRepository, IOrderRepository, etc. Instead of injecting a connection string in each of them, you should be injecting a IDatabaseConnectionFactory, or IConnectionManager into each of them. The connection string would in that case be hidden behind the IConnectionManager implementation which is unambiguous. The connection string would still be injected as follows:

public class SqlConnectionManager : IConnectionManager
{
    public SqlConnectionManager(string connectionString) { … }
}

This SqlConnectionManager would ideally have nothing more than primitive dependencies, or when it has, this will be the only class to inject the connection string into. In fact, in most cases primitives are configuration values and they can often be hidden behind an abstraction.

What will be left is a small set of classes that wrap those configuration values. There are multiple ways to register those types. You can register a delegate that manually creates that type:

container.Register<IConnectionManager>(
    () => new SqlConnectionManager(“myConStr”));

When this type has other dependencies, you can inject those types in the constructor as well:

container.Register<IConnectionManager>(() => 
    new SqlConnectionManager(
        container.GetInstance<IOtherDependency>(),
        “myConStr”));

Downside of this is that this configuration needs to be changed, every time the constructor of this type changes. So another option is to use property injection:

public class SqlConnectionManager : IConnectionManager
{
    public SqlConnectionManager(IOtherDependency dep) { … }

    public string ConnectionString { get; set; }
}


You can wire this as follows:

container.Register<IConnectionManager, SqlConnectionManager >();

container.RegisterInitializer<SqlConnectionManager>(instance =>
{
    instance.ConnectionString = “myConStr”;
});

Generally I advice to avoid mixing primitives and services in a service’s constructor, because this makes the configuration much harder (no matter which framework you use). For this reason Simple Injector lacks a built-in API to do this. Instead add a new abstraction, register a delegate, or promote the dependency to property. There is however a way to add such feature on top of the core library and that’s by changing the container’s default Constructor Injection Behavior. The following blog post describes how to do this Primitive Dependencies with the Simple Injector.

I hope this gives you some food for thoughts.

Marked as answer by dot_NET_Junkie on 11/4/2013 at 2:04 AM
Dec 11, 2012 at 3:40 AM

Thank you, I totally agree with you

Feb 14, 2014 at 10:14 AM
Hi,

I've been reading this and I'm close to what I want, so far I have:

var webLifeStyle = new WebRequestLifestyle();
container.Register<IDatabaseFactory>(()=> new DatabaseFactory(connectionString));


but I don't know how to assign the lifestyle to this registration as well as passing in the connection string.
Coordinator
Feb 14, 2014 at 11:03 AM
Mi Matt,

Registering the factory delegate with a alternative lifestyle can be done by calling the Register<T> overload that accepts the Lifestyle:
container.Register<IDatabaseFactory>(() => new DatabaseFactory(connectionString), webLifeStyle);
Or alternatively, you can use the RegisterPerWebRequest<T> extension method:
container.RegisterPerWebRequest<IDatabaseFactory>(() => new DatabaseFactory(connectionString));
This extension method simply shortcuts to the Register<T> by supplying a WebRequestLifestyle.