Search code examples
c#asp.net-coreattributerouting

AspNet Core AttributeRouting does not discover routes if Startup is in different assembly


I have a scenario where we have a "standardised startup" for many small AspNet Core websites.

A seemingly obvious solution to achieve this is to refactor the Startup.cs class into a separate common assembly (as Infrastructure.Web.Core.Startup). We then have each small AspNet Core website reference it the common assembly and use that startup class instead:

        public static Microsoft.AspNetCore.Hosting.IWebHostBuilder CreateWebHostBuilder( string[] args )
        {
            return new WebHostBuilder()
                   .UseKestrel()
                   .ConfigureServices( collection => { } )
                   .UseContentRoot( System.IO.Directory.GetCurrentDirectory() )
                   .UseStartup<Infrastructure.Web.Core.Startup>(); //.UseStartup<Startup>();
        }

Somehow, this breaks attribute routing in the sense that the routes are not hit. No errors, but not routing. The moment I copy the class back into the website project (with the exact same code) it works again.

As a test, if I wrap the Startup.cs class in the common library in a local startup class (like below), it also works:

    public class Startup
    {
        private readonly Infrastructure.Web.Core.Startup _startup;

        public Startup( IConfiguration configuration )
        {
            _startup = new Infrastructure.Web.Core.Startup( configuration );
        }

        public IConfiguration Configuration => _startup.Configuration;

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices( IServiceCollection services )
        {
            _startup.ConfigureServices( services );
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure( IApplicationBuilder app, IHostingEnvironment env )
        {
            _startup.Configure( app, env );
        }
    }

If I had to take a guess, it's probably something to do with the Dependency Injection.

Does anyone have any suggestions?

FYI: It's using typical AspNet Core 2.1 projects

UPDATE Incidentally, if I use inheritance it also works but the derived class must be in the same project as the website. I guess it seems obvious, but thought I include that information for completeness sake:

    public class Startup : Infrastructure.Web.Core.Startup
    {
        public Startup( IConfiguration configuration ) : base(configuration)
        {
        }
    }

Solution

  • You can fix this by adding the following statement to your services in your Startup.cs method.

    services.AddApplicationPart(typeof(AnTypeInTheOtherAssembly).Assembly);
    

    This will tell the View/Controller Discovery to also check for the new location. Your Project which contains the Startup.cs file would be the Startup Project, and all the others would be just references and libraries or similar.

    As of .Net Core 3 you can use something called Razor Class Libraries, see the MSDN. This will automatically add this your Controllers and Views to the discovery, it also has debugging support and will work just as a normal Class Library would.