-
Notifications
You must be signed in to change notification settings - Fork 10.1k
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
Implement package testing in ASP.NET Core repo #46683
Comments
Downgrading the HealthChecks packages worked for me <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Version="6.0.14" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="6.0.14" /> |
Thanks for the repro. You're issue seems to be mainly that you're mixing Microsoft.Extensions.Diagnostics.HealthChecks 7.0.3 with a net6.0 target framework. This forces you to use it as a netstandard2.0 dependency since there's only a net7.0 and no net6.0 dependency. When used as a netstandard2.0 dependency on net6.0, you apparently need Microsoft.Bcl.AsyncInterfaces because we call
For now, you can work around this issue by either.
Our recommendation is always to try to keep versions aligned if possible since that will keep you on the most well-tested path, but I still think we should probably add Microsoft.Bcl.AsyncInterfaces as a netstandard2.0 dependency for this package. @dotnet/dnceng @dotnet/aspnet-build. Is there some way to automatically detect we're using IAsyncDisposable or IAsyncEnumerable to a NuGet package targeting netstandard2.0 and fail the build if there's no Microsoft.Bcl.AsyncInterfaces dependency? |
@rquackenbush Thanks for the bug report and posting the resolution yourself, I'm reopening this to track the following question:
|
You shouldn't be able to compile code using them without the reference. I'm surprised the package compiled in the netstandard2.0 trm. |
The result should be one of the "Missing Compiler required member" errors. |
@dotnet/nuget-team sorry for the broad notification. Would appreciate your thoughts on any options that may be available. My only thought would involve complicated To @alexperovich's point, it's not clear how compilation succeeded. Has anyone gathered a binary log to help us (or the Roslyn team) figure that part out❔ |
This should be easily fixed with a |
Yeah, my "complicated |
The code compiling is the real problem. It should fail building. |
Let's get a binary log (someone❔) and bring in @jaredpar to get his opinion. |
Our local builds of Microsoft.Extensions.Diagnostics.HealthChecks.csproj work because we have a transitive reference (through Microsoft.Extensions.Hosting.Abstractions) when building for Put another way, the answer to
is that the package metadata should already bring in Microsoft.Bcl.AsyncInterfaces when using the I doubt your hypothesis is correct @halter73 because the repro project apparently works Just Fine:tm:. The only difference between good and bad is https://github.com/anvilcloud/HealthChecksRepro/blob/main/src/HealthCheckRepro/Program.cs#L14-L21.#46766 @halter73 could you or someone else on the HealthChecks team please test the reproduction and determine what is actually going on❔ |
The problem is that the app targets net6.0. Microsoft.Extensions.Diagnostics.HealthChecks 7.0 does not have a net6.0 target while Microsoft.Extensions.Hosting.Abstractions 7.0 has both net6.0 and net7.0 targets. This causes the app to resolve the netstandard2.0 version of HealthChecks that requires Microsoft.Bcl.AsyncInterfaces and the net6.0 version of Hosting.Abstractions which has no transitive dependency to Microsoft.Bcl.AsyncInterfaces as shown by HealthCheckRepro.deps.json: "Microsoft.Extensions.Hosting.Abstractions/7.0.0": {
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "7.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0",
"Microsoft.Extensions.FileProviders.Abstractions": "7.0.0"
},
"runtime": {
"lib/net6.0/Microsoft.Extensions.Hosting.Abstractions.dll": {
"assemblyVersion": "7.0.0.0",
"fileVersion": "7.0.22.51805"
}
}
},
I've already tested the repro. As I mentioned, when you call
If you do not call
We should be able to automatically detect that there are supported TFMs like net6.0 that do not transitively pull in Microsoft.Bcl.AsyncInterfaces, and fail the build until a direct dependency is added. |
Thats very interesting. The build never failed because there is no "build" of the net6.0 TFM in the HealthChecks package that could be made to fail, and the netstandard2.0 TFM build pulls in the netstandard2.0 hosting.abstractions which properly has the dependency. |
I wonder if the Microsoft.Bcl.AsyncInterfaces package could be tweaked to force a top level dependency on any project/TFM that would require it, such that transitive inclusions like this would still work when later referenced with other TFMs. |
@alexperovich @halter73 some of what you said today is new information to me, or at least old information reframed so I can (mostly) get it. @marcpopMSFT @dsplaisted something complicated and unexpected is occurring during assembly resolution. My flawed intuition says that when I bring in the If yes, there are at least two pertinent questions:
/cc @ericstj in case he owns Microsoft.Bcl.AsyncInterfaces or could pull in whoever does. |
No, whether a package is referenced directly or transitively does not affect what target framework is used to select assets. For each package, the assets for the "closest match" of the project's target framework will be used. I'm not sure about what to do about this. It sounds like Microsoft.Bcl.AsyncInterfaces is a "polyfill" type of library, and that may be something that NuGet / .NET don't handle too well. |
So dependencies of a package are supposed to be part of the public surface area of that package. So it's breaking if a package exposes a dependency on one framework but not on a compatible framework. The package "at fault" here is This has come up before and my recollection was that we intentionally have this gap where we will drop the polyfill packages in newer frameworks because the tradeoff of having the missing dependency that might be needed in some combinations of framework targeting is better than forcing all developers to carry the polyfill even after it's no longer needed. I can't find any of these issues, but I do recall a few. Maybe @joperezr remembers. As was suggested -- the safe thing to do is for any library that uses the polyfill to directly reference it. I wonder if we could force that by hiding the package from compile ( |
Interesting background @ericstj. I don't remember the history but believe ASP.NET has mostly avoided direct package references not required for compilation on a per-framework basis. We certainly have a fair number of conditional references though you need to scroll through https://github.com/dotnet/aspnetcore/search?q=%22condition%3D%5C%22+%27%24%28targetframework%29%22&type=code to find them. I'm not positive how bad that is or how much worse it is in our servicing branches. Sounds like the Extensions packages now in runtime have similar history. That said, are use of a 7.0.x package when targeting |
I think that's a great question that has never been very clearly stated to the community. The only time I've seen a clear statement here is in System.Collections.Immutable, where v7 includes (for anything below net6)
Most other things: don't complain, so I believe people have rightly or wrongly thought "that's fine". A very clear statement would be good, to help decide the route. Some options (just trying to keep driving this forward, as part of build-ops)
thoughts? (personal subjective opinion; 5 seems low impact - doesn't confuse unnecessary TFMs, and the shim should evaporate if it turns out to be unnecessary) |
As a side note: if the official story is "don't go above your TFM major", that sounds like something where the NuGet/package tooling could do a lot to help out (with some new "I'm part of the runtime, respect my TFM major" flag), because right now it will blindly suggest updates spanning majors, but won't suggest minors in the same major that exist in that scenario; i.e.
|
We permit use of packages from newer releases on older frameworks. There are consequences / trade-offs / side-effects of mixing bands, but it is supported so long as you do not downgrade. Good examples of this are packages like System.Text.Json - we explicitly put new features and API in this package so that folks can use it on .NETStandard / .NETFramework (and older .NET versions). Some of the consequences of using newer packages on older frameworks:
Adding PackageReferences for anything that's directly consumed by your assembly is actually a best practice since it insulates you from changes made by your dependencies. You can know you will need that PackageReference because it appears as an assembly dependency in your metadata. That won't change unless you rebuild the library. In other words, I recommend option 5 as well. It's not only low risk, but it's also best practice IMO. |
This makes sense. @mgravell do you want to take this as part of build ops❔ My main added suggestion is that we run the change by Tactics since it's a packaging change (at least kinda sorta). |
To be clear, I'm assuming we'll take this back to at least release/7.0. |
@ericstj what is the list of "polyfill packages" we should be concerned about❔ I'm thinking it might be worthwhile to expand @MackinnonBuck's #46920 to cover all the places where these packages show up in project.assets.json or Also, which of project.assets.json and |
Microsoft.BCL.* If you wanted a good solution to avoid this entire class of issues in the future, it would be to implement "Package Testing". We do this in dotnet/runtime. For every package we produce, we determine what frameworks it supports. We then restore that package on those frameworks and walk its closure of dependencies to ensure that all dependencies are present. |
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process. |
Is there an existing issue for this?
Describe the bug
Adding health checks with AddHealthChecks().AddCheck() prevents calls to
IHealthCheckPublisher.PublishAsync
.Expected Behavior
I expect
IHealthCheckPublisher.PublishAsync
to be called where.AddCheck
has been called or not.Steps To Reproduce
https://github.com/anvilcloud/HealthChecksRepro
Exceptions (if any)
None.
.NET Version
7.0.100
Anything else?
IDE
Microsoft Visual Studio Professional 2022 (64-bit) - Current
Version 17.4.2
dotnet --info
Update: This works if the
TargetFramework
is set tonet7.0
. Unfortunately I need to do this innet6.0
.The text was updated successfully, but these errors were encountered: