Archive

Archive for the ‘NuGet’ Category

Have Your NuGet Package Install Itself As A Development Dependency

September 18th, 2013 3 comments

The Problem

I recently blogged about a NuGet package I made that allows you to easily turn your own projects into a NuGet package, making it easy to share your work with the world.  One problem I ran into with this was that if somebody used my NuGet package to create their package, their NuGet package listed my NuGet package as a dependency.  This meant that when they distributed their package to others, it would install both their package and mine.  Obviously this is undesirable, since their library has no dependency on my package; my package was meant purely to help them with the development process.

Unfortunately there wasn’t much I could do about this; that is, until the release of NuGet 2.7 which came out a few weeks ago.  You can see from the release notes that they added a new developmentDependency attribute that can be used.  This made things a bit better because it allowed users who installed my package to go into their project’s packages.config file, find the element corresponding to my package, and add the developmentDependency=”true” attribute to it.

So this was better, but still kinda sucked because it required users to do this step manually, and most of them likely aren’t even aware of the problem or that there was a fix for it.  When users (and myself) install a package they want it to just work; which is why I created a fix for this.

 

The Fix

Update – As of NuGet 2.8 there is a built-in way to do the fix below. See this post for more info.

The nice thing about NuGet packages is that you can define PowerShell scripts that can run when users install and uninstall your packages, as is documented near the bottom of this page.  I’ve created a PowerShell script that will automatically go in and adjust the project’s packages.config file to mark your package as a development dependency.  This means there is no extra work for the user to do.

The first thing you need to do (if you haven’t already) is include an Install.ps1 script in your NuGet package’s .nuspec file.  If you don’t currently use a .nuspec file, check out this page for more information.  I also include a sample .nuspec file at the end of this post for reference.  The line to add to your .nuspec file will look something like this:

<file src=”NuGetFiles\Install.ps1″ target=”tools\Install.ps1″ />

and then the contents of Install.ps1 should look like this:

param($installPath, $toolsPath, $package, $project)

# Edits the project's packages.config file to make sure the reference to the given package uses the developmentDependency="true" attribute.
function Set-PackageToBeDevelopmentDependency($PackageId, $ProjectDirectoryPath)
{
    function Get-XmlNamespaceManager($XmlDocument, [string]$NamespaceURI = "")
    {
        # If a Namespace URI was not given, use the Xml document's default namespace.
	    if ([string]::IsNullOrEmpty($NamespaceURI)) { $NamespaceURI = $XmlDocument.DocumentElement.NamespaceURI }	

	    # In order for SelectSingleNode() to actually work, we need to use the fully qualified node path along with an Xml Namespace Manager, so set them up.
	    [System.Xml.XmlNamespaceManager]$xmlNsManager = New-Object System.Xml.XmlNamespaceManager($XmlDocument.NameTable)
	    $xmlNsManager.AddNamespace("ns", $NamespaceURI)
        return ,$xmlNsManager		# Need to put the comma before the variable name so that PowerShell doesn't convert it into an Object[].
    }

    function Get-FullyQualifiedXmlNodePath([string]$NodePath, [string]$NodeSeparatorCharacter = '.')
    {
        return "/ns:$($NodePath.Replace($($NodeSeparatorCharacter), '/ns:'))"
    }

    function Get-XmlNodes($XmlDocument, [string]$NodePath, [string]$NamespaceURI = "", [string]$NodeSeparatorCharacter = '.')
    {
	    $xmlNsManager = Get-XmlNamespaceManager -XmlDocument $XmlDocument -NamespaceURI $NamespaceURI
	    [string]$fullyQualifiedNodePath = Get-FullyQualifiedXmlNodePath -NodePath $NodePath -NodeSeparatorCharacter $NodeSeparatorCharacter

	    # Try and get the nodes, then return them. Returns $null if no nodes were found.
	    $nodes = $XmlDocument.SelectNodes($fullyQualifiedNodePath, $xmlNsManager)
	    return $nodes
    }

    # Get the path to the project's packages.config file.
    Write-Debug "Project directory is '$ProjectDirectoryPath'."
    $packagesConfigFilePath = Join-Path $ProjectDirectoryPath "packages.config"

    # If we found the packages.config file, try and update it.
    if (Test-Path -Path $packagesConfigFilePath)
    {
        Write-Debug "Found packages.config file at '$packagesConfigFilePath'."

        # Load the packages.config xml document and grab all of the <package> elements.
        $xmlFile = New-Object System.Xml.XmlDocument
        $xmlFile.Load($packagesConfigFilePath)
        $packageElements = Get-XmlNodes -XmlDocument $xmlFile -NodePath "packages.package"

        Write-Debug "Packages.config contents before modification are:`n$($xmlFile.InnerXml)"

        if (!($packageElements))
        {
            Write-Debug "Could not find any <package> elements in the packages.config xml file '$packagesConfigFilePath'."
            return
        }

        # Add the developmentDependency attribute to the NuGet package's entry.
        $packageElements | Where-Object { $_.id -eq $PackageId } | ForEach-Object { $_.SetAttribute("developmentDependency", "true") }

        # Save the packages.config file back now that we've changed it.
        $xmlFile.Save($packagesConfigFilePath)
    }
    # Else we coudn't find the packages.config file for some reason, so error out.
    else
    {
        Write-Debug "Could not find packages.config file at '$packagesConfigFilePath'."
    }
}

# Set this NuGet Package to be installed as a Development Dependency.
Set-PackageToBeDevelopmentDependency -PackageId $package.Id -ProjectDirectoryPath ([System.IO.Directory]::GetParent($project.FullName))

And that’s it.  Basically this script will be ran after your package is installed, and it will parse the project’s packages.config xml file looking for the element with your package’s ID, and then it will add the developmentDependency=”true” attribute to that element.  And of course, if you want to add more code to the end of the file to do additional work, go ahead.

So now your users won’t have to manually edit their packages.config file, and your user’s users won’t have additional, unnecessary dependencies installed.

 

More Info

As promised, here is a sample .nuspec file for those of you that are not familiar with them and what they should look like.  This is actually the .nuspec file I use for my package mentioned at the start of this post.  You can see that I include the Install.ps1 file near the bottom of the file.

<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
  <metadata>
    <id>CreateNewNuGetPackageFromProjectAfterEachBuild</id>
    <version>1.4.2</version>
    <title>Create New NuGet Package From Project After Each Build</title>
    <authors>Daniel Schroeder,iQmetrix</authors>
    <owners>Daniel Schroeder,iQmetrix</owners>
    <licenseUrl>https://newnugetpackage.codeplex.com/license</licenseUrl>
    <projectUrl>https://newnugetpackage.codeplex.com/wikipage?title=NuGet%20Package%20To%20Create%20A%20NuGet%20Package%20From%20Your%20Project%20After%20Every%20Build</projectUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Automatically creates a NuGet package from your project each time it builds. The NuGet package is placed in the project's output directory.
	If you want to use a .nuspec file, place it in the same directory as the project's project file (e.g. .csproj, .vbproj, .fsproj).
	This adds a PostBuildScripts folder to your project to house the PowerShell script that is called from the project's Post-Build event to create the NuGet package.
	If it does not seem to be working, check the Output window for any errors that may have occurred.</description>
    <summary>Automatically creates a NuGet package from your project each time it builds.</summary>
    <releaseNotes>Updated to use latest version of New-NuGetPackage.ps1.</releaseNotes>
    <copyright>Daniel Schroeder 2013</copyright>
    <tags>Auto Automatic Automatically Build Pack Create New NuGet Package From Project After Each Build On PowerShell Power Shell .nupkg new nuget package NewNuGetPackage New-NuGetPackage</tags>
  </metadata>
  <files>
    <file src="..\New-NuGetPackage.ps1" target="content\PostBuildScripts\New-NuGetPackage.ps1" />
    <file src="Content\NuGet.exe" target="content\PostBuildScripts\NuGet.exe" />
    <file src="Content\BuildNewPackage-RanAutomatically.ps1" target="content\PostBuildScripts\BuildNewPackage-RanAutomatically.ps1" />
    <file src="Content\UploadPackage-RunManually.ps1" target="content\PostBuildScripts\UploadPackage-RunManually.ps1" />
    <file src="Content\UploadPackage-RunManually.bat" target="content\PostBuildScripts\UploadPackage-RunManually.bat" />
    <file src="tools\Install.ps1" target="tools\Install.ps1" />
    <file src="tools\Uninstall.ps1" target="tools\Uninstall.ps1" />
  </files>
</package>

 

Happy coding!

Automatically Create Your Project’s NuGet Package Every Time It Builds, Via NuGet

June 22nd, 2013 15 comments

So you’ve got a super awesome library/assembly that you want to share with others, but you’re too lazy to actually use NuGet to package it up and upload it to the gallery; or maybe you don’t know how to create a NuGet package and don’t have the time or desire to learn.  Well, my friends, now this can all be handled for you automatically.

A couple weeks ago I posted about a new PowerShell script that I wrote and put up on CodePlex, called New-NuGetPackage PowerShell Script, to make creating new NuGet packages quick and easy.  Well, I’ve taken that script one step further and use it in a new NuGet package called Create New NuGet Package From Project After Each Build (real creative name, right) that you can add to your Visual Studio projects.  The NuGet package will, you guessed it, pack your project and its dependencies up into a NuGet package (i.e. .nupkg file) and place it in your project’s output directory beside the generated dll/exe file.  Now creating your own NuGet package is as easy as adding a NuGet package to your project, which if you’ve never done before is dirt simple.

I show how to add the NuGet package to your Visual Studio project in the New-NuGetPackage PowerShell Script documentation (hint: search for “New NuGet Package” (include quotes) to find it in the VS NuGet Package Manager search results), as well as how you can push your package to the NuGet Gallery in just a few clicks.

Here’s a couple screenshots from the documentation on installing the NuGet Package:

NavigateToManageNugetPackages   InstallNuGetPackageFromPackageManager

Here you can see the new PostBuildScripts folder it adds to your project, and that when you build your project, a new .nupkg file is created in the project’s Output directory alongside the dll/exe.

FilesAddedToProject     NuGetPackageInOutputDirectory

So now that packaging your project up in a NuGet package can be fully automated with about 30 seconds of effort, and you can push it to the NuGet Gallery in a few clicks, there is no reason for you to not share all of the awesome libraries you write.

Happy coding!

Create and publish your NuGet package in one click with the New-NuGetPackage PowerShell script

June 7th, 2013 No comments

I’ve spent a good chunk of time investigating how nuget.exe works and creating a PowerShell script called New-NuGetPackage to make it dirt simple to pack and push new NuGet packages.

Here’s a list of some of the script’s features:

  • Create the .nupkg package file and optionally push the package to the NuGet Gallery (or a custom gallery).
  • Can be ran from Windows Explorer (i.e. double-click it) or called via PowerShell if you want to be able to pass in specific parameters or suppress prompts.
  • Can prompt user for version number and release notes (prompts are prefilled with previous version number and release notes) or can suppress all prompts.

This makes packing and pushing your NuGet packages quick and easy, whether doing it manually or integrating it into your build system.  Creating NuGet packages wasn’t overly complicated before, but this makes it even simpler and less tedious.

Go to the codeplex page to download the script and start automating your NuGet package creating today.  The codeplex documentation describes the script in much more detail, as well as step by step instructions on how to get setup to start using it.

[UPDATE] I have also used this script in a new NuGet package that will automatically create a NuGet package for your own projects without you having to do anything. Read about it here. [/UPDATE]

 

Additional NuGet Information

During my investigation I compiled a list of what happens when doing “nuget spec” and “nuget pack” against the various different file types (e.g. dll vs. project vs. nuspec).  Someone else may find this information useful, so here it is:

Spec a Project or DLL directly (e.g. "nuget spec PathToFile"):
- Creates a partial .nuspec; still has placeholder info for some fields (e.g. Id, Dependencies).
- Creates [full file name with extension].nuspec file.
- The generated .nuspec file is meant to still be manually updated before making a package from it.

// TestProject.csproj.nuspec
<?xml version="1.0"?>
<package >
  <metadata>
    <id>C:\dev\TFS\RQ\Dev\Tools\DevOps\New-NuGetPackage\TestProject\TestProject\TestProject.csproj</id>
    <version>1.0.0</version>
    <authors>Dan Schroeder</authors>
    <owners>Dan Schroeder</owners>
    <licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
    <projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
    <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Package description</description>
    <releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
    <copyright>Copyright 2013</copyright>
    <tags>Tag1 Tag2</tags>
    <dependencies>
      <dependency id="SampleDependency" version="1.0" />
    </dependencies>
  </metadata>
</package>
=====================================================================
Spec a DLL using "nuget spec" from the same directory:
- Creates a partial .nuspec; still has placeholder info for some fields (e.g. Id, Dependencies).
- Creates "Package.nuspec" file.
- The generated .nuspec file is meant to still be manually updated before making a package from it.

// Package.nuspec
<?xml version="1.0"?>
<package >
  <metadata>
    <id>Package</id>
    <version>1.0.0</version>
    <authors>Dan Schroeder</authors>
    <owners>Dan Schroeder</owners>
    <licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
    <projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
    <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Package description</description>
    <releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
    <copyright>Copyright 2013</copyright>
    <tags>Tag1 Tag2</tags>
    <dependencies>
      <dependency id="SampleDependency" version="1.0" />
    </dependencies>
  </metadata>
</package>
=====================================================================
Spec a Project using "nuget spec" from the same directory:
- Creates a template .nuspec using the proper properties and dependencies pulled from the file.
- Creates [file name without extension].nuspec file.
- The generated .nuspec file can be used to pack with, assuming you are packing the Project and not the .nuspec directly.

// TestProject.nuspec
<?xml version="1.0"?>
<package >
  <metadata>
    <id>$id$</id>
    <version>$version$</version>
    <title>$title$</title>
    <authors>$author$</authors>
    <owners>$author$</owners>
    <licenseUrl>http://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
    <projectUrl>http://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
    <iconUrl>http://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>$description$</description>
    <releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
    <copyright>Copyright 2013</copyright>
    <tags>Tag1 Tag2</tags>
  </metadata>
</package>
=====================================================================
Pack a Project (without accompanying template .nuspec):
- Does not generate a .nuspec file; just creates the .nupkg file with proper properties and dependencies pulled from project file.
- Throws warnings about any missing data in the project file (e.g. Description, Author), but still generates the package.

=====================================================================
Pack a Project (with accompanying template .nuspec):
- Expects the [file name without extension].nuspec file to exist in same directory as project file, otherwise it doesn't use a .nuspec file for the packing.
- Throws errors about any missing data in the project file if the .nuspec uses tokens (e.g. $description$, $author$) and these aren't defined in the project, so the package is not generated.

=====================================================================
Cannot pack a .dll directly

=====================================================================
Pack a .nuspec:
- Creates the .nupkg file with properties and dependencies defined in .nuspec file.
- .nuspec file cannot have any placeholder values (e.g. $id$, $version$).

Force your ClickOnce app to update without prompting user – Now on NuGet!

March 8th, 2013 4 comments

A while ago I blogged about a powershell script I made that would automatically update your ClickOnce project file’s Minimum Required Version to the latest version of your application so that users would not be presented with the “There is an update for this application. Do you want to install it?” prompt; instead the application would just automatically download and install the update.  This is nice because it’s one less prompt the end-user has to see, and from a security standpoint it means that your users will be forced to always use the latest version of the app.

There was a bit of setup to get this to work.  You had to make sure the powershell script was in the proper directory and add a post-build event to your project.  I’m happy to announce that I’ve significantly updated the powershell script with more features and bug fixes, and you can now install it from Nuget, which will handle all of the setup for you.  So now making sure that your end-users are always using the latest version of your application is as easy as adding the AutoUpdateProjectsMinimumRequiredClickOnceVersion NuGet package to your ClickOnce project.

ManageNuget

Install

FileAdded

As you can see in the last screenshot, it adds a new “PostBuildScripts” folder to your project that contains the powershell script that is ran from the project’s post-build event.

A couple caveats to note.  Because this uses PowerShell it means that it can only be ran on Windows machines (sorry Mac and Unix).  Also, because the powershell script modifies the .csproj/.vbproj file outside of Visual Studio, the first time you do a build after creating a new ClickOnce version, if you have any files from that project open you will be prompted to reload the project.  In order to prevent this from closing your open tabs, I recommend installing Scott Hanselman’s Workspace Reloader Visual Studio extension.

I’ve also created a CodePlex site to host this open source project.

I hope you find this helpful.  Feel free to leave a comment.