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

Remove the PackageReference to Microsoft.AspNetCore.App/All from project files #3307

Closed
natemcmaster opened this Issue Jul 9, 2018 · 28 comments

Comments

Projects
None yet
10 participants
@natemcmaster
Member

natemcmaster commented Jul 9, 2018

Most NuGet packages provide both compilation and runtime assets. Microsoft.NETCore.App, Microsoft.AspNetCore.App, and Microsoft.AspNetCore.All effectively only provide the first - compilation references. Users must install other runtime assets to make .NET Core apps work but this is not obvious or intuitive, and not always possible: for example, Azure Web Apps, AWS, Google Cloud, etc. This violates a reasonable expectation of using a NuGet package, and has been a continual source of grief for users. Microsoft.NETCore.App had the same issues, but these were largely resolved by (1) making the PackageReference implicit based on TargetFramework and (2) pinning the package version to the lowest stable release. We should follow this pattern in the Microsoft.AspNetCore.App and .All metapackages.

Proposal

These changes are currently open for discussion. I may update this issue as we tweak this proposal.

Change 1

Update Sept. 24: this change will not be implemented.

Remove the PackageReference to Microsoft.AspNetCore.App/All from the .csproj file. Make it implicit when the RuntimeFrameworkName property is set. An ASP.NET Core web project would look like this.

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <RuntimeFrameworkName>Microsoft.AspNetCore.App</RuntimeFrameworkName>
  </PropertyGroup>

</Project>

When RuntimeFrameworkName is set, an implicit PackageReference is added to the project, but this will use the IsImplicitlyDefined property, which hides updates from NuGet UI.

The default implicit package reference will stay pinned to version AspNetCore.App 2.1.1 to maximize compatibility with the most deployment environments.

This implicit version will also use the self-contained rollforward mechanism used by Microsoft.NETCore.App today.

If users need to elevate the minimum version of the shared runtime, they can use RuntimeFrameworkVersion (which is already supported by Microsoft.NETCore.App).

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <RuntimeFrameworkName>Microsoft.AspNetCore.App</RuntimeFrameworkName>
    <!-- Less common, but available for users who want to ensure a minimum version. -->
    <RuntimeFrameworkVersion>2.1.789</RuntimeFrameworkVersion>
  </PropertyGroup>

Change 2

Update July 11: this piece will be implemented in 2.1.3, regardless of the other changes. We believe it helps address some issues, even if we don't land Changes 1, 3, and 4 until later. See #3316

All packages which share a dependency with Microsoft.AspNetCore.App should target 2.1.0 unless there is an important reason to force a patched version. This applies to most ASP.NET Core packages, and should also apply to third-party libraries.

We'll start by implementing this within ASP.NET Core on a repo by repo basis. Doing this from package to package within a repo is currently prohibitively expensive. We'll re-evaluate this in 2.2 or 3.0.

Change 3

Update Sept. 24: this change will not be implemented.

Issue warnings when Microsoft.AspNetCore.App/All are explicit references and encourage users to switch to the new implicit reference format. Wording might say something like:

warning: A PackageReference for 'Microsoft.AspNetCore.App' was included in your project.
We recommend removing this and adding the RuntimeFrameworkName property.

 <PropertyGroup>
    <RuntimeFrameworkName>Microsoft.AspNetCore.App</RuntimeFrameworkName>
 </PropertyGroup>

For more information, see https://aka.ms/sdkimplicitrefs

Change 4

Update Sept. 24: this change will not be implemented.

When both RuntimeFrameworkName and an explicit PackageReference are present, issue the same warning that currently exists for Microsoft.NETCore.App. It would look like this:

warning NETSDK1023: A PackageReference for 'Microsoft.AspNetCore.App' was included in your project. This package is implicitly referenced by the .NET SDK and you do not typically need to reference it from your project. For more information, see https://aka.ms/sdkimplicitrefs

Impact

Scenario: 2.1.x patch updates

Currently: users need to update the PackageReference to ensure their packages and the shared runtime stay aligned. Users must install the latest ASP.NET Core shared runtime on their servers.

Change: no modification to the .csproj file would be necessary. Users should install the latest ASP.NET Core shared runtime on their servers.

Scenario: patch updates for ASP.NET Core on .NET Framework

Currently: we cascade version udpates and re-release packages to ensure updating PackageReference hoists all transitives to latest.

Change: if there are changes in transitive dependencies which are important for users to consume, they may need to add new explicit references to get the latest patched versions.

Scenario: Minor releases

Currently: users would need to update the TargetFramework property to netcoreapp2.2 and the PackageReference to Microsoft.AspNetCore.App

Change: users only need to update the TargetFramework property to netcoreapp2.2.

cc @DamianEdwards @davidfowl @dsplaisted @nguerrera @JunTaoLuo @mlorbetske @normj

@nguerrera

This comment has been minimized.

Member

nguerrera commented Jul 9, 2018

I'm trying to think about the ways in which having a single RuntimeFrameworkName/RuntimeFrameworkVersion pair might be a problem. We need to add an implicit ref to both Microsoft.NETCore.App and Microsoft.AspNetCore.App, right? For example, if I have this example from the description:

    <RuntimeFrameworkName>Microsoft.AspNetCore.App</RuntimeFrameworkName>
    <!-- Less common, but available for users who want to ensure a minimum version. -->
    <RuntimeFrameworkVersion>2.1.789</RuntimeFrameworkVersion>

Am I now forced to use Microsoft.NETCore.App 2.1.0?

@natemcmaster

This comment has been minimized.

Member

natemcmaster commented Jul 9, 2018

We need to add an implicit ref to both Microsoft.NETCore.App and Microsoft.AspNetCore.App, right?

That's one solution, or, we could introduce a package dependency from Microsoft.AspNetCore.App -> Microsoft.NETCore.App. I'm prototyping both approaches today to see which works better.

Am I now forced to use Microsoft.NETCore.App 2.1.0?

In which way do you mean this? ...forced to use the Microsoft.NETCore.App 2.1.0 { package or shared runtime }?

@poke

This comment has been minimized.

Contributor

poke commented Jul 9, 2018

What exactly is the plan for non-Web SDK projects? We have to keep in mind that we have library or test projects that may require dependencies from ASP.NET Core. For the latter, we ended up declaring them as Web SDK projects (#3156) although that’s pretty much a work around to get the shared framework working.

While this works for test projects, this is not an option for library projects which should target netstandard. So what exactly is the plan? I would like to see a solution that works equally on all project types because otherwise we will have to end up educating users all the time about when they have to do what – something that didn’t exactly get easier with the decision to add back explicit version numbers.

All packages which share a dependency with Microsoft.AspNetCore.App should target 2.1.0 unless there is an important reason to force a patched version. This applies to most ASP.NET Core packages, and should also apply to third-party libraries.

What is the behavior if they end up targetting a different version though when they require a patched version? Right now we get version conflict errors because of the implicit references of the shared framework. So we cannot actually overwrite anything that’s already part of the framework.

@natemcmaster

This comment has been minimized.

Member

natemcmaster commented Jul 9, 2018

What exactly is the plan for non-Web SDK projects?

I left that piece out because I'm still investigating. My thinking: we should implement the RuntimeFrameworkName property in the non-Web SDK so it works well for console and test projects, but I can't commit to that without more review from @nguerrera and @dsplaisted.

While this works for test projects, this is not an option for library projects which should target netstandard. So what exactly is the plan?

Not planning to address right now. This change is only about netcoreapp2.1 projects. But in general, I would recommend keeping your class libraries using the lowest compatible package version, and then let end-of-line projects upgrade to higher versions.

Right now we get version conflict errors because of the implicit references of the shared framework. So we cannot actually overwrite anything that’s already part of the framework.

Are you using 2.1.0? This sounds like aspnet/Universe#1180, which was address in the 2.1.1 update.

@davkean

This comment has been minimized.

Member

davkean commented Jul 9, 2018

The issue is missing context on how the above proposal fixes:

Users must install other runtime assets to make .NET Core apps work but this is not obvious or intuitive, and not always possible: for example, Azure Web Apps, AWS, Google Cloud, etc.

@natemcmaster

This comment has been minimized.

Member

natemcmaster commented Jul 9, 2018

Updated to add this:

"The default implicit package reference (to Microsoft.AspNetCore.App) will stay pinned to version 2.1.1 to maximize compatibility on deployment."

We hope to never update this package version with new SDK updates. Apps get the latest runtime by updating their deployment environment, not their PackageReference. We let the host do the rollforward to newer versions.

@dasMulli

This comment has been minimized.

Contributor

dasMulli commented Jul 9, 2018

A single RuntimeFrameworkVersion may be problem for ASP.NET Core only releases where you only increase the version number of ASP.NET Core but not .NET Core - like the recent 2.0.8 release.
The implicit reference to M.NETCore.App would then fail. Or are you planning to remove that as well and make it a dependency of the shared fx packages?

@natemcmaster

This comment has been minimized.

Member

natemcmaster commented Jul 9, 2018

@nguerrera had the same concern. My thinking is that there only needs to be one implicit package reference, and RuntimeFrameworkName/Version controls what that is. The layered shared frameworks, like AspNetCore.App and .All can use package dependencies to represent the shared runtime layers. e.g. Microsoft.AspNetCore.All (package) depends on AspNetCore.App depends on NETCore.App.

Also, we learned in 2.0.8 that we should keep NETCore.App and AspNetCore.App aligned exactly in version number, so regardless of this proposal, we plan to keep them in sync.

@dasMulli

This comment has been minimized.

Contributor

dasMulli commented Jul 10, 2018

In this case, it would be great if the RuntimeFrameworkName logic was implemented in the core (non-web) SDK, this would open up the possibility to use the shared framework in test projects without the side effects of referencing the web sdk (icon, launchSettings.json generation, different globbing patterns, web.config generation on publish etc.).

@dasMulli

This comment has been minimized.

Contributor

dasMulli commented Jul 10, 2018

Since I keep asking about 3.0 all the time: Are there any plans / thoughts for how the desktop app experience (WPF/WinForms-on-core) could look like?
If it's going to be a shared framework as well, having an abstract model that could work for both would be great.
So you'd either have:

  1. An app using a project type specific SDK and probably a custom RuntimeFrameworkName
  2. A test project using the Microsoft.NET.Sdk and an optional custom RuntimeFrameworkName (M.AspNetCore.All/App, ?M.NETCore.WindowsApp?,…)
@natemcmaster

This comment has been minimized.

Member

natemcmaster commented Jul 10, 2018

We're still in the early phases of designing 3.0. The questions you've just asked are ones we are also asking ourselves. I don't have answers yet and would rather not speculate.

@Kukkimonsuta

This comment has been minimized.

Kukkimonsuta commented Jul 10, 2018

I'm also concerned whether single RuntimeFramework is enough. Consider .net core 3.0 and desktop - I can imagine a desktop app that exposes web server and uses asp.net core to do it - but I doubt there will be framework that includes both. Could maybe following work?

<ItemGroup>
    <RuntimeFramework Include="Microsoft.AspNetCore.App" />
    <RuntimeFramework Include="Microsoft.Windows.Desktop" />
</ItemGroup>

This would also keep the doors open for custom runtime frameworks if ever implemented. Imagine having dotnet runtime-framework update and suddenly have all apps on given machine use newest security patch of nancy, orchard or inhouse company suite without redeployment.

Also please consult xamarin developers. Xamarin doesn't use the new project system yet, but IIRC it's planned and if done right maybe this could resolve insanity that referencing (and updating) android support libs is?

@DamianEdwards

This comment has been minimized.

Member

DamianEdwards commented Jul 10, 2018

As Nate said, we're early on in 3.0 composition planning and this exact topic has come up. We will support multiple frameworks in that time, but it isn't a requirement for 2.1.x and I don't want to couple the eventual solution for 3.0 scenarios to the specific issues we want to address for 2.x.

@poke

This comment has been minimized.

Contributor

poke commented Jul 10, 2018

In my opinion, 3.0 should still be taken into account when planning this change for 2.2.

ASP.NET Core already has enough history when it comes to tooling-related breaking changes with early and later DNX, the switch to MSBuild, the introduction of meta packages, then shared frameworks, implicit versions and now explicit versions.

It would be really nice if whatever results from this discussion wouldn’t have to be scrapped again when 3.0 comes but proved to be a stable and flexible way beyond 2.2.

@DamianEdwards

This comment has been minimized.

Member

DamianEdwards commented Jul 10, 2018

These changes are for 2.1.x, not 2.2. I agree with you RE breaking changes in new versions and our goal for the design in 3.0 is to ensure that it can be migrated to very simply with build-time instructions on how to do so, e.g. moving a project from 2.x to 3.0 should be as simple as changing TFM and then building. The build should work and any idiom changes will be highlighted in the build output, instructing you on what small project file change to make to bring inline with latest constructs. But as I said, the timing of this is such that tying the two directly together is going to risk either delaying getting the 2.x experience to where it needs to be, or settling on a design for 3.0 too early before we've had ample time to ensure it meets the requirements of the new scenarios.

@normj

This comment has been minimized.

normj commented Jul 11, 2018

I like this proposal. It will solve a lot of the versioning difficulties we have had at AWS with .NET Core. The shared runtimes are treated more like a first class entity as opposed to shoehorned into a PackageReference.

I wonder if there is anything we can do to help encourage library writers to try and target the lowest compatible version. I worry somebody is going to take in a library that mistakenly took a newer version dependency of one of the packages in Microsoft.AspNetCore.App high up in the list of dependencies that could cause an explosion of dlls in the publish folder. For example could there be warnings written out when doing a dotnet pack when referencing versions out of bounds of Microsoft.AspNetCore.App.

@tmds

This comment has been minimized.

Contributor

tmds commented Jul 11, 2018

All packages which share a dependency with Microsoft.AspNetCore.App should target 2.1.0 unless there is an important reason to force a patched version.

@natemcmaster I think this won't work for source-build .NET Core. Since there is no shared framework, this will cause an out-dated package to be used from nuget.org.

@dasMulli

This comment has been minimized.

Contributor

dasMulli commented Jul 11, 2018

I don't think this will make the story for source build much worse than it currently is (no shared fx, no asp.net core bundled CLI tools).
If library authors target the lowest possible version of a package (this may even be 2.0.0 or lower for some abstraction libs), then the app projects would need to raise the transitive package to a higher version, either through a single metapackage or by updating all packages.
Is source-build for ASP.NET panned in the foreseeable future?

@tmds

This comment has been minimized.

Contributor

tmds commented Jul 11, 2018

I don't think this will make the story for source build much worse than it currently is (no shared fx, no asp.net core bundled CLI tools).

Currently, for source-build, the sdk will use the latest patch version (known to the sdk) as the implicit version for Microsoft.AspNetCore.App/All. So if you are using the latest sdk, you're app includes the latest ASP.NET Core patch versions from nuget.org.

Is source-build for ASP.NET panned in the foreseeable future?

Good question. It is tracked here: dotnet/source-build#375

@natemcmaster

This comment has been minimized.

Member

natemcmaster commented Jul 11, 2018

@tmds: So if you are using the latest sdk, you're app includes the latest ASP.NET Core patch versions from nuget.org.

Maybe I'm missing something. I thought this solved the issue. As @dasMulli pointed out, the latest Microsoft.AspNetCore.App/All patch will depend on to the highest patch versions of other aspnet packages.

@normj: I wonder if there is anything we can do to help encourage library writers to try and target the lowest compatible version. I worry somebody is going to take in a library that mistakenly took a newer version dependency of one of the packages in Microsoft.AspNetCore.App high up in the list of dependencies that could cause an explosion of dlls in the publish folder.

This is also something I've been thinking about, too, but don't have a solution. NETStandard.Library 1.6.* had the same issues in the .NET Core 1.x days. If your netcoreapp1.0 project ended up referencing NETStandard.Library 1.6.1, publish output exploded with a few dozen System.*.dll files. Same thing could easily happen when you referenced any of the dozens of System.* packages. NETStandard.Library 2.0.0 solved this by consolidating reference assemblies into one package, and updating the SDK to prevent NETStandard.Library from ending up in the nuspec on dotnet pack. Corefx also stopped shipping many of the System.* packages. While some of these approaches are available to us, we have to tread carefully. I think we'd start a small riot if we stopped shipping as packages without a suitable replacement. Corefx could pull that off because NETStandard.Library maps 1:1 to the netstandard2.0 TFM, but ASP.NET does not have its own TFM, nor do I think it should.

@tmds

This comment has been minimized.

Contributor

tmds commented Jul 11, 2018

Maybe I'm missing something.

That was a reply to @dasMulli, did you see my earlier comment about change 2?

@natemcmaster

This comment has been minimized.

Member

natemcmaster commented Jul 11, 2018

Yes. I was under the impression the source-build SDK still supported using the Microsoft.AspNetCore.App/All metapackages, but it tweaks the behavior to disable shared runtime trimming and to also lift the implicit PackageVersion to the latest. Since the latest Microsoft.AspNetCore.App/All metapackage depend on highest versions of everything else, I don't see how you end up with outdated nuget packages.

@tmds

This comment has been minimized.

Contributor

tmds commented Jul 11, 2018

If I add a reference to Microsoft.AspNetCore.Mvc.Testing (aspnet/Universe#1180) in my asp.net core project, to what should I set the version?

@poke

This comment has been minimized.

Contributor

poke commented Jul 11, 2018

Do I understand it correctly that one of the major problems about having a version number on the shared framework is that this might end up with lots of dlls in the output when the shared framework from the executing runtime should provide those assemblies?

In a way, the runtime’s shared framework is kind of like a GAC, so couldn’t we introduce some alternative <PackageReference> (e.g. <FrameworkReference>) which basically has the following build semantics: When building, use the assemblies that are part of the SDK and compile against those. Do not emit the assemblies in the output (unless doing a self-contained build or something).

So a version mismatch at build time would never result in unwanted assemblies in the build output because it is always assumed that the target machine has the right runtime with the required shared framework installed.

@natemcmaster

This comment has been minimized.

Member

natemcmaster commented Jul 12, 2018

@tmds: If I add a reference to Microsoft.AspNetCore.Mvc.Testing in my asp.net core project, to what should I set the version?

Short answer: still use the latest version.
Longer answer: This is a perfect example of what Change 2 is meant to address. This package depends on Microsoft.AspNetCore.Mvc.Core, which is part of the shared framework. Ideally, this package dependency would never be higher than Mvc.Core 2.1.0 so that you would not unintentionally upgrade Mvc.Core out of the shared framework just by using the latest Mvc.Testing. That said, we did not design our build system for this behavior. We're making progress towards fixing this. We'll probably get part of the way there -- our build system can handle setting "baseline" package versions between repos, but no within repos. So, in 2.1.3 you may end up upgrading out some of the shared framework, but the number of assemblies you upgrade out will go down when we finish #3316.

@poke

The major problem is more about the user experience. Users (rightly so) expect that a PackageReference provides everything - compilation references and the runtime implementation. The problem with Microsoft.AspNetCore.App is that it only provides the first, and users frequently have issues understanding why. Removing the PackageReference from the .csproj isn't a silver bullet, but it reduces the chance that you'll tweak the version because the NuGet UI in VS told you to update.

When building, use the assemblies that are part of the SDK and compile against those. Do not emit the assemblies in the output (unless doing a self-contained build or something)...

That's basically how it already works, except that it uses PackageReference versions to decide when the user has referenced something newer than what the shared runtime provides. The user experience problem we are trying to solve is that users typically do this unintentionally.

natemcmaster added a commit to natemcmaster/dotnet-sdk that referenced this issue Jul 17, 2018

Implement support for RuntimeFrameworkName in .NET Core 2.1 and up
When set by the project, this property adds an additional PackageReference to Microsoft.AspNetCore.App/All
which behaves like Microsoft.NETCore.App. It is the recommended replacement for the versionless PackageReference, which
only worked when using Microsoft.NET.Sdk.Web.

See aspnet/AspNetCore#3307

natemcmaster added a commit to natemcmaster/dotnet-sdk that referenced this issue Jul 17, 2018

Implement support for RuntimeFrameworkName in .NET Core 2.1 and up
When set by the project, this property adds an additional PackageReference to Microsoft.AspNetCore.App/All
which behaves like Microsoft.NETCore.App. It is the recommended replacement for the versionless PackageReference, which
only worked when using Microsoft.NET.Sdk.Web.

See aspnet/AspNetCore#3307

@natemcmaster natemcmaster added this to the 2.2.0-preview1 milestone Jul 18, 2018

@natemcmaster natemcmaster removed their assignment Jul 18, 2018

@natemcmaster

This comment has been minimized.

Member

natemcmaster commented Jul 18, 2018

After several rounds of review and discussion, Changes 1, 3, and 4 are being considered for the future, but is not likely to make it in for the 2.1 SDK due to time constraints. Change 2 was implemented for the 2.1.3 servicing update and will continue to be the servicing policy going forward in 2.1.x and 2.2.

@muratg muratg removed this from the 2.2.0-preview1 milestone Aug 23, 2018

@muratg

This comment has been minimized.

Member

muratg commented Aug 23, 2018

@natemcmaster Removed this from the milestone. I don't believe we'll be doing more on this in 2.2.

@natemcmaster

This comment has been minimized.

Member

natemcmaster commented Sep 24, 2018

There is no plan to make changes to the schema of a .csproj in 2.1 or 2.2. We implemented and tested variations of the proposed changes, but ultimately, we did not believe those were significantly better than the versionless PackageReference. Bigger changes, which are not possible in 2.x, are necessary to cleanup the experience. We are preparing plans for 3.0 that rework the way a project references the ASP.NET Core shared framework. These changes draw from some of the ideas proposed in this thread. It's unlikely these can be backported to 2.x since they will involve some breaking changes, so our recommendation for 2.1 and 2.2 is to continue using the versionless package reference:

<ItemGroup>
   <PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

I'm closing this issue because some of the proposals in the original issue were implemented, and others will not be fixed in 2.x. I've update the original issue to indicate which changes were made. We will share more details about 3.0 plans soon.

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