8

I have the following code:

public void ConfigureServices(IServiceCollection services)
{
   services.AddOptions();

   services.Configure<MyConfig>(Configuration.GetSection("MySection"));
   services.AddSingleton<IMyClass>(sp => new MyClass(sp.GetService<IOptions<MyConfig>>()));
}

This registers a singleton for MyClass and now I can have my controllers take a constructor argument of type IMyClass. This works as intended.

The MyClass is only instantiated first when a controller requires an IMyClass. However, I would like MyClass to be instantiated before anyone ever asks for it (since it does some work in it's constructor that takes a little while).

I could do something like:

public void ConfigureServices(IServiceCollection services)
{
   services.AddOptions();

   services.Configure<MyConfig>(configuration.GetSection("MySection"));

   var myinstance = new MyClass(/*...*/);  // How do I get MyConfig in here?
   services.AddSingleton<IMyClass>(myinstance);
}

...but then I can't get to the configuration since I don't have a reference to an IServiceProvider (The sp variable in the first code example). How do I get to the sericeprovider or what would I have to do to make sure the instance is initialized as soon as possible?

2
  • 4
    "since it does some work in its constructor that takes a while" - This should probably be the thing you try to fix. Why does it take a while? Constructors should be fast, they shouldn't call out to outside systems, and they shouldn't fail. Commented Oct 2, 2018 at 16:55
  • @mason It builds an internal "lookup table" that takes some time. It doesn't call to outside systems and it won't fail. It just needs to crunch some data. And since it's a singleton it doesn't matter if it's slow(-ish) since it will only be slow(-ish) once. I could also do the work in some "Initialize()" method instead of the constructor or something but either way the work needs to be/get done and I want it to be done ASAP (on startup) instead of on the first request. Commented Oct 2, 2018 at 16:57

2 Answers 2

4

In that case there really was no need for the IOptions<T> as you could extract the config and pass it directly to your class, but if you insist on using options, you can use the OptionsWrapper<TOptions> Class

IOptions wrapper that returns the options instance.

and pass that to your instance

// How do I get MyConfig in here?
MyConfig myConfig = configuration.GetSection("MySection").Get<MyConfig>();    
var wrapper = new OptionsWrapper<MyConfig>(myConfig);
var myinstance = new MyClass(wrapper);  
services.AddSingleton<IMyClass>(myinstance);

extracting your settings from configuration for the wrapper.

Reference Configuration in ASP.NET Core: Bind to an object graph

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

2 Comments

Thanks! I rewrote the MyClass constructor to take a MyConfig instead of IOptions<MyConfig> and used it without the OptionsWrapper. I didn't know about the Get<T>() extensionmethod! Thanks!
@RobIII included a link to the documentation
3

If your main goal is to instantiate the class before it's required by any controller, you can request it in the Configure method in Startup.cs, which leaves your registrations clean, but ensures that it will be initialized.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IMyClass myClass)
{
  myClass.Initialize();
}

Depending on why you need it to be instantiated, you might also want to check out IApplicationLifetime if you need to connect to a push service on application start or something of that nature.

applicationLifetime.ApplicationStarted.Register(() => myConnection.Connect());
applicationLifetime.ApplicationStopping.Register(() => myConnection.Disconnect());

Comments

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.