title: Classes with runtime parameters built by custom factories: how to honor container lifetime using .NET Core DI?
body: <p>Given some class that relies on a constructor parameter that can only be obtained at runtime, how do I ensure instances of that class have their lifetimes still be controlled by the Microsoft DI container if I'm using a custom factory to bypass the runtime parameter limitation?</p>
  <p>For example, say we have a interface/class pair such as:</p>
  <pre class="lang-cs prettyprint-override"><code>interface IFooService
  {
      void DoServicyStuff();
  }
  
  class MyFooService
  {
      public MyFooService(string somePeskyRuntimeArgument)
      {
          this.peskyValue = somePeskyRuntimeArgument;
      }
  
      void DoServicyStuff()
      {
          // do some stuff here with the peskyValue...
      }
  }
  </code></pre>
  <p>The most common practice to deal with these types of runtime parameters is to build a factory class to basically <em>transfer the parameter from the constructor to a method</em>:</p>
  <pre class="lang-cs prettyprint-override"><code>interface IFooServiceFactory
  {
      IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter);
  }
  
  class FooServiceFactory
  {
      public IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
      {
          return new MyFooService(heyItsNowAMethodLevelPeskyParameter);
      }
  }
  </code></pre>
  <p>The factory then allows us to provide the value at runtime to create the service and then use the service. There is a problem however: the factory takes full ownership of creating the value, <em>including its lifetime</em>.</p>
  <p>Now, what if I want <code>IFooService</code> instance to be scoped to the current request, the equivalent of the <code>Scoped</code> lifetime in the container?</p>
  <p>If <code>IFooService</code> is resolved directly from the container, this is straightforward:</p>
  <pre class="lang-cs prettyprint-override"><code>services.AddScoped&lt;IFooService, MyFooService&gt;()
  </code></pre>
  <p>However, we <em>cannot</em> resolve it directly from the container because of the runtime argument. .NET Core's container abstraction allows us to <em>build</em> an instance with runtime parameters, but then the container registration lifetime is not honored and it only works on concrete types.</p>
  <p>The following doesn't work, because <code>IFooService</code> is not a concrete type:</p>
  <pre class="lang-cs prettyprint-override"><code>class FooServiceFactory
  {
      private readonly IServiceProvider serviceProvider;
  
      public FooServiceFactory(IServiceProvider serviceProvider)
      {
          this.serviceProvider = serviceProvider
      }
  
      public IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
      {
          return ActivatorUtilities.CreateInstance&lt;IFooService&gt;(
              this.serviceProvider, 
              heyItsNowAMethodLevelPeskyParameter);
      }
  }
  </code></pre>
  <p>And this also doesn't work, because <code>FooService</code> is always created regardless of the setup in the container:</p>
  <pre class="lang-cs prettyprint-override"><code>class FooServiceFactory
  {
      private readonly IServiceProvider serviceProvider;
  
      public FooServiceFactory(IServiceProvider serviceProvider)
      {
          this.serviceProvider = serviceProvider
      }
  
      public IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
      {
          return ActivatorUtilities.CreateInstance&lt;MyFooService&gt;(
              this.serviceProvider, 
              heyItsNowAMethodLevelPeskyParameter);
      }
  }
  </code></pre>
  <p>Even if <code>MyFooService</code> is directly registered in the container (without its interface), <code>ActivatorUtilities</code> will <em>still</em> ignore the registration and just create a new one every time it is called.</p>
  <p>How can I rely on the container lifetime handling mechanism while still working with a factory like this to resolve a class that requires runtime parameters? If the parameter value doesn't change across multiple calls in the same request, then it should respect whatever is configured in the container, be it Scoped, Singleton, Transient, etc.</p>