Search code examples
visual-studiotemplatesnugetvsixproject-template

VS Template not installing Nuget Packages


I am building a Visual Studio 2015 Web API 2 template for my company. It is a multiproject template. I have it all setup and it is working fine except for the Nuget packages. They will not install.

I followed the steps outlined here: https://learn.microsoft.com/en-us/nuget/visual-studio-extensibility/visual-studio-templates.

Here is what I have setup:

  • The .nupkg files in my vsix project. If I unzip the vsix, I see them in the Packages folder. (I copied these .nupkg files from the packages folder in my original solution I made.)

  • I have listed every Nuget package as an asset in my source.extension.vsixmanifest file (found in the vsix project).

Here is an example:

<Asset Type="AutoMapper.5.2.0.nupkg" d:Source="File" Path="Packages\AutoMapper.5.2.0.nupkg" d:VsixSubPath="Packages" />
  • In my sub-project .vstemplate files I have added the nuget wizard and listed the packages needed for that template.

Here is an example of one of my subprojects (the first wizard is my vsix project):

<WizardExtension>
    <Assembly>MyVsixProject, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=52156a0ac017d515</Assembly>
    <FullClassName>MyVsixProject.WizardImplementation</FullClassName>
</WizardExtension>
<WizardExtension>
    <Assembly>NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</Assembly>
    <FullClassName>NuGet.VisualStudio.TemplateWizard</FullClassName>
</WizardExtension>
<WizardData>
    <packages repository="extension" repositoryId="MyVsixProject.8b0b584a-d7ab-4608-e317-84e1aa773a01">
        <package id="AutoMapper" version="5.2.0" />            
        <package id="EntityFramework" version="6.1.3" />
        <package id="Microsoft.Net.Compilers" version="1.3.2" />
        <package id="SimpleInjector" version="3.2.0" />            
    </packages>
</WizardData>

Near as I can tell, I am following the instructions.

However, when I run the template, the solution level folder does not have a packages folder and all my nuget based references are broken.


Solution

  • Turns out that you have to have all the Nuget artifacts gone from your template. (As if it has not ever been installed.) Then the Nuget wizard will install correctly.

    The link I mentioned above lists this as a "Best Practice" not a "It will not work if you don't do it", like it really is.

    This is my script that I run in my build engine to remove the nuget stuff from my working project:

    # DO NOT CALL THIS DIRECTLY!  IT SHOULD ONLY BE CALLED BY THE BUILD SYSTEM.
    # IF YOU CALL THIS DIRECTLY then the projects will have all of their nuget references removed.
    #
    # For the template to be able to install the nuget stuff, it needs it to be in a state as if
    # it has never been installed.  This script removes:
    #     • The packages.config files
    #     • Removes <None Include="packages.config" /> from any csproj files
    #     • Compiler references that are added by nuget
    #     • Removes any references from csproj files that have a hint path that contains '..\packages\
    
    # Find all packages.config files and delete them
    get-childitem ./ -include packages.config -recurse | foreach ($_) {remove-item $_.fullname -force}
    
    # Find all .csproj files 
    $csProjFiles = get-childitem ./ -include *.csproj -recurse 
    
    # Remove the packages.config include from the csproj files.
    $csProjFiles | foreach ($_) {$currentFile = $_; (get-content $_) | Where-Object {$_ -notmatch 'Include="packages.config"'} | Set-Content $currentFile -force}
    
    # Remove any compiler references added by the compiler nuget packages.
    $csProjFiles | foreach ($_) {$currentFile = $_; (get-content $_) | Where-Object {$_ -notmatch 'build\\Microsoft.Net.Compilers.props'} | Set-Content $currentFile -force}
    $csProjFiles | foreach ($_) {$currentFile = $_; (get-content $_) | Where-Object {$_ -notmatch 'build\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props'} | Set-Content $currentFile -force}
    
    # Remove any references that have a hint path that contains '..\packages\'
    foreach ($csProjFile in $csProjFiles){
        [xml] $csProjFileXml = get-content $csProjFile;
        foreach ($itemGroup in $csProjFileXml.Project.ItemGroup) {  
            foreach ($reference in $itemGroup.Reference) {
                foreach ($hintPath in $reference.HintPath){
                    if ($hintPath -like '*..\packages\*'){
                        $itemGroup.RemoveChild($reference)
                    }           
                }           
            }
        }
        $csProjFileXml.Save($csProjFile)
    }