NuGet/Home

packages.config (PC) to PackageReference (PR) Migration

nkolev92 opened this issue · 94 comments

Status: In Progress

Issue to track new feature work around enabling packages.config (PC) to PackageReference (PR) upgrader workflow.

Here is the link to the spec.

Feel free to comment below with your feedback.

Related issues

#12388

Overall Issue Description:

  • #4942 After enabling PackageReference support for projects, some packages may not install or work correctly

Likely Project System Issues

  • dotnet/project-system#3042 - ContentFiles "Any" folder issue with classic csproj

  • dotnet/project-system#3431 Display ContentFiles in Legacy PR

  • #2365 - Some assemblies in NuGet packages should be linked, not referenced (Pertains to interop assemblies and the knowledge of whether an assembly needs to be referenced. Lost when moved to the transitive world)

  • dotnet/project-system#2859 - Project System side ASK for embedded interops

  • PP transforms - supported, but csproj.dll issue (link?) (see related #5880)

  • ContentFiles doesn't work with legacy PackageReference. Some issues in NuGet but also needs to coordinate with Project System as well. (#5958 dotnet/project-system#2861)

  • CPS projects can't handle contentFiles from separate packages using the same file name. (#5048)

  • https://devdiv.visualstudio.com/DevDiv/NuGet/_workitems/edit/567298 - Wildcard support in legacy project system Won't fix.

  • Internal bug 465204 - NuGet Build Tasks don’t put proper metadata on satellite assemblies (potentially a restore issue)

NuGet Migration Issues:

  • #5963 Come up with a strategy for packages that have install.ps1/uninstall.ps1 .
  • #5954 XDT Transforms don't work for transitive restore
  • NuGet.Config RepositoryPath controls Solution package directory for PC users. PR doesn't have a Solution package directory. (RestorePackagesPath can set the location of UserPackageFolder that is used by PC and PR codepaths) - No fix. Everything goes to the global packages folder.
  • In order to pack normal PackageRef projects, you need to add a PR to NuGet.Build.Tasks.Pack, but there are still gaps (includereferencedprojects) - at that point, dotnet.exe pack will work, but nuget.exe pack won't. Related - #6285
  • EntityFramework story - #5974 & dotnet/ef6#189
  • what data should we collect to ensure we learn and adapt (this needs more thought)
  • #6009 - Update documentation for package reference

NuGet PC to PR Migration Tool Issues

  • #5488 - Provide migration tool to move from packages.config project to packagereference
  • #5879 - Add support for solution level PC -> PR migration
  • Ensure the user understands changes made for them (and give them options to tweak our behavior if necessary???)
  • P0 - enable project level migration (which needs to be able to walk up towards the root, changing each to PR.
    Changes to NuGet PM UI to adapt to transitive:
  • Transitive dependency management, list transitive package in a flatlist - #5887
  • Rework the UI - #6530

VS Extensibility Team Issues

  • VS SDK project support : #5899

C++ Team Issues

  • Find bug to link Internal C++ bug# 188588

WPF Project Compat Issues:

  • #5894 - PackageReference broken in WPF projects due to tmp_proj not importing Package-supplied build authoring

Clean up our own Repro to remove the need for install.ps1

  • #5414 - Update NuGet.VisualStudio for PackageReference projects
  • #5971 Enable the build bootstrapping scenario which is supported by PC today. See configure.ps1 in NuGet repo. (dotnet install tool foo.bar -- may help solve this)

Work with package owners (see related item# #5960)

  • Analyze how many packages have install/uninstall.ps1 and analyze the impact this change would have.
  • Analyze contentfiles vs content packages - #5048
  • Analyze lib/foo.dll packages
  • #6623 Jquery/Bower + Alternative Package Manager Providers

Validation to improve ecosystem for new push/ingested packages

  • once we clean up, how do we keep it clean? Validation at pack/push/ingest time?

Package Reference experience issues

  • #5939 - Install/Uninstall operations from PMC do not refresh PM UI for legacy project system
  • dotnet/project-system#2129 - Improve PackageReference support in old project system - $(MyVersion) in version string.
  • #4778 Error experience with unavailable frameworks, PR.
  • #4989 - Documentation issue.
  • #4488 - PackageRef project opt-in technique
  • #8980 Allow project format selection dialog should be enabled by default.

You might want to add #5894 to your list of issues to be fixed. Since NuGet contains WPF assets, this could bite you.

Done.
Thanks @AArnott.

As I understand it, 465204 is also a scenario that works with packages.config but not PackageReferences

roslyn 22095 is one that is stopping us from migrating. I had it as a nuget issue originally. If nuget could have a type of lib that ended up being output to bin but would be flagged as not having its API exposed to consuming projects, then it wouldn't be a problem.

@mungojam NuGet packages can already depend on another package without exposing the API from that package to their own consumer. I think that that problem is solved at the right place right now because, for example, if package A depends on package B, we might say the ideal situation is that package A hides package B from the compiler of the app project if and only if no APIs from package B are exposed from package A's API.

Let's take an example:

Package B defines public class Tree and Package A derives from it: public class AppleTree : Tree.
It is important then that anyone referencing Package A automatically get Package B's types so the compiler doesn't emit an error when using AppleTree telling the user to add a reference to resolve Tree as a base type. That would be a bad experience for Package A's consumer if using it was broken by default. Also, considering Package A's public API itself depends on Package B, package A cannot remove its dependency on Package B without it being a binary breaking change, so it's unlikely they would do that--at least not without a major version increment per semver.

But now consider Package A only defines internal class AppleTree (note it is internal). Package B is now an implementation detail of Package A. Now it is appropriate for Package A to specify B as a dependency in their nuspec, including the attribute to omit B as a reference to the compiler that builds the app. Now the app can't accidentally take a dependency on B without the app developer adding a PackageReference to B explicitly, thereby mitigating the problem you're calling out.

The issue that remains, I think, is that most packages out there today don't do due diligence to mark their dependencies carefully in this way. And even if a package author wanted to, it's not trivial to audit your public API for dependencies of this kind, nor to maintain that properly over time. So tooling to automatically discern between public dependencies and internal dependencies, and possibly automatically setting the appropriate package dependency metadata may be the best way to solve your problem in general.

@AArnott Thanks for reviewing it, you've summed it up perfectly. I may be missing a trick then, how do we specify that a particular dependency is only to be added as an internal dependency and not exposed to compiler further up the chain?

I agree that tooling would definitely solve it nicely if the nuget mechanism exists already.

@AArnott Is this the mechanism you are referring to, using contentFiles?

<contentFiles>
  <file include="bin/Release/SomeInternalDependency.dll" buildAction="None" copyToOutput="true" flatten="true" />
</contentFiles>

I might see what happens with a wildcard in the include. Maybe we could do that for the packages we make and then add external dependencies explicitly in an exclude.. sounds yukky, but might work.

No, don't use contentFiles for this. When building your own package via csproj with PackageReference items, you add an attribute like this (if this were package A):

  <PackageReference Include="PackageB" Version="1.0" PrivateAssets="compile" />

This makes it so your own package A consumes and references package B in your compiler references, but folks consuming package A will not get package B in their assembly references.

Documented here

Thanks, that does work, actually using "compile;contentfiles;analyzers;build" to keep the default behaviour of PrivateAssets for the other types.

So, I will raise a feature request for the tooling improvement that you suggested, recognising that it won't be an easy thing to implement.

By the way, I had tried PrivateAssets previously and hit various errors. Some my own doing (package name clash). Other issues I ran into have been raised as issues already against the project system I think. I had to keep closing VS 15.4 and deleting obj/bin/.vs folders for various changes to package references to work. I hope that is fixed soon as it is a blocker for us too.

Is it the case that #4491 should be included in this checklist?

@awesley #6285 is tracking that work and is included in the list in the OP.

I can't see this mentioned anywhere, but I assume this would work just as well from the CLI, right? Remember, not everyone uses Visual Studio these days 😉

@khellang
packages.config installation/uninstallation works correctly only in Visual Studio.

Unfortunately the migration will only work in VS due to that limitation.

Do we really need a backup? In 2018? For source code? It's just one more annoying directory to delete before commit.

@IanMercer you would be surprised...

@IanMercer I think a lot of people (most?) already have backup folders ignored. It's even part of GitHub's .gitignore template for Visual Studio 😄

Is this gonna work for Asp.Net Website (WSP) projects? These projects have no csproj file and currently they have support for NuGet using a packages.config file.
If packages.config files are deprecated/removed in the feature, WSP projects have no story for using NuGet?

@JarnoNijboer currently, the migrator will not be enabled for website projects. But that does not mean that packages.config is going to be deprecated, it will continue to be supported until there is a clear path forward to move to PackageReference

while the migrator will be available in 15.7, some of the issues listed in the OP still need to be worked on. Moving this to 4.8

I ran it against one of my class library projects and it added a lot more than just the package reference stuff. It added entries for PublishUrl, Intall.., Update..,Application.., etc. It also added Bootstrap entries. This is way more than I wanted. Just replace the package references - why is it making non-package related changes as well.

From:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <OutputType>Library</OutputType>
    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
    ...
  </PropertyGroup>

To:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <OutputType>Library</OutputType>
    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
    ...
   <PublishUrl>publish\</PublishUrl>
    <Install>true</Install>
    <InstallFrom>Disk</InstallFrom>
    <UpdateEnabled>false</UpdateEnabled>
    <UpdateMode>Foreground</UpdateMode>
    <UpdateInterval>7</UpdateInterval>
    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
    <UpdatePeriodically>false</UpdatePeriodically>
    <UpdateRequired>false</UpdateRequired>
    <MapFileExtensions>true</MapFileExtensions>
    <ApplicationRevision>0</ApplicationRevision>
    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
    <IsWebBootstrapper>false</IsWebBootstrapper>
    <UseApplicationTrust>false</UseApplicationTrust>
    <BootstrapperEnabled>true</BootstrapperEnabled>
  </PropertyGroup>

And added this-

<ItemGroup>
    <BootstrapperPackage Include=".NETFramework,Version=v4.6.1">
      <Visible>False</Visible>
      <ProductName>Microsoft .NET Framework 4.6.1 %28x86 and x64%29</ProductName>
      <Install>true</Install>
    </BootstrapperPackage>
    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
      <Visible>False</Visible>
      <ProductName>.NET Framework 3.5 SP1</ProductName>
      <Install>false</Install>
    </BootstrapperPackage>
  </ItemGroup>

@CoolDadTx that definitely doesn’t sound right. Any chance you can give us a repro project or your list of packages in packages.config ?

@CoolDadTx I had a similar issue whenever I made changes to project file these tags were added.

The problem was, my project once had ClickOnce and after removing ClickOnce there were still some stuff left behind and it tried to add again all the removed ClickOnce tags.

My solution was to make sure all ClickOnce tags were removed and the tags stopped reappearing.

Maybe your cause is similar.

Do you know what element triggered ClickOnce because this was a class library project that had no references to ClickOnce at any point? The only element I see that might have been auto-added when the project was created was TargetFrameworkProfile.

@rohit21agrawal

Packages config:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="AutoMapper" version="6.0.2" targetFramework="net461" />
  <package id="EntityFramework" version="6.1.3" targetFramework="net452" />
  <package id="Fsmb" version="2.0.1.0" targetFramework="net451" />
  <package id="Fsmb.Apollo" version="5.0.17009.1" targetFramework="net461" />
  <package id="Fsmb.Augusta" version="2.5.17177.1" targetFramework="net461" />
  <package id="Fsmb.Augusta.Cdc" version="2.5.17052.1" targetFramework="net461" />
  <package id="Fsmb.Augusta.EntityFramework" version="2.5.17177.1" targetFramework="net461" />
  <package id="Fsmb.EnterpriseServices.Logging" version="3.0.17083.3" targetFramework="net461" />
  <package id="Fsmb.EnterpriseServices.Reporting" version="1.0.14065.5" targetFramework="net452" />
</packages>

We have a private VSTS repo where most of the packages come from but the rest are in NuGet.

@CoolDadTx
oh, I might not be able to test this out if your packages are coming from a private VSTS repo.

can you try this:

  1. Create a plain old packages.config based Class Library (Full .NET Framework). Check the project file.
  2. Install the packages you listed above
  3. Check the project file for any changes after installation.
  4. Migrate from packages.config to PackageReference .
  5. Look for any further changes.

If there is something confidential about your projects/packages that you can't share with us, I can work on getting a NDA so I can inspect where the migration is going wrong?

I tried a test scenario and couldn't replicate it. I wiped my changes from the original project and ran it again and it didn't do it this time. Strange, maybe some other extension was trying to do something as well. I'll consider this issue closed for now. Thanks.

thanks @CoolDadTx for verifying! If you do have any other feedback/issues with the migrator, please do share with us!

@rohit21agrawal, I do have one complaint but I suspect there is nothing you can do about it. When the migrator is moving packages it is auto-generating an app.config file if one does not exist. I suspect this is because it is trying to uninstall a package that had transforms (i.e. EntityFramework) but I'm only guessing here. Nevertheless every project that has the migration tool run on it (that didn't have an app.config before) now has an empty one that has to be deleted. I replicated this by creating a class library that was using EntityFramework but had no config (because it was a library).

@CoolDadTx installing EntityFramework to a packages.config based ClassLibrary actually ended up creating an app.config for me with the following content:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="mssqllocaldb" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>

@rohit21agrawal, correct. Now go to the project and delete the app.config file. Then go out to the file system and ensure it is gone. Save the project. Then run the package migration tool. Notice there is no app.config in the project but if you go out to the file system it has in fact created an empty app.config file. That config file will be pushed to Git if you happen to be using it.

I tried running the tool on one of my projects and VS crashes. I attached to it from another VS instance to see why and i'm seeing an exception thrown with the message "Illegal characters in path."
I can't figure out why this is happening.

This the stack trace:

 	mscorlib.dll!System.IO.Path.CheckInvalidPathChars(string path, bool checkAdditional)	Unknown
 	mscorlib.dll!System.IO.Path.GetFileName(string path = "D:\\tfs\\Testvs17\\.\t\t")	Unknown
 	Microsoft.TeamFoundation.Common.dll!Microsoft.TeamFoundation.Common.FileSpec.GetFullPath(string path = "D:\\tfs\\Testvs17\\.\t\t", bool checkForIllegalDollar = false)	Unknown
>	Microsoft.TeamFoundation.VersionControl.Client.dll!Microsoft.TeamFoundation.VersionControl.Client.Client.GetLocalWorkspace(string localPath, bool throwIfNotFound = false)	Unknown
 	NuGet.PackageManagement.VisualStudio.dll!NuGet.PackageManagement.VisualStudio.DefaultTFSSourceControlManager.DefaultTFSSourceControlManager(NuGet.Configuration.ISettings settings, EnvDTE80.SourceControlBindings sourceControlBindings)	Unknown
 	NuGet.PackageManagement.VisualStudio.dll!NuGet.PackageManagement.VisualStudio.VsSourceControlManagerProvider.GetSourceControlManager.AnonymousMethod__4_0()	Unknown
 	mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(object stateMachine)	Unknown
 	mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)	Unknown
 	mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)	Unknown
 	mscorlib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run()	Unknown
 	Microsoft.VisualStudio.Threading.dll!Microsoft.VisualStudio.Threading.JoinableTaskFactory.SingleExecuteProtector.TryExecute()	Unknown
 	Microsoft.VisualStudio.Threading.dll!Microsoft.VisualStudio.Threading.JoinableTaskFactory.SingleExecuteProtector..cctor.AnonymousMethod__20_0(object state)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source = {System.Windows.Threading.Dispatcher}, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler = null)	Unknown
 	WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeImpl()	Unknown
 	WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(object state)	Unknown
 	WindowsBase.dll!MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(object obj)	Unknown
 	mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)	Unknown
 	mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)	Unknown
 	mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state)	Unknown
 	WindowsBase.dll!MS.Internal.CulturePreservingExecutionContext.Run(MS.Internal.CulturePreservingExecutionContext executionContext = {MS.Internal.CulturePreservingExecutionContext}, System.Threading.ContextCallback callback, object state)	Unknown
 	WindowsBase.dll!System.Windows.Threading.DispatcherOperation.Invoke()	Unknown
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.ProcessQueue()	Unknown
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.WndProcHook(System.IntPtr hwnd, int msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled)	Unknown
 	WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr hwnd = {System.IntPtr}, int msg = 49946, System.IntPtr wParam = {System.IntPtr}, System.IntPtr lParam = {System.IntPtr}, ref bool handled = false)	Unknown
 	WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object o)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs)	Unknown
 	WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object source = {System.Windows.Threading.Dispatcher}, System.Delegate callback, object args, int numArgs, System.Delegate catchHandler = null)	Unknown
 	WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs)	Unknown
 	WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr hwnd = {System.IntPtr}, int msg = 49946, System.IntPtr wParam = {System.IntPtr}, System.IntPtr lParam = {System.IntPtr})	Unknown

@tamirdresher this is because the API call to Path.GetFileName is throwing when it's getting " D:\tfs\Testvs17\.\t\t " The problem is the . in the path.

Do you know where is this path coming from?

@rohit21agrawal I saw the path but i have no idea where is it coming from. The root folder for the *.sln is D:\tfs\Testvs17\ but i dont know where the . and the rest is coming from.
I unbound the entire folder from TFS (VSTS) and now it works.
Do you have clue why working with a project that is bound to TFS can cause this error?

@tamirdresher I am investigating the issue - can you tell me if the solution packages folder is also bound to TFS?

UPDATE: I am unable to repro the issue in either case :/

Any chance you can create a repro TFS project and share it with me?

@CoolDadTx looked at your issues. It's actually a package issue with EntityFramework where they end up creating that file on uninstall. You can repro it by following the same steps, except that instead of migrating , uninstall the EntityFramework package and you will see the empty app.config appear.
Unfortunately, there is nothing we can do about it :( .

Hi,
I tried upgrading my VS 2017 project to PackageReference. I upgraded using the tool given here:https://marketplace.visualstudio.com/items?itemName=CloudNimble.NuGetPackageReferenceUpgrader
Once the upgrade was done, I deleted the packages folder from my solution and then Restored Nuget Packages. Seeing the following issues:

  1. It again recreates the packages folder under my solution directory as well as the global-cache directory %userprofile%.nuget\packages. Shouldn't the packages be created under the global-cache %userprofile%.nuget\packages only?
  2. The build fails.
    For now I am going to revert the changes

@techie55 that tool is not provided from NuGet team so it might not be following the right pattern to upgrade all your existing packages from packages.config to PackageRef.

Please use latest VS preview release from https://www.visualstudio.com/vs/preview/ and then try upgrading your individual projects to PackageRef and let us know if you see any issue there. Please find more details in this blogpost

When this tool is officially released, will it be possible to use the command line to invoke a migration, so it can be scripted? We have hundreds of solutions across many repos and doing this manually would be a pain.

Just checking - Did this ship in 15.7, or should I see it in the 15.8 preview (now that 15.7 has shipped)

(I ask as I can't see it in either of these)

It's shipped as part of 15.7. Please find more details from https://blog.nuget.org/20180409/migrate-packages-config-to-package-reference.html and if you still don't see the option then open an issue with repro steps.

@jainaashish Same question as @flcdrg . I do not see the option in my Visual Studio Community version

Attaching the images to verify.
visual_studio_version
nuget

The option is enabled only on certain projects and disabled for projects such as C++ and ASP.NET to name a few.
Also, make sure you open the NuGet package manager UI or console first before checking for the migration option

@rohit21agrawal We should probably update the documentation to add the following step:
Make sure you open the NuGet package manager UI or console first before checking for the migration option
After doing the above step, I can see the option Migrate packages.config to PackageReference

Any reason why this tool cannot be enabled for ASP.NET projects?

Just curious if anyone else has tried this on an existing project?
When I try it, it causes a complete removal of all Nuget packages.
Followed by an "invalid nuget configuration" error post migration.
Followed by a working Nuget Manager ui after restarting vstudio, with a [restore] button which looks like it works but restores nothing.
Followed by manually having to re-add all nuget packages, which results in a new packages.config file, starting me back at the beginning.

The migration wizard is clearly non functional and vstudio integration has some issues.
I was excited to hear about this new feature. But now, not so much. I'll come back when the kinks are worked out. good day to you.

Can you share a repro project with us please where this happens? This is clearly not supposed to happen and we are sorry you had to face this inconvenience. Having said that, we are very interested in solving this issue and making this experience better for you, so any details you can share with us will be greatly appreciated

No apologies necessary, I know you guys are working on things far more advanced than I can even comprehend. I'll see if I can get a reproduction repo built up and on github later today, and will post back. Might even find the issue that way, thank you :)

memao commented

I am having similar issues as ensemblebd when I use the tool. Sometimes the restore failed, it suggest me to roll back. Sometimes it shows the migration succeed and .html/backup files are generated, but actually when I look at the modified .csproj file, no package reference is added or no entry is removed. I have to manullay re-add all package reference or remove those .

It doesn't happen to all my project, only some of them.

@memao can you share some of the projects with us? If there is any confidential information involved, we can set up a NDA and follow due process.

@techie55 the reason I suggested opening the PM UI/Console first is because I realized we ended up shipping a bug, for which I will file a tracking issue and fix as appropriate. In the meanwhile, we will work on documenting this workaround so people don't get blocked on this! Thanks for your feedback!

Hi,
I feel this feature is not very useful because it is not implemented for Web and WebAPI projects. Most of our projects are web based and I would have loved to see this feature available for Web projects as well

I'd like to reiterate @Falconne's question. Will there be the option to use this from the command line? We're keen to make this move, but doing this manually would be prohibitive.

@sclarke81 as of now there is no plan to have a command line option. Besides the right approach of migration is to uninstall the current package from packages.config and reinstall with PackageReference which is hard to achieve through a command line tool specially the uninstallation part.

@jainaashish Any update on the packagereference support being available for Web projects (ASP.NET full framework) ? We have an issue that is dependent on this support being available. (microsoft/testfx#241)

We're talking to AS.NET full framework team to be able to support PackageReference for this but there are some core issues with existing ASP.NET specific packages to be able to work well with PackageReference like Content folders, install.ps1/ uninstall.ps, XDT transform, etc... which is why we have not been able to make much progress.

We're evaluating multiple options at this time, one such option is to at least allow people to be able to migrate their ASP.NET projects to PackageReference and shows clear warnings with existing packages being used as part of that project which wont be compatible after migration so that consumers can take their own call (in some cases, it might just work like WebForms has less dependencies on content specific packages, or ASP.NET is also migrating to LibMan for content packages, etc...). But we're still evaluating and nothing is finalize yet. Will keep on posting as soon as there is any decision on it.

cc @rrelyea @DoRonMotter

@jainaashish Will you consider updating Microsoft.CodeAnalysis.Analyzers and Microsoft.CodeDom.Providers.DotNetCompilerPlatform to be compatible with PackageReference? Most of the popular libraries provide .net standard versions, but those dlls are from Microsoft, and they are the one providing warnings in most of our asp.net project, when we manually convert them to PackageReference.

You can ignore warnings for Microsoft.CodeAnalysis.Analyzers package since it works fine for both PackageReference. We can improve our tool to ignore warnings for analyzers packages... tracking issue# #7208

For Microsoft.CodeDom.Providers.DotNetCompilerPlatform We'll talk to the corresponding owners to update their package to be compatible with PackageReference

Hasn't been any activity on this for 1.5 months - I am wondering if we are any closer to supporting shifting ASP.NET projects to PackageReference? this has been a big blocker for our team to shift to .NET core / standard.

@JarnoNijboer NuGet still needs to add support for adding files to the project, via a regular NuGet package that is not front-end... This has been the main blocker for my team.

@JarnoNijboer that is the problem our team faces.

Shifting to use LibMan doesn't seem like a small task for us.

If you're "still" using NuGet for client side packages then LibMan would be a first step but honestly everybody uses NPM for that now. If you're going to take the hit to switch from client packages to LibMan then I'd just forgo that and go straight to NPM. VS is fully integrated with it as is all build systems.

But as @caioproiete mentions, there are other (non-front end) packages that you still need NuGet for. Pretty much any package that wants to insert new code into your project or modify your configs don't work properly with package reference. Some functionality can be restored if the package is updated to use the newer content file model but that assumes the package is being maintained.

Appreciate the feedback. I haven't been too involved in the front-end side of our projects. I have heard it mentioned about ideally moving to npm but hasn't seemed to gain traction so far.

In regards to the other shortcomings of the PackageReference format - why is this the case? Are the issues likely to be "fixed" in the future? or do these issues not exist for new .NET core projects? is it just a pain for those developers attempting to migrate .NET framework projects?

@nzandy, this doesn't really have anything to do with .NET Core but changes to NuGet itself. The NuGet team, for better or worse, has decided that how packages worked in the past won't do that now. So we are still dealing with the ramifications of these changes. The specific changes that impact this issue (as I understand them) is that packages installed via PackageReference don't go into the solution anymore. They are stored in a per-user cache to optimize the downloads.

Additionally packages that rely on other packages aren't "installed" into projects anymore. NuGet does a dependency graph traversal to pull in dependent packages at restore time. So there is no install step for packages hence content files and install scripts don't run.

This is by design so it won't be "fixed" nor is it just for NF apps. Everybody using PR is impacted and this is how it will work going forward. There are still gaps in the PR implementation and the NuGet team seems really slow on getting the feature sets more level so at this time I don't know what is going on.

We're talking to AS.NET full framework team to be able to support PackageReference for this but there are some core issues with existing ASP.NET specific packages to be able to work well with PackageReference like Content folders, install.ps1/ uninstall.ps, XDT transform, etc... which is why we have not been able to make much progress.

We're evaluating multiple options at this time, one such option is to at least allow people to be able to migrate their ASP.NET projects to PackageReference and shows clear warnings with existing packages being used as part of that project which wont be compatible after migration so that consumers can take their own call (in some cases, it might just work like WebForms has less dependencies on content specific packages, or ASP.NET is also migrating to LibMan for content packages, etc...). But we're still evaluating and nothing is finalize yet. Will keep on posting as soon as there is any decision on it.

cc @rrelyea @DoRonMotter

@jainaashish @rrelyea @DoRonMotter Any updates here ?

Work faster.

There is a VSIX extension that supposedly allows migration of ASP.net web projects. However it breaks when trying to migrate VB.Net projects. We are trying to migrate away from VB.Net completely but it takes time. We really would like to change from package.config to the package reference format. Is there some way to do this manually for now?

for the sole purpose of enabling and completing the migration, you can remove the following guids from your project file:

{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}
{349C5851-65DF-11DA-9384-00065B846F21}
{E24C65DC-7377-472B-9ABA-BC803B73C61A}

The presence of the above GUIDs causes NuGet to not show the Migrate dialog on right clicking the project.

NOTE: Might cause certain other functionality to stop working. Restore them after migration is complete.

THanks, that allowed me to do the migrations.

Does the package manager work for that project, though, after this hack? Like, restore and update?

Seems to be.

When is Microsoft going to add support for PackageReference for ASP.NET Web Forms packages??? I suppose never, since they are throwing Web Forms under the bus. Thanks a lot Microsoft.

I have successfully used the work-around described above and so far I haven't seen any issue. Makes me wonder why isn't it working by design for the web projects? What issue do I have with them that I am not yet seeing?

If you switch an existing project from package.config (PC) to package reference (PR) then you'll have no issues. In fact any project that supports PC supports PR as it is a built time featue. Your builds will work just fine.

The issue with PR is that it doesn't support all the scenarios that PC installs did and this is where things go wrong. Specifically PR doesn't support running install/uninstall scripts when a package is added/removed. Therefore any package that makes changes to a project during install (such as modifying the config file, adding project files, etc) don't work in PR. If you install a package using PR that has an install script then it adds the package but doesn't do anything else.

This is why ASP.NET apps aren't formally supported yet. For many ASP.NET-specific packages they need to update the system.web or system.webserver sections of the config file and/or add files to the project that can then be compiled into code. That simply doesn't work in PR. Since it can be very hard to know what a package does without opening it up and looking at the install script the current recommendation has been to stick with PC. In some cases PR has been updated to support some features but because of transient package resolution this doesn't work unless you explicitly include a package. That defeats one of the benefits of PR.

So yes you can use PR with any project that supports PC but you have to be aware of any install scripts that won't run and manually make the changes yourself. If you have the expertise to do that then go for it. However be aware that future updates to packages may change things so each time you update a package you need to review the scripts. This adds an extra layer of work for little gain in most cases. Hence most people stick with PC. Note that you can mix this in the solution. For example at my company we use PR for everything except ASP.NET and WCF projects. These projects stick with PC while the rest of the code in the solution use PR.

binki commented

If it were possible to generate web.config at build-time with MSBuild targets hooks for incrementally building it, which people would only do if MS lead the effort by changing the templates to do so, it would be possible for ASP.NET-style projects to switch to PR in a clean way.

@binki, you can already do that. MSBuild tasks can generate/update config files at build time. That is how the AutoGenerateBindingRedirects property works. Packages can integrate into the build process with custom .props and .targets files. This is how the more complex packages work. As such a package can integrate into the build at any point in the process just like anything else.

What cannot be done via MSBuild is anything that is needed at design time such as generating user-editable files. Adding files to a project at build time is easily handled in MSBuild and, once again, already done by the SDK format when generating assembly info files. But design time (e.g. before the build) changes cannot be done.

binki commented

@CoolDadTx I understand that. What I’m saying is that web.config is considered a “user-editable file”. It doesn’t have to be if the ASP.NET tooling were updated to make it a generated file. Of course, that would be very difficult to do and would break a lot of things which assume it is user-editable.

@binki, web.config has to be editable because devs do edit it. It is no different than an app.config in every other project type. You said making this auto-generate would solve the PR issue for ASP.NET. I fail to see how this feature (which already works) solves the problem with migrating ASP.NET apps to PR. Config files are easy to change at build time. This isn't what makes updating ASP.NET apps hard. It's the other stuff like updating bundling rules when adding content files or modifying the config file when there are user-settable options inside it (e.g. identity providers).

Can't merge conflicts be detected and the dev prompted to solve them? Worst case, can't the user-modified sections which the PR changes be commented out (rather than wiped out), so the dev can see them after adding a package?

@hyankov Who is your comment directed to? I don't understand what you mean by a merge conflict as that would only apply to a PR. Since packages cannot modify configs at install time anymore (because there is no install) then the only file changed when adding a package is the project file (to add the package reference element).

Is there a right-click menu to convert a ASP.NET Web Forms application project to use PackageReference yet? If not, the problem is not fixed. Which isn't a surprise because it is clear that Microsoft could give a flying you know what about Web Forms. They already threw it under the bus with .NET Core. Instead, they want you to port your code to unreleased vaporware.

binki commented

@CoolDadTx

@binki, web.config has to be editable because devs do edit it. It is no different than an app.config in every other project type. You said making this auto-generate would solve the PR issue for ASP.NET. I fail to see how this feature (which already works) solves the problem with migrating ASP.NET apps to PR. Config files are easy to change at build time. This isn't what makes updating ASP.NET apps hard. It's the other stuff like updating bundling rules when adding content files or modifying the config file when there are user-settable options inside it (e.g. identity providers).

web.config doesn’t have to be editable. It could be built from other files, some which are user-edited and others which are transformations applied incrementally by targets from <PackageReference/>. What you’re saying is something like “web.config has to be editable because it currently is editable”. What I’m saying is that the <PackageReference/> approach would be a lot easier if Visual Studio were willing/able to run targets to generate web.config, default to web.config being in .gitignore, have a user-friendly way to store the edits that you would need to make to web.config in different files which automatically get applied to the web.config as it is generated, and public well-specified MSBuild targets that would collect information for generating web.config and run when it needs to be generated (such as after the user edits the user-editable files).

The same approaches can be extended to bundling rules. IMO, the system is broken if a file is both autogenerated and requires post-generation user edits before it works for them.

Making web.config built would make a lot of projects’ git repos a ton cleaner because they would be able to have less generated code in them. This gets us closer to the ideal of 0 boilerplate. It would allow projects’ git repos to contain exactly the code that is specific to that project and omit things which are needed for every project like FSharp assembly binding redirects (for non-ASP.NET projects, those are already autogenerated at build-time because app.config is transformed while it is being copied to bin. In ASP.NET projects, the web.config in the root of the repository has to be post-transform because that is where IISExpress looks when serving the project—which is one of the few reasons why VS still must implement the functionality where it can edit app.config/web.config for you if you right-click the error message about missing binding redirects).

@binki, while I agree that separating web.config into separate pieces (which you can already do by the way) would make it easier to autogenerate stuff. This doesn't really have anything to do with PR in ASP.NET projects. Your thoughts sound more like a feature request and therefore should probably be posted in the ASP.NET team. Breaking up web.config would not solve the PR issue with ASP.NET projects. It would simply lessen the things that need to be done to get it to work.

binki commented

@CoolDadTx

This doesn't really have anything to do with PR in ASP.NET projects.

I’m convinced it is a big part of it. The installation/uninstallation scripts that packages.config run primarily do things like edit app.config/web.config. Bundled assets are already solved. However, there is no way for a <PackageReference/> NuGet to edit app.config upon installation—which is a good thing. It enforces less boilerplate. .csproj files no longer generate a bunch of churn when updating or adding/removing packages to a project.

separating web.config into separate pieces (which you can already do by the way)

Where are the docs on this? I don’t expect NuGet package authors to write targets to work with one person’s way of autogenerating configuration files because there is not yet a right way to do so. Microsoft needs to make a guide on how to write a NuGet which can be installed into an ASP.NET project as <PackageReference/> and still work without requiring the user to read and manually do the steps outlined in install.ps1.

@binki, I'm afraid we'll have to disagree on this. Separating out the config file introduces way more problems then it solves (especially at runtime where multiple files are now needed) just to get PR to work and there are still cases where PR won't work with a package. Since ASP.NET is deprecated in lieu of ASP.NET Core (which focuses on programmatic configuration and JSON instead of web.config) I doubt MS would take the hit to implement such a feature vs just forcing everyone down the ASP.NET Core route.

Where are the docs on this?

configSource is what handles this. Some larger apps use it to separate their configurations out. Personally I find it harder to work with but I can see the draw for really large apps.

binki commented

Where are the docs on this?

configSource is what handles this. Some larger apps use it to separate their configurations out. Personally I find it harder to work with but I can see the draw for really large apps.

I know what configSource is and have looked at it. But what you linked is not a protocol for writing a <PackageReference/>-compatible NuGet package intended for consumption by ASP.NET.

Since ASP.NET is deprecated in lieu of ASP.NET Core

OK, so I am reading that is: MS does not intend to fix this issue. Thanks for the update!

OK, so I am reading that is: MS does not intend to fix this issue. Thanks for the update!

I don't work for MS so I cannot answer the official word on the matter but if you read all the information coming out, including .NET 5 then the writing is on the wall.

zendu commented

I see following error.


Microsoft Visual Studio

Operation failed

Project is not eligible for migration. Either the project is not packages.config based or doesn't support PackageReference yet. Visit https://docs.microsoft.com/en-us/nuget/reference/migrate-packages-config-to-package-reference for more information.

OK

Microsoft Visual Studio Enterprise 2022
Version 17.1.0 Preview 2.0 [31910.343.main]
VisualStudio.17.IntPreview/17.1.0-pre.2.0+31910.343.main
Microsoft .NET Framework
Version 4.8.04161

Installed Version: Enterprise

Visual C++ 2022 00476-80000-00000-AA668
Microsoft Visual C++ 2022

.NET Core Debugging with WSL 1.0
.NET Core Debugging with WSL

ASP.NET and Web Tools 2019 17.1.165.16736
ASP.NET and Web Tools 2019

ASP.NET Web Frameworks and Tools 2019 17.1.165.16736
For additional information, visit https://www.asp.net/

Azure App Service Tools v3.0.0 17.1.165.16736
Azure App Service Tools v3.0.0

Azure Functions and Web Jobs Tools 17.1.165.16736
Azure Functions and Web Jobs Tools

C# Tools 4.1.0-2.21558.9+518162cc0ccd9f90a309d4acdd5a22886865b77c
C# components used in the IDE. Depending on your project type and settings, a different version of the compiler may be used.

Common Azure Tools 1.10
Provides common services for use by Azure Mobile Services and Microsoft Azure Tools.

Fabric.DiagnosticEvents 1.0
Fabric Diagnostic Events

Microsoft Azure Service Fabric Tools for Visual Studio 17.0
Microsoft Azure Service Fabric Tools for Visual Studio

Microsoft Azure Tools for Visual Studio 2.9
Support for Azure Cloud Services projects

Microsoft JVM Debugger 1.0
Provides support for connecting the Visual Studio debugger to JDWP compatible Java Virtual Machines

Microsoft Library Manager 2.1.134+45632ee938.RR
Install client-side libraries easily to any web project

Microsoft MI-Based Debugger 1.0
Provides support for connecting Visual Studio to MI compatible debuggers

Microsoft Visual C++ Wizards 1.0
Microsoft Visual C++ Wizards

Microsoft Visual Studio Tools for Containers 1.2
Develop, run, validate your ASP.NET Core applications in the target environment. F5 your application directly into a container with debugging, or CTRL + F5 to edit & refresh your app without having to rebuild the container.

Microsoft Visual Studio VC Package 1.0
Microsoft Visual Studio VC Package

Node.js Tools 1.5.31027.1 Commit Hash:dac60d9b246a1d6a5daf23d223c933dbe1518465
Adds support for developing and debugging Node.js apps in Visual Studio

NuGet Package Manager 6.1.0
NuGet Package Manager in Visual Studio. For more information about NuGet, visit https://docs.nuget.org/

ProjectServicesPackage Extension 1.0
ProjectServicesPackage Visual Studio Extension Detailed Info

Razor (ASP.NET Core) 17.0.0.2152601+724154d925d7d9d26ebf8a73a66d5219aa320400
Provides languages services for ASP.NET Core Razor.

Snapshot Debugging Extension 1.0
Snapshot Debugging Visual Studio Extension Detailed Info

SQL Server Data Tools 17.0.62111.10130
Microsoft SQL Server Data Tools

TypeScript Tools 17.0.1029.2001
TypeScript Tools for Microsoft Visual Studio

Visual Basic Tools 4.1.0-2.21558.9+518162cc0ccd9f90a309d4acdd5a22886865b77c
Visual Basic components used in the IDE. Depending on your project type and settings, a different version of the compiler may be used.

Visual F# Tools 17.1.0-beta.21558.1+467d1b5daffaf2a3f0052fc366c91b11131e6528
Microsoft Visual F# Tools

Visual Studio Code Debug Adapter Host Package 1.0
Interop layer for hosting Visual Studio Code debug adapters in Visual Studio

Visual Studio Container Tools Extensions 1.0
View, manage, and diagnose containers within Visual Studio.

Visual Studio IntelliCode 2.2
AI-assisted development for Visual Studio.

Visual Studio Tools for Containers 1.0
Visual Studio Tools for Containers

Issue is missing Type label, remember to add a Type label

Can Microsoft please provide an official statement if PackageReference will or will not be supported by ASP.Net .NetFramework projects?

Under Project type support:

.NET Framework projects support PackageReference, but currently default to packages.config. To use PackageReference, migrate the dependencies from packages.config into your project file, then remove packages.config.

Under Project type support:

.NET Framework projects support PackageReference, but currently default to packages.config. To use PackageReference, migrate the dependencies from packages.config into your project file, then remove packages.config.

Only partially true, as @daniatic says ASP.Net projects currently only work with packages.config, if you try to migrate manually it fails in several ways.

See dotnet/project-system#2670

I'm referring to the docs, that state:

ASP.NET apps targeting the full .NET Framework include only limited support for PackageReference. C++ and JavaScript project types are unsupported

https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#project-type-support

Limited Support is linked to this specific issue. It is not easy to deduct, what limited support means. Is it limited support regarding the migration? Or is it limited support in general with asp.net with .net Framework? And what are these limitations? Will they be fixed? Am I supposed to read through the 91 preceding comments to get an answer? I could but I'm afraid that I won't get an thorough answer...

Only partially true, as @daniatic says ASP.Net projects currently only work with packages.config, if you try to migrate manually it fails in several ways.

What's the source? What are those ways?

Been using (hundreds of) PackageReference in ASP.NET WebForms apps for many years. No issues. I can't remember whether it was migrated automatically or manually (or a combination) since it's been a while, but we haven't looked back since.

See dotnet/project-system#2670

That's support for SDK-based projects. Not the same thing.

@khellang the two known issues that I'm aware of are config transforms and transient binding redirects. Note that you can use package references in any project but you have to be aware of the limitations as it isn't formally supported.

Config transforms used to be the biggest issue. Many packages, pre SDK, made changes to configs using Nuget's install/uninstall feature. This was dropped with package references so they can no longer make changes. The biggest package impacted by this was EF but there were many others including Dotnet Compilers. Because PRs do not run the install/uninstall scdripts then no changes are made. If the config changes were never really needed (e.g. EF) then you would never notice the issue. But Roslyn, for example, wouldn't work properly. To remedy this the package format was updated to support build files (targets and props). Most packages were updated to use this route and so you don't see the problem but older packages would continue to have problems.

Another area is transient dependencies which PRs support but package.config does not. This problem tends to rear its head when you upgrade packages. The problem comes in when you have multiple dependencies on the same third party package. You can get into versioning conflicts so you have to use binding redirects. With PRs you only need to depend on the packages your project uses and Nuget will pull in the rest but that doesn't work properly without SDK projects. In that case you can see runtime errors because the binding redirects aren't updated for transient dependencies unless you're using SDK projects. If your code happens to build in the "correct" order you may not see this problem for years but at some point an upgrade of a package or a change in build order can suddenly reveal that your project has a bad binding. The general workaround is to add the transient dependency as a direct dependency. This resolves the issue generally bad at the cost of an 'unneeded" dependency.

We too have a couple of ASP.NET projects using PRs but it is not a supported situation and we have docs that discuss how to handle the issues it causes. In at least one case we reverted back from PRs when trying to update the project at a later date because we could not get around the binding issues. So if you have it working in your projects then great for you, but it still isn't formally supported.