title: Discovering Generic Controllers in ASP.NET Core
body: <p>I am trying to create a generic controller like this:</p>
  
  <pre><code>[Route("api/[controller]")]
  public class OrdersController&lt;T&gt; : Controller where T : IOrder
  {
      [HttpPost("{orderType}")]
      public async Task&lt;IActionResult&gt; Create(
          [FromBody] Order&lt;T&gt; order)
      {
         //....
      }
  }
  </code></pre>
  
  <p>I intend for the {orderType} URI segment variable to control the generic type of the controller.  I'm experimenting with both a custom <code>IControllerFactory</code> and <code>IControllerActivator</code>, but nothing is working.  Every time I try to send a request, I get a 404 response.  The code for my custom controller factory (and activator) is never executed.  </p>
  
  <p>Evidently the problem is that ASP.NET Core expects valid controllers to end with the suffix "Controller", but my generic controller instead has the (reflection based) suffix "Controller`1".  Thus the attribute-based routes it declares are going unnoticed.</p>
  
  <p>In ASP.NET MVC, at least in its early days, <a href="https://msdn.microsoft.com/en-us/magazine/dd695917.aspx" rel="noreferrer">the <code>DefaultControllerFactory</code> was responsible for discovering all the available controllers</a>.  It tested for the "Controller" suffix:</p>
  
  <blockquote>
    <p>The MVC framework provides a default controller factory (aptly named DefaultControllerFactory) that will search through all the assemblies in an appdomain looking for all types that implement IController and whose name ends with "Controller."</p>
  </blockquote>
  
  <p>Apparently, in ASP.NET Core, the controller factory no longer has this responsibility.  As I stated earlier, my custom controller factory executes for "normal" controllers, but is never invoked for generic controllers.  So there is something else, earlier in the evaluation process, which governs the discovery of controllers.</p>
  
  <p>Does anyone know what "service" interface is responsible for that discovery?  I don't know the customization interface or "hook" point.</p>
  
  <p>And does anyone know of a way to make ASP.NET Core "dump" the names of all the controllers it discovered?  It would be great to write a unit test that verifies that any custom controller discovery I expect is indeed working.</p>
  
  <p>Incidentally, if there is a "hook" which allows generic controller names to be discovered, it implies that route substitutions must also be normalized:</p>
  
  <pre><code>[Route("api/[controller]")]
  public class OrdersController&lt;T&gt; : Controller { }
  </code></pre>
  
  <p>Regardless of what value for <code>T</code> is given, the [controller] name must remain a simple base-generic name.  Using the above code as an example, the [controller] value would be "Orders".  It would not be "Orders`1" or "OrdersOfSomething".</p>
  
  <h2>Note</h2>
  
  <p>This problem could also be solved by explicitly declaring the closed-generic types, instead of generating them at run time:</p>
  
  <pre><code>public class VanityOrdersController : OrdersController&lt;Vanity&gt; { }
  public class ExistingOrdersController : OrdersController&lt;Existing&gt; { }
  </code></pre>
  
  <p>The above works, but it produces URI paths that I don't like:</p>
  
  <pre><code>~/api/VanityOrders
  ~/api/ExistingOrders
  </code></pre>
  
  <p>What I had actually wanted was this:</p>
  
  <pre><code>~/api/Orders/Vanity
  ~/api/Orders/Existing
  </code></pre>
  
  <p>Another adjustment gets me the URI's I'm looking for:</p>
  
  <pre><code>[Route("api/Orders/Vanity", Name ="VanityLink")]
  public class VanityOrdersController : OrdersController&lt;Vanity&gt; { }
  [Route("api/Orders/Existing", Name = "ExistingLink")]
  public class ExistingOrdersController : OrdersController&lt;Existing&gt; { }
  </code></pre>
  
  <p>However, although this appears to work, it does not really answer my question.  I would like to use my generic controller directly at run-time, rather than indirectly (via manual coding) at compile-time.  Fundamentally, this means I need ASP.NET Core to be able to "see" or "discover" my generic controller, despite the fact that its run-time reflection name does not end with the expected "Controller" suffix.</p>