Skip to content

[.NET Core 3] ApplicationModel finding only in original assembly #15373

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

Closed
wisepotato opened this issue Oct 24, 2019 · 16 comments
Closed

[.NET Core 3] ApplicationModel finding only in original assembly #15373

wisepotato opened this issue Oct 24, 2019 · 16 comments
Assignees
Labels
area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates question
Milestone

Comments

@wisepotato
Copy link

wisepotato commented Oct 24, 2019

Describe the bug

I'm having an issue with the MapControllers method of UseEndpoints.

my thought process:

For the class

Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModel

when injected into the apply method of an IControllerResourceMapping, the controllers that are located on the Controllers property are based on the assembly the dervied Startup file is in (which calls IApplicationBuilder.UseRouting/IApplicationBuilder.UseEndpoints).

I have a TestStartup (assembly B) that extends Startup (assembly A) which calls the IApplicationBuilder.UseRouting/IApplicationBuilder.UseEndpoints behaviour, where UseEndpoints has MapControllers in it.

I only get controllers in assembly B, not the ones in assembly A (the ones i want). Is this expected behaviour?

This behaviour is inside of a framework, will try to get a minimum code sample asap.

Expected behavior

A clear and concise description of what you expected to happen.

Screenshots

If applicable, add screenshots to help explain your problem.

Additional context

A compatible installed .NET Core SDK for global.json version [5.0.100-alpha1-014696] from [C:\Users\x\Documents\git\github\AspNetCore\global.json] was not found
Install the [5.0.100-alpha1-014696] .NET Core SDK or update [C:\Users\xDocuments\git\github\AspNetCore\global.json] with an installed .NET Core SDK:
  2.1.202 [C:\Program Files\dotnet\sdk]
  2.1.400 [C:\Program Files\dotnet\sdk]
  2.1.401 [C:\Program Files\dotnet\sdk]
  2.1.403 [C:\Program Files\dotnet\sdk]
  2.1.500 [C:\Program Files\dotnet\sdk]
  2.1.503 [C:\Program Files\dotnet\sdk]
  2.1.505 [C:\Program Files\dotnet\sdk]
  2.1.509 [C:\Program Files\dotnet\sdk]
  2.1.600-preview-009472 [C:\Program Files\dotnet\sdk]
  2.1.600-preview-009497 [C:\Program Files\dotnet\sdk]
  2.1.800-preview-009696 [C:\Program Files\dotnet\sdk]
  2.2.101 [C:\Program Files\dotnet\sdk]
  2.2.102 [C:\Program Files\dotnet\sdk]
  3.0.100 [C:\Program Files\dotnet\sdk]

Host (useful for support):
  Version: 3.0.0
  Commit:  7d57652f33

.NET Core SDKs installed:
  2.1.202 [C:\Program Files\dotnet\sdk]
  2.1.400 [C:\Program Files\dotnet\sdk]
  2.1.401 [C:\Program Files\dotnet\sdk]
  2.1.403 [C:\Program Files\dotnet\sdk]
  2.1.500 [C:\Program Files\dotnet\sdk]
  2.1.503 [C:\Program Files\dotnet\sdk]
  2.1.505 [C:\Program Files\dotnet\sdk]
  2.1.509 [C:\Program Files\dotnet\sdk]
  2.1.600-preview-009472 [C:\Program Files\dotnet\sdk]
  2.1.600-preview-009497 [C:\Program Files\dotnet\sdk]
  2.1.800-preview-009696 [C:\Program Files\dotnet\sdk]
  2.2.101 [C:\Program Files\dotnet\sdk]
  2.2.102 [C:\Program Files\dotnet\sdk]
  3.0.100 [C:\Program Files\dotnet\sdk]

.NET Core runtimes installed:
  Microsoft.AspNetCore.All 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
@wisepotato wisepotato changed the title ApplicationModel finding only in original assembly [.NET Core 3] ApplicationModel finding only in original assembly Oct 24, 2019
@javiercn javiercn added the area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates label Oct 24, 2019
@javiercn
Copy link
Member

@wisepotato thanks for contacting us.

This is likely due to changes in hosting and the fact that you are using a derived startup class. Check the following:

  • Check the list of application parts and see which parts get listed.
  • Check IHostEnvironment.Name to make sure it has the right value.
  • Try using `webhost.UseSetting(WebHostDefaults.ApplicationKey, "YourWebAppProject")

If you have a standard Program.cs from .net core 3.0 having multiple startups is not going to work well.

    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

In 3.0 the ConfigureServices callback gets queued inmediately when you call UseStartup and the result if you call UseStartup again is that it will queue another ConfigureServices callback from that second Startup class, which will result in both Startup callbacks running, which might not be what you want.

@javiercn javiercn added the Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. label Oct 25, 2019
@wisepotato
Copy link
Author

Any way to have derived startup classes for e2e tests?

I wouldn't want both startup classes to queue ConfigureServices..

@javiercn
Copy link
Member

@wisepotato I'm not sure there's any way with the way the new hosting works, other than passing a flag or similar to the CreateWebHostBuilder method and check that flag to avoid calling UseStartup in the first place.

@davidfowl @Tratcher Thoughts?

@wisepotato
Copy link
Author

To rephrase my question: is my current setup with derived startups the way to go? Is this not common practice? I need different configs for different testing enviornments (disabling middleware, spoofing user authentication, different naming convention for routes etc..)

@maurei
Copy link

maurei commented Oct 28, 2019

Usecase: testing client generated ids in JsonApiDotNetCore (a framework that implements json:api spec). In the codebase we have an example project dedicated to e2e testing. Its default Startup class has the client-generated ids option disabled, and we have a separate startup class ClientGeneratedIdsEnabledStartup that derives from Startup which enables this feature. It is used only for that particular test case.

We can avoid the problem for now by moving ClientGeneratedIdsEnabledStartup to the same assembly as Startup, but this file shouldn't (have to) be in this assembly.

@Tratcher
Copy link
Member

@maurei see Environments https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-3.0

@wisepotato
Copy link
Author

This seems like a mixture of concerns, let's say I have feature switches 1 till 35. Your solution would require me to facilitatie this with:

if(env.IsEnvironment("testing_One"){
     FeatureSwitchOne();
}
if(env.IsEnvironment("testing_Two"){
     FeatureSwitchOne();
}
.
.
.
if(env.IsEnvironment("testing_35"){
     FeatureSwitchThirtyFive();
}

I think environment switching is enough for most people, but If i want to test 1 to 35 with combinations of them, I could in theory have 35*34 = 1190 combinations i would need to clutter my startup.cs with.

So it will not do it for me :(

@Tratcher
Copy link
Member

Or in your dev and test environments you load the individual switches from the dev/test config.

@wisepotato
Copy link
Author

How would I approach that? Maybe this is me misunderstanding but I would like individual tests to be able to set switches, from the test itself.

Is this not common practice? If not, then I guess i'm misunderstanding.

@maurei
Copy link

maurei commented Oct 31, 2019

Tried to use WebApplicationFactory in a test with an external startup class as in dotnet/AspNetCore.Docs#7063 (comment), but the error persists.

@ghost
Copy link

ghost commented Dec 2, 2019

<Deleted by @anurse. We shouldn't be using this flow for issues in Discussions. I'll update the bot.>

@Tratcher
Copy link
Member

Tratcher commented Dec 2, 2019

How would I approach that? Maybe this is me misunderstanding but I would like individual tests to be able to set switches, from the test itself.

Is this not common practice? If not, then I guess i'm misunderstanding.

The theory was to inject IConfiguration into Startup and then have it query configuration keys to enable/disable features. Tests can provide in-memory configuration overrides to toggle individual features.

@analogrelay analogrelay removed the Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. label Dec 2, 2019
@wisepotato
Copy link
Author

So my startup knows about how tests are run? I mean I want to disable the middleware in my tests but I don't want that to EVER happen in production.

Is this really the idea? Because that would mean all the options i want to test/disable in my tests should be checked in my startup, creating a lot of checking and passes. While I could also override it in a clean new startup.

So my question is: why not both ways? I see uses for your version, but my version seems.. cleaner. Maybe I'm mistaken.

@Tratcher
Copy link
Member

Tratcher commented Dec 4, 2019

Startup controls how your app runs in any environment. If you want to provide a different startup for tests, that's up to you.

@wisepotato
Copy link
Author

Startup controls how your app runs in any environment. If you want to provide a different startup for tests, that's up to you.

So thats kind of my point, my test startup has to be in the assembly i'm testing. Not in my testing assembly, where I would expect them to be.

But yeah, that's atleast a start and one way to do it.

@ghost
Copy link

ghost commented Feb 3, 2020

Thank you for contacting us. Due to no activity on this issue we're closing it in an effort to keep our backlog clean. If you believe there is a concern related to the ASP.NET Core framework, which hasn't been addressed yet, please file a new issue.

@ghost ghost closed this as completed Feb 3, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Feb 3, 2020
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates question
Projects
None yet
Development

No branches or pull requests

6 participants