I have created a generic type
public interface IContext<T> {}
And, I have a type implemented that (with a constructor with parameters)
public class Context<T> : IContext<T>
{
public Context(string url, string key)
{
}
...
}
I want to register with simple injector. With the below code, I dont know how to pass the values for the constructor
container.Register(typeof(IContext<>), typeof(Context<>))
This one shows a way if I have a type passed in the constructor parameter. However, for me its primitive types only. Looks like by overriding construction resolution behaviour I may achieve this. But, dont really get the idea of how shall I leverage it. Can someone guide me to find an appropriate way to register this?
When dealing with primitive dependencies into an open-generic registration, the typical solution is to extract the set of configuration value(s) into a DTO and inject that DTO into the type's constructor; this allows you to register that new configuration object as singleton into the container:
I have created a generic type
public interface IContext {}
And, I have a type implemented that (with a constructor with parameters)
public class ContextConfiguration
{
public readonly string Url;
public readonly string Key;
public ContextConfiguration(string url, string key) { ... }
}
public class Context<T> : IContext<T>
{
public Context(ContextConfiguration config)
{
}
...
}
// Configuration
container.RegisterSingleton(new ContextConfiguration(...));
container.Register(typeof(IContext<>), typeof(Context<>));
In case you can't change the constructor of that type, you create a sub class of that type that you place inside the Composition Root. This sub type again uses this configuration DTO:
// Part of the Composition Root
private class ContextConfiguration
{
public readonly string Url;
public readonly string Key;
public ContextConfiguration(string url, string key) { ... }
}
private class CompositionRootContext<T> : Context<T>
{
public Context(ContextConfiguration config) : base(config.Url, config.Key)
{
}
...
}
// Configuration
container.RegisterSingleton(new ContextConfiguration(...));
container.Register(typeof(IContext<>), typeof(CompositionRootContext<>));
If that Context<T>
is sealed, you could override the parameter injection behavior, but in general, in that case you are dealing with a type that is defined by an external library. For external types it is generally better to hide them behind an application-tailored abstraction (according to the DIP). Instead of letting application code depend on IContext<T>
, you let the application depend on an interface that is defined by the application. As part of your Composition Root, you would implement an Adapter that adapts the application-specific interface to Context<T>
. The constructor of that adapter would -again- be able to use this configuration DTO.