New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moving Startup class to a library project breaks my site. #903

Closed
Eilon opened this Issue Dec 20, 2016 · 13 comments

Comments

Projects
None yet
7 participants
@Eilon
Member

Eilon commented Dec 20, 2016

From @sam-wheat on December 19, 2016 21:43

This question refers to beta I am using .net core 1.1:
http://stackoverflow.com/questions/33183357/move-startup-cs-to-class-library-package-project-asp-net-5

I moved my Startup class to a library project and now my site does not work. Only error I get is 404.
I checked ContentRootPath and it appears to point to the correct directory.
I see no errors in the output window.
IIS Express says my site is running on the correct port specified in launchSettings.json.
Startup class is exactly the same in library project as site project. Only difference is namespsce.
I don't believe my question is environment related:
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/startup?highlight=startup#the-startup-class

Program.cs:

public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            //.UseStartup<xStartup>() works
            .UseStartup<Application.AppComponents.Startup>() // broken
            .Build();

        host.Run();
    }

Startup.cs (exactly the same in library / application projects):

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddMvc();
        // Autofac

        ContainerBuilder builder = new ContainerBuilder();
        builder.RegisterModule(new Application.AppComponents.IOCModule());

        builder.Populate(services);
        var container = builder.Build();
        return container.Resolve<IServiceProvider>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseMvc();
    }
}

Copied from original issue: aspnet/Mvc#5623

@Tratcher

This comment has been minimized.

Member

Tratcher commented Dec 21, 2016

If you run it without IIS Express what do you see in the console logs?

@sam-wheat

This comment has been minimized.

sam-wheat commented Dec 24, 2016

//.UseIISIntegration()

Same chatter about loading symbols. No error messages from build or Debug.

@davidfowl

This comment has been minimized.

Member

davidfowl commented Dec 24, 2016

It's not an exception, it's just that something is returning 404 right? What request is returning a 404 that shouldn't be? You said you checked the content root, can you double check? Is it razor views that can't be found? If you turn logging up to the debug level:

loggerFactory.AddConsole(LogLevel.Debug);
@davidfowl

This comment has been minimized.

Member

davidfowl commented Dec 24, 2016

Also change the run tab in visual studio to pick the application instead of IIS express. This will run on Kestrel directly:

image

@sam-wheat

This comment has been minimized.

sam-wheat commented Dec 24, 2016

It's not an exception, it's just that something is returning 404 right?
Correct.

What request is returning a 404 that shouldn't be?
Every request.

You said you checked the content root, can you double check?
Looked at env.ContentRootPath in a watch window and it is correct.

Is it razor views that can't be found?
No, .html page.

I think I misunderstood Tratcher's question about running without IIS Express.

When running under kestrel and startup is in library project:

dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[3]
	  Hosting starting
dbug: Microsoft.AspNetCore.Hosting.Internal.WebHost[4]
	  Hosting started
Hosting environment: Development
Content root path: C:\Git\AdaptiveClientDemo\AdaptiveClientDemo\src\RESTServer
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
dbug: Microsoft.AspNetCore.Server.Kestrel[1]
	  Connection id "0HL1C2L6N3NVR" started.
dbug: Microsoft.AspNetCore.Server.Kestrel[1]
	  Connection id "0HL1C2L6N3NVS" started.
dbug: Microsoft.AspNetCore.Server.Kestrel[6]
	  Connection id "0HL1C2L6N3NVR" received FIN.
dbug: Microsoft.AspNetCore.Server.Kestrel[10]
	  Connection id "0HL1C2L6N3NVR" disconnecting.
dbug: Microsoft.AspNetCore.Server.Kestrel[7]
	  Connection id "0HL1C2L6N3NVR" sending FIN.
dbug: Microsoft.AspNetCore.Server.Kestrel[8]
	  Connection id "0HL1C2L6N3NVR" sent FIN with status "0".
dbug: Microsoft.AspNetCore.Server.Kestrel[2]
	  Connection id "0HL1C2L6N3NVR" stopped.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
	  Request starting HTTP/1.1 GET http://localhost:5000/api/values/index
dbug: Microsoft.AspNetCore.Builder.RouterMiddleware[1]
	  Request did not match any routes.
dbug: Microsoft.AspNetCore.Server.Kestrel[9]
	  Connection id "0HL1C2L6N3NVS" completed keep alive response.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
	  Request finished in 305.7897ms 404

When running under kestrel and startup is in app project:

Hosting environment: Development
Content root path: C:\Git\AdaptiveClientDemo\AdaptiveClientDemo\src\RESTServer
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
	  Request starting HTTP/1.1 GET http://localhost:5000/api/values/index
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
	  Executing action method RESTServer.Controllers.ValuesController.Index (RESTServer) with arguments ((null)) - ModelState is Valid
info: Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ViewResultExecutor[1]
	  Executing ViewResult, running view at path /Project_Readme.html.
info: Microsoft.Extensions.DependencyInjection.DataProtectionServices[0]
	  User profile is available. Using 'C:\Users\Sam\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
	  Executed action RESTServer.Controllers.ValuesController.Index (RESTServer) in 1971.8227ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
	  Request finished in 2371.1935ms 200 text/html; charset=utf-8
@sam-wheat

This comment has been minimized.

sam-wheat commented Dec 24, 2016

I imagine you guys will want to see project.json:

Web app project:

{
  "dependencies": {
	"Autofac": "4.2.1",
	"Autofac.Extensions.DependencyInjection": "4.0.0",
	"Microsoft.AspNetCore.Mvc": "1.1.0",
	"Microsoft.AspNetCore.Routing": "1.1.0",
	"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
	"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
	"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
	"Microsoft.Extensions.Configuration.FileExtensions": "1.1.0",
	"Microsoft.Extensions.Configuration.Json": "1.1.0",
	"Microsoft.Extensions.Logging": "1.1.0",
	"Microsoft.Extensions.Logging.Console": "1.1.0",
	"Microsoft.Extensions.Logging.Debug": "1.1.0",
	"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
	"Microsoft.NETCore.App": {
	  "type": "platform",
	  "version": "1.1.0"
	},
	"Application.Domain": { "target": "project" },
	"Application.Model": { "target": "project" },
	"Application.Services": { "target": "project" },
	"Application.AppComponents": { "target": "project" },
	"LeaderAnalytics.AdaptiveClient": "0.0.4"
  },

  "tools": {
	"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
  },

  "frameworks": {
	"netcoreapp1.1": {
	  "imports": [
		"dotnet5.6",
		"portable-net45+win8"
	  ]
	}
  },

  "buildOptions": {
	"emitEntryPoint": true,
	"preserveCompilationContext": true
  },

  "runtimeOptions": {
	"configProperties": {
	  "System.GC.Server": true
	}
  },

  "publishOptions": {
	"include": [
	  "wwwroot",
	  "**/*.cshtml",
	  "appsettings.json",
	  "web.config"
	]
  },

  "scripts": {
	"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  }
}

Library project:

{
  "version": "1.0.0-*",

  "dependencies": {
	"Autofac": "4.2.1",
	"Autofac.Extensions.DependencyInjection": "4.0.0",
	"NETStandard.Library": "1.6.1",
	"Microsoft.AspNetCore.Mvc": "1.1.0",
	"Microsoft.DotNet.InternalAbstractions": "1.0.0",
	"Microsoft.AspNetCore.Routing": "1.1.0",
	"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
	"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
	"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
	"Microsoft.Extensions.Configuration.FileExtensions": "1.1.0",
	"Microsoft.Extensions.Configuration.Json": "1.1.0",
	"Microsoft.Extensions.Logging": "1.1.0",
	"Microsoft.Extensions.Logging.Console": "1.1.0",
	"Microsoft.Extensions.Logging.Debug": "1.1.0",
	"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
	"NLog": "5.0.0-beta03",
	"Application.Core": { "target": "project" },
	"Application.Domain": { "target": "project" },
	"Application.Model": { "target": "project" },
	"Application.Services": { "target": "project" },
	"Application.RESTClient": { "target": "project" },
	"Application.WCFClient": { "target": "project" },
	"LeaderAnalytics.AdaptiveClient": "0.0.4"
  },
  "frameworks": {
	"net462": {
	  "dependencies": {
	  }
	},
	"netstandard1.6": {
	  "imports": [ "dnxcore50" ]
	}
  }
}
@Tratcher

This comment has been minimized.

Member

Tratcher commented Dec 24, 2016

@rynowak Does the MVC controller discovery take into account the location of the Startup class?

@davidfowl

This comment has been minimized.

Member

davidfowl commented Dec 24, 2016

Yes, it does. Specifically, it uses the ApplicationName as the "entry point" assembly. The controller scan starts from that "root" assembly.

@sam-wheat Do you have the Startup in a class library and the Controllers in another class library?

@sam-wheat

This comment has been minimized.

sam-wheat commented Dec 24, 2016

OMG you guys are working on Christmas Eve! Merry Christmas!

Do you have the Startup in a class library and the Controllers in another class library?
No, controllers are in web app.

@davidfowl

This comment has been minimized.

Member

davidfowl commented Dec 24, 2016

You can workaround it by doing the following in Program.cs

public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Application.AppComponents.Startup>() 
            .UseSetting(WebHostDefaults.ApplicationKey, typeof(Program).GetTypeInfo().Assembly.FullName) // Ignore the startup class assembly as the "entry point" and instead point it to this app
            .Build();

        host.Run();
    }
@sam-wheat

This comment has been minimized.

sam-wheat commented Dec 25, 2016

Works, thank you!

@muratg muratg closed this Jan 10, 2017

@memark

This comment has been minimized.

memark commented Sep 24, 2017

I ran into this today, in my case because I had an alternate Startup class in my test assembly. Great workaround @davidfowl!

@jayoma

This comment has been minimized.

jayoma commented Aug 22, 2018

Thank you @davidfowl! I've been chasing this issue all day (I'm using an alternate Startup class for my tests like @memark), and your suggestion was the answer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment