VS Templates with Private NuGet Packages?

Topics: General
Jul 22, 2012 at 11:19 PM

Hi,

I'm looking at creating some Visual Studio templates that reference some nuget packages from a internally-hosted feed. I've read through the instructions on creating templates with packages here, but it doesn't seem to suggest any way to point packages at a private feed.

Is it possible to create VS Templates with packages that point to a private feed?

 

Cheers,
Brad

Jul 23, 2012 at 7:32 PM

No, it's not possible to point to a private feed.

Jul 26, 2012 at 12:03 AM
Edited Sep 6, 2012 at 10:22 PM
You can but not using the NuGet wizard. What you have to do is create your own wizard.

http://msdn.microsoft.com/en-us/library/ms185301.aspx

IN your custom wizard project add a regference to the NuGetVisualStudio assembly found in C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft Corporation\NuGet Package Manager\2.0.30619.9119\NuGet.VisualStudio.dll

Add an import statment in the class that implements your wizard:

        [Import]
        internal IVsPackageInstaller NuGetPackageInstaller { get; set; }

In the RunStart method add code to initialize the NuGet package installer (automationObject is the first param to RunStart):

if (runKind == WizardRunKind.AsNewProject)
{
    using (var serviceProvider = new ServiceProvider((IServiceProvider)automationObject))
    {
        var componentModel = (IComponentModel)serviceProvider.GetService(typeof(SComponentModel));
        using (var container = new CompositionContainer(componentModel.DefaultExportProvider))
        {
            container.ComposeParts(this);
        }
    }

    if (NuGetPackageInstaller == null)
    {
        MessageBox.Show("NuGet Package Manager not available.");

        throw new WizardBackoutException("NuGet Package Manager not available.");
    }
}

 

Now you can use the NuGetPackageInstaller to install any package from any source. In the ProjectFinishedGenerating(Project project) method of your IWiizard implementation class you can add nuget packages to the project as needed by calling  NuGetPackageInstaller.InstallPackage (which is what NuGet does internally when you use the NuGet Wizard). I wrote a method to do this that uses an XML configuration (whcih would need to be installed along with your template) file where I can list my packages by project name, for example:

            if (NuGetPackageInstaller != null)
            {
                foreach (PackageType package in packages)
                {
                    dte.StatusBar.Text = string.Format("Installing NuGet package {0}.{1}", package.id, package.version);

                    NuGetPackageInstaller.InstallPackage(package.source, project, package.id, package.version, true);
                    }
                }
            }

Jul 26, 2012 at 1:35 AM
Edited Jul 26, 2012 at 1:58 AM

Actually there is another way to do this as well and it might be easier for you than my previous post. Using the method in my previous post you have fine-grained, complete control of what packages get installed and from what sources. However the NuGet Visual Studio Template supports reading the package source from the registry. If you install MVC4 and then look at

C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ProjectTemplates\CSharp\Web\1033\MvcWebApplicationProjectTemplatev4.0.cshtml.zip

And in that zip file look at the .csproj you will see they use the NuGet wizard to load packages for MVC4:

     <WizardExtension>
        <Assembly>NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</Assembly>
        <FullClassName>NuGet.VisualStudio.TemplateWizard</FullClassName>
    </WizardExtension>
    <WizardData>
        <packages repository="registry" keyName="AspNetMvc4VS2010" isPreunzipped="true">
            <package id="EntityFramework" version="5.0.0-rc" skipAssemblyReferences="true" />

As you can see the <packages> element has a repository attribute that specifies "registry" and a keyName attribute that specifies "AspNetMvc4VS2010"

If you look in the registry at: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\NuGet\Repository you will see the string value of AspNetMvc4VS2010 with a value that points to C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET MVC 4\Packages\

Go look in C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET MVC 4\Packages\ and you will see all the MVC4 packages.

You can add a new registry entry for your repository call it "MyRespository" and set it the value to the path that contains your repository (url, local machine, unc).Then in your wizard specify the name of your registry key

    <WizardExtension>
        <Assembly>NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</Assembly>
        <FullClassName>NuGet.VisualStudio.TemplateWizard</FullClassName>
    </WizardExtension>
    <WizardData>
        <packages repository="registry" keyName="MyRespository" isPreunzipped="true">
            <package id="EntityFramework" version="5.0.0-rc" skipAssemblyReferences="true" />

The only issue wtith this method is that ALL of your packages must come from your repository. Using the wizard method in my previous post you can get some packages from the web and others from an internal repository. You can also choose to install packages based on some criteria (perhaps as part of your XML config)

Also note the isPreUnzipped attribute. If you set this tor true then NuGet will expect all the packages to be unzipped in the repository (optimization for better UI experience). If you just want to store the .nupkg files you will wan to set isPreUnzipped="false"

Jul 31, 2012 at 6:17 PM

Very nice post PhllpSchrdr. It looks like you know more about NuGet than I do :)

Jun 24, 2013 at 4:11 PM
Hi PhllpSchrdr,

I have been trying to implement VSIX custom wizard referring your code above. Code doesnt get compiled for following line -
using (var serviceProvider = new ServiceProvider((IServiceProvider)automationObject))
I have added 2 references - Microsoft.VisualStudio.OLE.Interop (Version 7.1.40304.0) and Microsoft.VisualStudio.Shell.dll (Version 2.0.0.0)
Then it asked me to add this assembly - Microsoft.VisualStudio.OLE.Interop

After doing all this, I get following exceptions -

Error 2 The best overloaded method match for 'Microsoft.VisualStudio.Shell.ServiceProvider.ServiceProvider(Microsoft.VisualStudio.OLE.Interop.IServiceProvider)' has some invalid arguments C:\samples\Multi-Project Templates Sample\Multi-Project Templates Sample Solution\Template_Wizard\IWizardImplementation.cs 70 50 Template Wizard
Error 3 Argument 1: cannot convert from 'System.IServiceProvider' to 'Microsoft.VisualStudio.OLE.Interop.IServiceProvider' C:\samples\Multi-Project Templates Sample\Multi-Project Templates Sample Solution\Template_Wizard\IWizardImplementation.cs 70 71 Template Wizard

I would really appriciate if you could post sample code, I am not sure but seem I badly messed up with VS2010 and 2012 SDK assemblies.

Thanks,
Satish