TMiNus
TMiNus

Reputation: 33

Delay creation of instance in Simple Injector

I am using Simple Injector in my project to hook up all the required dependencies, but I cannot call container.Verify because it creates a Singleton instance for an http configuration before the actual first request

public interface IConfiguration { }
public class Configuration : IConfiguration
{
    public Configuration()
    {
        var httpContext = HttpContext.Current;
        var httpRequest = currentHttpContext.Request;
        var httpRequestUrl = currentHttpRequest.Url;

        this.UriScheme = currentHttpRequestUrl.Scheme;
        this.UriHost = currentHttpRequestUrl.Host;
        this.UriPort = currentHttpRequestUrl.Port;
    }

    public string UriScheme { get; private set; }
    public string UriHost { get; private set; }
    public int UriPort { get; private set; }
}

public class ServiceA
{
    private readonly _configuration;

    public ServiceA(IConfiguration configuration) 
    {
        _configuration = configuration 
    }
}

public class ServiceB
{
    private readonly _configuration;

    public ServiceB(IConfiguration configuration) 
    {
        _configuration = configuration
    }
}

This is a basic example of the scenario. I currently have around 60 services all depending on IConfiguration

All the configuration needs to happen when the configuration class is created

This is what I do to register the instances in the container

var container = new Container();

//container.RegisterSingleton<IConfiguration, Configuration>();

var lazy = new Lazy<InstanceProducer>(() =>
    Lifestyle.Singleton.CreateProducer(typeof(IConfiguration), typeof(Configuration), container));

container.Register<ServiceA>();
container.Register<ServiceB>();

container.Verify(); // Creates configuration class --> not desired

As per How can I skip verification of an object in the container

So the trick here is to trigger the creation of new InstanceProducer instances after the verification process

I know the workaround is using Lazy<T> and InstanceCreator but I cannot finish hooking my code correctly

EDIT

The Configuration class has no dependencies. The problem with Configuration is that it gets created as a Singleton on the container.Verify method call and at that time the currentHttpRequest.Url is not the actual url

I suppose I can move the configuration from the constructor to a method (e.g GetConfiguration) and do some refactoring but I am curious if delaying the instance creation can be achieved under the scenario of the question

Upvotes: 2

Views: 478

Answers (1)

Steven
Steven

Reputation: 172606

As explained by Mark Seemann in this article, injection constructors should be simple and reliable. They shouldn't do anything that might cause it to fail. Calling HttpContext.Current inside the constructor makes it unreliable, since this is something that might fail.

Besides this, your Configuration component now depends upon runtime data (the HttpContext.Current is runtime data), which is a sin, as explained in this article.

The solution to your problem however is really simple and straightforward. Just change your Configuration class to the following:

public sealed class Configuration : IConfiguration
{
    public string UriScheme => this.Url.Scheme;
    public string UriHost => this.Url.Host;
    public int UriPort => this.Url.Port;
    private Uri Url => HttpContext.Current.Request.Url;
}

Not only does this simplify things, it also removes the anti-patterns that you were applying which caused you trouble. Your constructor is now so simple, that it isn't even there anymore (can't get any simpler than this). And the runtime data is now only requested (from HttpContext.Current) after the object graph is constructed. This allows the container to verify its configuration reliably.

Upvotes: 3

Related Questions