title: .Net Core: How do I initialize a singleton that needs a DBContext?
body: <p>I have a .Net Core service ("MyLookup") that does a database query, some Active Directory lookups, and stores the results to a memory cache.</p>
  
  <p>For my first cut, I did <code>.AddService&lt;&gt;()</code> in Startup.cs, injected the service into the constructors of each of the controllers and views that used the service ... and everything worked.</p>
  
  <p>It worked because my service - and it's dependent services (IMemoryCache and a DBContext) were all <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollectionserviceextensions.addscoped" rel="nofollow noreferrer">scoped</a>.  But now I'd like to make this service a <a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollectionserviceextensions.addsingleton" rel="nofollow noreferrer">singleton</a>.  And I'd like to initialize it (perform the DB query, the AD lookups, and save the result to a memory cache) when the app initializes.</p>
  
  <p>Q: How do I do this?</p>
  
  <p><strong>Startup.cs</strong></p>
  
  <pre><code>    public void ConfigureServices(IServiceCollection services)
      {
          services.AddDbContext&lt;MyDBContext&gt;(options =&gt;
              options.UseSqlServer(Configuration.GetConnectionString("MyDBContext")));
          services.AddMemoryCache();
          services.AddSingleton&lt;IMyLookup, MyLookup&gt;(); 
          ...
      public void Configure(IApplicationBuilder app, IHostingEnvironment env)
      {
          ...
          // Q: Is this a good place to initialize my singleton (and perform the expensive DB/AD lookups?
          app.ApplicationServices.GetService&lt;IDILookup&gt;();   
  </code></pre>
  
  <p><strong>OneOfMyClients.cs</strong></p>
  
  <pre><code>    public IndexModel(MyDBContext context, IMyLookup myLookup)
      {
          _context = context;
          _myLookup = myLookup;
          ...
  </code></pre>
  
  <p><strong>MyLookup.cs</strong></p>
  
  <pre><code>public class MyLookup : IMyLookup
      ...
      public MyLookup (IMemoryCache memoryCache)
      {
          // Perform some expensive lookups, and save the results to this cache
          _cache = memoryCache;  
      }
      ...
      private async void Rebuild()  // This should only get called once, when app starts
      {
          ClearCache();
          var allNames =  QueryNamesFromDB();
          ...
  
      private List&lt;string&gt;QueryNamesFromDB()
      {
          // Q: ????How do I get "_context" (which is a scoped dependency)????
          var allNames = _context.MyDBContext.Select(e =&gt; e.Name).Distinct().ToList&lt;string&gt;();
          return allSInames;
  </code></pre>
  
  <p>Some of the exceptions I've gotten trying different things:</p>
  
  <blockquote>
    <p>InvalidOperationException: Cannot consume scoped service 'MyDBContext' from singleton 'MyLookup'.</p>
  </blockquote>
  
  <p>... and ...</p>
  
  <blockquote>
    <p>InvalidOperationException: Cannot resolve scoped service 'MyDBContext' from root provider 'MyLookup'</p>
  </blockquote>
  
  <p>... or ...</p>
  
  <blockquote>
    <p>System.InvalidOperationException: Cannot resolve scoped service 'IMyLookup' from root provider.</p>
  </blockquote>
  
  <hr>
  
  <p>Thanks to <a href="https://stackoverflow.com/users/264697/steven">Steve</a> for much valuable insight.  I was finally able to:</p>
  
  <ol>
  <li><p>Create a "lookup" that could be used by any consumer at any time, from any session, during the lifetime of the app.</p></li>
  <li><p>Initialize it once, at program startup.
  FYI, it would <em>NOT</em> be acceptable to defer initialization until some poor user triggered it - the initialization simply takes too long.</p></li>
  <li><p>Use dependent services (IMemoryCache and my DBContext), regardless of those services' lifetimes.</p></li>
  </ol>
  
  <p>My final code:</p>
  
  <p><strong>Startup.cs</strong></p>
  
  <pre><code>public void ConfigureServices(IServiceCollection services)
  {
      services.AddDbContext&lt;MyDBContext&gt;(options =&gt;
          options.UseSqlServer(Configuration.GetConnectionString("MyDBContext")));
      services.AddMemoryCache();
      // I got 80% of the way with .AddScoped()...
      // ... but I couldn't invoke it from Startup.Configure().
      services.AddSingleton&lt;IMyLookup, MyLookup&gt;(); 
      ...
  
  public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  {
      // This finally worked successfully...
      app.ApplicationServices.GetService&lt;IMyLookup&gt;().Rebuild();
  </code></pre>
  
  <p><strong>OneOfMyClients.cs</strong></p>
  
  <pre><code>public IndexModel(MyDBContext context, IMyLookup myLookup)
  {
      // This remained unchanged (for all consumers)
      _context = context;
      _myLookup = myLookup;
      ...
  </code></pre>
  
  <p><strong>MyLookup.cs</strong></p>
  
  <pre><code>public interface IMyLookup
  {
      Task&lt;List&lt;string&gt;&gt; GetNames(string name);
      Task Rebuild();
  }
  
  public class MyLookup : IMyLookup
  {
      private readonly IMemoryCache _cache;
      private readonly IServiceScopeFactory _scopeFactory;
      ...
  
      public MyLookup (IMemoryCache memoryCache, IServiceScopeFactory scopeFactory)
      {
          _cache = memoryCache;
          _scopeFactory = scopeFactory;
      }
  
      private async void Rebuild()
      {
          ClearCache();
          var allNames =  QueryNamesFromDB();
          ...
  
      private List&lt;string&gt;QueryNamesFromDB()
      {
          // .CreateScope() -instead of constructor DI - was the key to resolving the problem
          using (var scope = _scopeFactory.CreateScope())
          {
              MyDBContext _context =
                  scope.ServiceProvider.GetRequiredService&lt;MyDBContext&gt;();
              var allNames = _context.MyTable.Select(e =&gt; e.Name).Distinct().ToList&lt;string&gt;();
              return allNames;
          }
      }
  </code></pre>