1

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?

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the insights Steven. I think I can create a DTO as suggested by you. However, why would I register it as singleton? Cant I pass parameters during runtime? (My requirement also is to pass them during runtime)
@AthiS: Ah, that was some crucial information missing from your question. The values are runtime _data. Please read this article. It describes how to handle runtime data.
Interesting read Steven. With your inputs I have changed the design so that run time data wont get passed thru the constructor

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.