Coding

Packaging Contract Assemblies Like A Pro

This is a short follow up to my NuGet Like A Pro post.  I left an additional step out of that post, even though I almost always need to to do it.  I didn’t think this next step was widely applicable, and wanted to position the previous post as a “Super Duper Happy Path” that most people could follow with out confusing digressions.

However, I did my self a disservice by leaving it out, because now whenever I need to refresh my memory by reading my own post, I am left still having to figure out this one step again.  So, I’m going to post it here so that I’ve got all my documentation in one place.

Contract Assemblies

If you don’t know what they are, then you probably don’t need to read this post.  However, if you are curious they are an artifact created when using Code Contracts.

Code Contracts provide a language-agnostic way to express coding assumptions in .NET programs. The contracts take the form of preconditions, postconditions, and object invariants. Contracts act as checked documentation of your external and internal APIs. The contracts are used to improve testing via runtime checking, enable static contract verification, and documentation generation.

In other words, Code Contracts are another form of static analysis and client code needs to know about your contracts in order to properly evaluate their own contracts.  This is where the contract assembly comes in, it provides the contract information about the assembly in your package.

So you need to create this assembly, put it in your nuget package so that the contract checker can find it, and then give nuget a hint indicating that only the “normal” assembly should get a project reference, while the contract assembly (which only contains metadata) should not be referenced by the project.

Creating the Contract Assembly

This step is easy, but I will include it for those who are new.  First one must visit the Visual Studio Gallery and download the tools.  Once the tools are installed, the Visual Studio project properties page will grow a new blade, pictured below.

Code Contracts Control Panel
Code Contracts Control Panel

I check almost everything in the “Static Checking” section and leave “Runtime Checking” alone.  It would be off topic to explain why in this post, but you can visit the Code Contracts website and make your own decision.  You can also choose not to turn anything on, yet still build the Contract Reference Assembly.  This will let clients using Contracts know that you don’t have any.

By default, the Contract Reference Assembly is not configured to build, but as you can see in the red rectangle, I have turned it on.

Now when I build my project, the additional assembly is created (below the build output folder, in a subfolder called “CodeContracts”)

The Contract Assembly
The Contract Assembly

Adding to the package

Now that you have the assembly you can let nuget know about it by adding a file reference to the nuspec file.  This reference goes in the files node, which is a child of the package node.  I usually put it right after the metadata node:

  </metadata>
  <files>
    <file src="bin\Debug\CodeContracts\TemporaryFile.Contracts.dll" target="lib\net45" />
  </files>
</package>

After rebuilding, you will see that the Contract assembly is now packaged with the normal library.

Packaged
Packaged

However, if you were to use this package as is, NuGet would add a reference to the Contracts assembly as well as the library.  To prevent that, we provide NuGet a white list of assemblies which should be referenced, and it will ignore the rest.

To do this, add a child node to metadata called “references” and a “reference” node for the normal library.

    <references>
      <reference file="TemporaryFile.dll" />
    </references>
  </metadata>
  ...
</package>

Now rebuild again, and the NuGet Package Explorer will indicate that the assembly references have been “filtered”.

Filtered
Filtered

Conclusion

So, to distribute Contract Assemblies (or other any assembly which should not be referenced) follow the steps above.  First create the assembly you want to distribute.  Next add a file reference to the nuspec which points at the new assembly.  Then, add a references node and add references to each assembly which should be referenced (the new assembly should not be in this section, but the original assembly should be).  After filtering your references you are ready to go.  Upload your package to your favorite feed (nuget.org, myget.org, proget, etc…) and pour yourself a drink.

Coding

NuGet like a Pro, the MSBuild way

Back in 2012 I posted an article on this blog called “Creating Packages with NuGet the MSBuild Way“. That post described an MSBuild-integrated method to create NuGet packages from your own source code. It has remained one of my most popular posts. Like many popular things on the internet, it has been out of date for sometime now. When I check on my blog and see that the most visited article of the day is “Creating Packages with NuGet the MSBuild Way“, I wonder if visitors know that its out of date. Do they dismiss me as a crank and leave the page immediately? Even worse: do they follow the outdated and complicated recipe described in the post?

In 2012, I needed to integrate packaging into MSBuild because I could not find a plug-in for CruiseControl.net that would create NuGet packages.  There may be a plug-in now, I don’t know.  After a couple years creating NuGet packages, many tools I use from day to day have changed including my source control and continuous integration options. Even though I now have the option to create CI builds on TFS, where NuGetter is available, I still use MSBuild to configure my projects to create packages every time I hit F6.

I have a new, simple process for setting this up and it usually takes me about five minutes to convert an existing project to produce a NuGet package as part of it’s build output. I start with some existing code, enable package restore, make one small edit to my project file, and build. That’s all it takes to get the first package in the first five minutes.

If I want to continue customizing after creating the first package, I pull the nuspec file out of the existing package, put the nuspec file next to my project file, and customize from there, that’s the second five minutes.

Finally, I make some small modifications to the nuget.targets file provided by package restore in order to automate some cleanup, that takes about five more minutes.

It takes me about fifteen minutes to get everything setup just how I like it, but if your needs are simple, you can be done in five minutes. Hopefully this simplified process will be much more useful to my future visitors and help you, dear reader, understand how easy it is to create NuGet packages for your open source (or private) packages.  So read on for all the details!

Build

Start with Some Code

Any Class Library will do.  The important thing is that its something you want to share.  Either its your open source project, or a bit of private code which you’d like to share with your customers, other departments in your organization, or just your team.

For this example I’ve created a super-cool class called TemporaryFile.  TemporaryFile provides a disposable wrapper around a FileInfo which deletes the file when the Dispose method executes.  This allows the user to control the lifetime of the temporary file with a using statement, or trust the garbage collector to take care of it during finalization.  I find myself creating and deleting temporary files for a certain class of unit tests, and a wrapper like this takes alot of the grunt work out of the task.

namespace TemporaryFile
{
    using System;
    using System.IO;
    using ApprovalUtilities.Utilities;

    public class Temp : IDisposable
    {
        private readonly FileInfo backingFile;

        public Temp(string name)
        {
            this.backingFile =
                            new FileInfo(PathUtilities.GetAdjacentFile(name));
            this.backingFile.Create().Close();
        }

        ~Temp()
        {
            this.Dispose();
        }

        public FileInfo File
        {
            get
            {
                return this.backingFile;
            }
        }

        public void Dispose()
        {
            // File on the file system is not a managed resource
            if (this.backingFile.Exists)
            {
                this.backingFile.Delete();
            }
        }
    }
}

Notice that the class uses a method from PathUtilities in ApprovalUtilities (part of ApprovalTests).  I added this method call solely to generate a dependency on another package, which in turn helps demonstrate how much metadata NuGet can infer for you without explicit configuration.  Relying on inference is a big part of keeping this process fast an simple–as long as the inferred information meets your needs.

However, the way I used PathUtilities here turned out to be a bug.  So don’t copy this code.  It is useful to have a bug in the code when doing demos, so I left it in there.  If you think the temporary file idea sounds super useful, then a bug free version is now available as part of ApprovalUtilities.

If you examine the NugetLikeAPro repository on GitHub, TemporaryFile is a plain old .net # class library.  It has a test project but not much else is going on.

Enable Package Restore

The NuGet documentation is very good, and covers a lot of ground but if it covered everything then you wouldn’t need me!  I think that “Using NuGet without committing packages to source control” contains a lot of good information about what happens when you click the “Enable Package Restore” menu item, but it does not emphasize something very important to us as package creators: the NuGet.Build package installed by package restore contains everything you need to convert a project to create packages.

When you enable package restore, two packages are added to your solution: NuGet.CommandLine and NuGet.Build.  You could add these yourself, but that would be two steps instead of one.  Package restore also performs a third, more tedious step for you: it updates your project files to reference a new MSBuild script and adds a $(SolutionDir) property so that the new script can do its work.  The project files need to reference an MSBuild script (NuGet.targets) in order to run the package restore target before the build.  The package restore article doesn’t mention that the script also defines a build package target, which can create a package for you after the build completes.

So, lets enable package restore on TemoraryFile and see what we get.

Image of the Visual Studio solution context menu
Enable Package Restore

Just as promised by the documentation, the process added a solution folder and three files: NuGet.targets, NuGet.exe, and NuGet.Config.  NuGet.Config is only needed by TFS users so you can probably delete it safely.  It has no impact on what we are doing here.  By observing red checkmarks in the Solution Explorer we can also see that the process modified TemporaryFile.csproj and TemporaryFile.Tests.csproj.

Image showing Visual Studio solution explorer
Modifications to Solution

Lets see what changes package restore made to TemporaryFile.

diff --git a/NugetLikeAPro/TemporaryFile/TemporaryFile.csproj b/NugetLikeAPro/TemporaryFile/TemporaryFile.csproj
index c1e5a2c..85e156b 100644
--- a/NugetLikeAPro/TemporaryFile/TemporaryFile.csproj
+++ b/NugetLikeAPro/TemporaryFile/TemporaryFile.csproj
@@ -11,6 +11,8 @@
 <AssemblyName>TemporaryFile</AssemblyName>
 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
 <FileAlignment>512</FileAlignment>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+ <RestorePackages>true</RestorePackages>
 </PropertyGroup>
 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
 <DebugSymbols>true</DebugSymbols>
@@ -49,6 +51,13 @@
 <None Include="packages.config" />
 </ItemGroup>
 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
+ </Target>
 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
 Other similar extension points exist, see Microsoft.Common.targets.
 <Target Name="BeforeBuild">

Lines 18-24 create the reference to the NuGet.targets file in the .nuget folder, and add some error handling if the script is missing during the build.  On line 9 the $(SolutionDir) property is created, and its default value is the project’s parent directory.  NuGet.targets uses this piece of configuration to find resources it needs, like NuGet.exe or the solution packages folder.  Finally on line 10, package restore is enabled by adding the RestorePackages property and setting it’s value to true.  (Side note: this is a bit misleading.  It is getting harder and harder to opt-out of package restore.  If you set this to false, Visual Studio will set it to true again during the build, unless you opt-out again using a separate Visual Studio option.)

Editing project files is a bit tedious because you have to unload them, open them again as XML files, make your changes and then reload them.  Its not hard to learn but its at least four mouse clicks and then some typing in an obscure syntax without much intellisense (although R# helps here).  It’s nice that the Enable Package Restore menu item did all that editing for you with one click.  Remember that the process also added two NuGet packages for you, so you can add all that to your overall click-savings.  Note that the documentation mentions a new feature available in NuGet 2.7 called “Automatic Package Restore“.  This feature is enabled by default and solves some problems caused by package restore in certain scenarios.  It’s already on by default, so we can imagine that someday a program manager at Microsoft is going to say, “Hey, lets get rid of that ‘Enable Package Restore’ menu item.”

If the Enable Package Restore “gesture” is ever removed then we can install the NuGet packages ourselves and make the necessary changes to the project files.  This will get tedious and use way more than the five minutes I’ve allotted to the process, so I’m sure someone will think of a clever way to automate it again with yet another NuGet package.  However, this is all just my own speculation.  Today we live in the Golden Age of NuGet package creation, and package restore does 99% of the work for us.

One Small Edit

The NuGet.targets file provided by the NuGet.build package provides a “BuildPackage” target.  Unlike the “RestorePackages” target, the build package target is not enabled by default.  So, we have to edit our project file to turn it on.  To edit the file in Visual Studio is a several step process.  If I were to make the change from within the IDE, I would: right-click on the  TemporaryFile node in Solution Explorer, select “Unload Project”, right click again, select “Edit Project”, edit the project file, save the project file, close the project file, right-click the project again, select “Reload Project”.  It’s a hassle.

An image of the project context menu in Solution Explorer
Too Much Work

I find it’s easiest to use a regular text editor to make this change rather than Visual Studio.  Anything should work, I often use Sublime Text or Notepad++.  Plain old notepad or WordPad should work fine.  I prefer Sublime because I keep a my “Projects” folder open in Sublime by default so that I can glance at code or edit these types of files quickly.  However you choose to do it, you only need to add one property in order to turn on the BuildPackage target.

diff --git a/NugetLikeAPro/TemporaryFile/TemporaryFile.csproj b/NugetLikeAPro/TemporaryFile/TemporaryFile.csproj
index 85e156b..e42d010 100644
--- a/NugetLikeAPro/TemporaryFile/TemporaryFile.csproj
+++ b/NugetLikeAPro/TemporaryFile/TemporaryFile.csproj
@@ -13,6 +13,7 @@
 <FileAlignment>512</FileAlignment>
 <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
 <RestorePackages>true</RestorePackages>
+ <BuildPackage>true</BuildPackage>
 </PropertyGroup>
 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
 <DebugSymbols>true</DebugSymbols>

I usually put it right below the RestorePackages property (line 9), but you can choose where it goes.  For example, if you wanted to only create packages for debug builds, you could down a few lines to line 12, into the next PropertyGroup, which is only defined when Debug is selected.  The same technique would work to restrict package creation to Release builds, if that’s what you would like to do.  If you made the change out side Visual Studio, the IDE will notice and ask you if you want to reload the project.  You do, so click “Reload” or “Reload All”.

An Image of the "File Modification Detected" dialog
You need to reload now

Once the BuildPackage property is set to true, MSBuild will execute the corresponding target in NuGet.targets and create a package for you on every build.  This package will get most of it’s configuration by inference, and appear in the bin directory next to your normal build outputs.

An image of Windows File Explorer
BuildPackage creates two packages by default

BuildPackage created two packages for me.  One is an ordinary NuGet package, which contains the TemporaryFile assembly and one is a “Symbol” package, which includes the same assembly along with additional debugging resources.

An image of the standard NuGet package, open in NuGet Package Explorer
The ‘Standard’ NuGet package

We didn’t provide NuGet with any configuration information.  NuGet configured these packages by convention, and used the project and assembly information to infer what the package configuration should be.  By opening the standard package in NuGet Package Explorer we can see what NuGet came up with.  The Id, Version, Title, and Copyright are all inferred by examining assembly attributes.  These attributes are defined in AssemblyInfo.cs by default.

using System.Reflection;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("TemporaryFile")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TemporaryFile")]
[assembly: AssemblyCopyright("Copyright ©  2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("4365a184-3046-4e59-ba28-0eeaaa41e795")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Authors and Owners are both set to “James” which is my user name on the machine where I created the package. NuGet would prefer to use the value from “AssemblyCompany” for these fields, but I haven’t filled it out yet. Since AssemblyCompany was empty, NuGet moved on to the next convention and chose my user name instead. NuGet would also prefer to use “AssemblyDescription” to populate the Description value, but this was also blank. Since there is no other logical place (yet) for NuGet to find a description, the program simply gave up and used the word “Description” instead. NuGet uses the build log to warn me (lines 4, 5, 11, and 12 below) when this happens.

1>  Attempting to build package from 'TemporaryFile.csproj'.
1>  Packing files from 'C:\Users\James\Documents\GitHub\Blogs\NugetLikeAPro\TemporaryFile\bin\Debug'.
1>  Found packages.config. Using packages listed as dependencies
1>EXEC : warning : Description was not specified. Using 'Description'.
1>EXEC : warning : Author was not specified. Using 'James'.
1>  Successfully created package 'C:\Users\James\Documents\GitHub\Blogs\NugetLikeAPro\TemporaryFile\bin\Debug\TemporaryFile.1.0.0.0.nupkg'.
1>
1>  Attempting to build symbols package for 'TemporaryFile.csproj'.
1>  Packing files from 'C:\Users\James\Documents\GitHub\Blogs\NugetLikeAPro\TemporaryFile\bin\Debug'.
1>  Found packages.config. Using packages listed as dependencies
1>EXEC : warning : Description was not specified. Using 'Description'.
1>EXEC : warning : Author was not specified. Using 'James'.
1>  Successfully created package 'C:\Users\James\Documents\GitHub\Blogs\NugetLikeAPro\TemporaryFile\bin\Debug\TemporaryFile.1.0.0.0.symbols.nupkg'.

Notice on lines 3 and 10 that NuGet noticed that my project depends on another NuGet package. It infers this by detecting the ‘packages.config’ file where NuGet lists the project dependencies, reads that file, and automatically configures TemporaryFile to depend on ApprovalUtilities.

Overall NuGet did a pretty good job, and this package is actually usable.  Before we move on to customizing this package lets take a look at it’s sibling, the symbol package.

An Image of the Symbol package open in NuGet Package Explorer
The Symbol Package

The symbol package configuration is identical to the standard package.  Version, Id, Authors, and the rest are all the same.  However, there are more files in the symbol package.  Along with the class library, the lib/net45 folder contains the debugging symbols.  There is also a new folder called src.  Under the src directory, we can find all the source code for TemporaryFile.dll.  All together, this extra content gives Visual Studio enough information to provide a complete step-through debugging experience for this NuGet package.  What to do with this package and how to configure Visual Studio to use it are topics better handled on their own, so I wont cover them further here.  Stay tuned.

Customize

There are a few things I would like to change in this package before sharing it with the team/customers/world. I don’t like the default values for Author/Owner and Description. At a minimum the Author field should contain my last name, or perhaps my twitter handle or something I’d like the world to know me by. It is also appropriate to use your company name in this field. The description is important because this package will probably end up in a gallery and certainly be presented in the NuGet Package Manager inside Visual Studio. You need a good concise description so people have an idea what you are trying to share with them.  The copyright isn’t claimed by anyone either, be careful here because some default Visual Studio installs automatically use “Microsoft” as the default copy right holder (this seems to have been fixed in 2013, now its just blank).  Finally, I don’t like the default 3-dot version number, I prefer the 2-dot version, so I’d like to change that too.  These are the low hanging fruit which can be customized using AssemblyInfo.cs.

diff --git a/NugetLikeAPro/TemporaryFile/Properties/AssemblyInfo.cs b/NugetLikeAPro/TemporaryFile/Properties/AssemblyInfo.cs
index 7c3c830..bf494d8 100644
--- a/NugetLikeAPro/TemporaryFile/Properties/AssemblyInfo.cs
+++ b/NugetLikeAPro/TemporaryFile/Properties/AssemblyInfo.cs
@@ -2,14 +2,14 @@
 using System.Runtime.InteropServices;

 [assembly: AssemblyTitle("TemporaryFile")]
-[assembly: AssemblyDescription("")]
+[assembly: AssemblyDescription("A file that deletes itself when disposed")]
 [assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
+[assembly: AssemblyCompany("ACME Co.")]
 [assembly: AssemblyProduct("TemporaryFile")]
-[assembly: AssemblyCopyright("Copyright ©  2013")]
+[assembly: AssemblyCopyright("Copyright © Jim Counts 2013")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 [assembly: ComVisible(false)]
 [assembly: Guid("4365a184-3046-4e59-ba28-0eeaaa41e795")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
+[assembly: AssemblyVersion("1.0.0")]
+[assembly: AssemblyFileVersion("0.0.1")]
\ No newline at end of file

I filled or edited out the attributes which NuGet checks when looking for configuration information: AssemblyDescription, AssemblyCompany. AssemblyCopyright and AssemblyVersion.  I also changed AssemblyFileVersion, even though NuGet doesn’t use it, and I left AssemblyTitle alone because I was happy with the value already there.  After building again, these changes should show up in the newly created package.

An Image of the NuGet Package Explorer showing updated metadata
Most AssemblyInfo changes are applied automatically

NuGet applied most of my changes automatically, and all the build warnings are gone.  But I expected a 2-dot version number both in the package name and as part of the metadata.  That 3-dot version is still hanging around.  I can take greater control over the version number, as well as many other aspects of the package metadata by providing a “nuspec” metadata file.  If this file has the same name as my project and is in the same directory as my project, then NuGet will prefer to use the data from the nuspec.

Pull the Nuspec File Out

You can generate nuspec files from assemblies or project files using NuGet.exe.  In the past I’ve found this method for creating nuspec files to be tedious because it creates configuration  I don’t always need or configuration with boilerplate text that I need to delete.  My old solution was some fairly complex MSBuild scripts that transformed generated files, but today I just create the default package as described above, rip it’s metadata, then customize to my liking.  If you have NuGet Package Explorer open, it’s pretty easy to use the “Save Metadata As…” menu item under “File” and save the nuspec file next to your project file (remove the version number from the filename if you do this).

Another way to retrieve the package nuspec file is with an unzip tool.  NuGet packages are zip files, and tools like 7-zip recognize this, buy you can always change the extension from nupkg to zip, if 7-zip isn’t handy.   Once the file has a zip extension, any zip utility can manipulate it, including the native support built into Windows.

An image showing the nuget package as a zip, open in Windows FIle Explorer
Nupkg files are Zip files

You can extract all the files from the zip, or just the nuspec file.  You will only need the nuspec file.

Put the Nuspec File Next to the Project

Once you have pulled the nuspec file out of the existing package, move it to the project directory.  It should sit in the same folder where the csproj file is (or vbproj, or fsproj) and have the same base name as the csproj.  There should be no version number in the nuspec file name, so remove it if there is.

An image showing the nuspec file in the project folder.
Put the nuspec file in the project folder

You can also add the item to the project using Visual Studio for easy access from the IDE, but it is not required.  I usually add it.

Make Changes

Now, let’s take a look at what is inside the nuspec file.

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
 <metadata>
 <id>TemporaryFile</id>
 <version>1.0.0.0</version>
 <title>TemporaryFile</title>
 <authors>ACME Co.</authors>
 <owners>ACME Co.</owners>
 <requireLicenseAcceptance>false</requireLicenseAcceptance>
 <description>A file that deletes itself when disposed</description>
 <copyright>Copyright © Jim Counts 2013</copyright>
 <dependencies>
 <dependency id="ApprovalUtilities" version="3.0.5" />
 </dependencies>
 </metadata>
</package>

We can see that most of the information in the nuspec file is the exact information displayed in the package explorer. I can now override the defaults by editing this file.  Any XML or text editor will work, it’s very convenient to use Visual Studio if you add the nuspec file to the project, so that’s what I usually do.

diff --git a/NugetLikeAPro/TemporaryFile/TemporaryFile.nuspec b/NugetLikeAPro/TemporaryFile/TemporaryFile.nuspec
index 5770b72..815c44e 100644
--- a/NugetLikeAPro/TemporaryFile/TemporaryFile.nuspec
+++ b/NugetLikeAPro/TemporaryFile/TemporaryFile.nuspec
@@ -2,15 +2,12 @@
 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
 <metadata>
 <id>TemporaryFile</id>
- <version>1.0.0.0</version>
+ <version>0.0.1</version>
 <title>TemporaryFile</title>
- <authors>ACME Co.</authors>
+ <authors>@jamesrcounts</authors>
 <owners>ACME Co.</owners>
 <requireLicenseAcceptance>false</requireLicenseAcceptance>
 <description>A file that deletes itself when disposed</description>
 <copyright>Copyright © Jim Counts 2013</copyright>
- <dependencies>
- <dependency id="ApprovalUtilities" version="3.0.5" />
- </dependencies>
 </metadata>
 </package>
\ No newline at end of file

I changed the version number to “0.0.1” and updated the the author to use my twitter handle.  “ACME Co.” is still the owner, and I removed the dependency list.  I prefer to allow NuGet to continue to infer this information on it’s own.

With these changes, the next package I build should reflect the new version number in the file name, and show updated metadata for Version and Authors.  However, the dependency list should remain the same in the completed package.

An image of Nuget Package Explorer showing the applied customizations
That’s More Like It

Automate

You’ll need some way to share your package now that you’ve created one.  If it’s an open source project you can definitely upload it to nuget.org if you like.  For private code, that’s probably not a good idea.  There are solutions out there, and I wrote about one of them in a previous article: Use ProGet to Host Your Private Packages.  In the interest of making sure this article doesn’t get any longer than it already is, I won’t cover options for sharing private packages here.

However, there are a couple things you can do now which will make your life easier once you do start sharing your package.  First, nuget.targets does not clean up after itself during clean and rebuild.  This means that all your old package versions will hang around in the build folder until you delete them manually.  Besides taking up space, those packages eventually slow you down when you get ready to share.  If you are using the NuGet Package Explorer to share, you have to scroll past an increasingly longer list of old package versions to find the new version you want to upload, and if you use the command line utility, all those old versions increase the amount of typing and tabbing in order to complete the command.  Finally, I find the quickest way to push packages is with a custom script which wraps the command line utility, and that script is much easier to write when the bin folder only contains the latest package.

Cleanup with nuget.targets

To integrate nuget.target with “Clean” and “Rebuild” you need to add a new target to the script, add a new item group which lists the files to clean, and finally ad a hook using the “CleanDependsOn” property that will actually execute the target.

Nuget.targets is already added to your solution in the .nuget folder, open it and add what you need.

diff --git a/NugetLikeAPro/.nuget/NuGet.targets b/NugetLikeAPro/.nuget/NuGet.targets
index 8962872..a5cebf3 100644
--- a/NugetLikeAPro/.nuget/NuGet.targets
+++ b/NugetLikeAPro/.nuget/NuGet.targets
@@ -1,5 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <OutputPackages Include="$(TargetDir)*.nupkg" />
+ </ItemGroup>
 <PropertyGroup>
 <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>

@@ -83,6 +86,11 @@
 $(BuildDependsOn);
 BuildPackage;
 </BuildDependsOn>
+
+ <CleanDependsOn Condition="$(BuildPackage) == 'true'">
+ $(CleanDependsOn);
+ CleanPackages;
+ </CleanDependsOn>
 </PropertyGroup>

 <Target Name="CheckPrerequisites">
@@ -118,6 +126,10 @@
 Condition=" '$(OS)' == 'Windows_NT' " />
 </Target>

+ <Target Name="CleanPackages">
+ <Delete Files="@(OutputPackages)"></Delete>
+ </Target>
+
 <UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
 <ParameterGroup>
 <OutputFilename ParameterType="System.String" Required="true" />

On lines 8-10 I define a collection of items called “OutputPackages” which uses a glob to find all the NuGet packages in the bin directory, referred to in the script as TargetDir.

Then I use this item collection with the new target defined on lines 30-32.  The CleanPackages target is a very simple target that uses MSBuild’s built-in Delete task to remove the files in the OutptuPackages collection.

Finally, I instruct MSBuild to run this target during clean by hooking into the CleanDependsOn property using lines 19-22.  CleanDependsOn is one of several hooks provided for modifying targets defined in Microsoft.Common.Targets. On line 20, I add back any existing dependencies and on line 21 I append the CleanPackages target to the end of the list.  Now, MSBuild will clean up old packages whenever I Clean or Rebuild my project.

Write a push script

Pushing your packages to NuGet.org is pretty simple because it is the default for nuget.exe.  Both NuGet.exe and the NuGet Package Explorer will allow you to specify a custom host to push your package to, but I’m paranoid that I will forget to specify the host and send packages to nuget.org that I don’t want to share publicly.

So, to speed things up, and to keep the risk of mistakes to a minimum, I use a simple shell script to push my packages.  Here is an example that would push to a local ProGet server.

.nuget\NuGet.exe push .\TemporaryFile\bin\Debug\*.nupkg -apikey Admin:Admin -source http://localhost:81/nuget/Default

I specified ProGet’s default credentials as the API key, but if you plan to push to nuget.org I suggest you use the NuGet “setapikey” option to configure the API key on your machine, and that way you don’t have to commit the key to source control.

Recap

In this post I showed how to create basic packages with MSBuild, customize them, and gave a couple automation tips I find useful.  Once you have converted a few of projects to produce packages this way, you can do the conversion in about 15 minutes for straightforward packages.  NuGet packages can become complex and you may need to do a lot more in the customization stage.  However, for most cases I find that these few steps are enough: enable package restore, add the BuildPackage property, rip the nuspec file from the first package, customize a few pieces of AssemblyInfo and nuspec metadata, and start sharing your package.

Once you have the package, you can quit, or you can make your life a little easier by adding a cleanup target and a push script.  Either way, I hope you find this information useful, and bit more approachable than my previous post on this topic.

The GitHub repository to accompany this post is here: https://github.com/jamesrcounts/Blogs/tree/master/NugetLikeAPro

Tips, Tools

Use ProGet to Host Your Private Packages

I’ve been using private NuGet packages for a while. The easiest way to get up and running with private packages is to drop them in a folder and setup the NuGet Package Manager to use that folder as a package feed. Like many simple solutions, this works great until you outgrow it. I create NuGet packages whenever I build in release mode, and the package-build automation copies the packages to the feed folder. I use Windows Live Mesh to keep the folder in sync across development workstations.

The drawback with this approach is that the relative path to the feed folder must be consistent (I’m too lazy to specify a custom path in each MSBuild file). This means that I’m not free to put my projects anywhere I would like. For example, GitHub for Windows clones into Documents\GitHub\<project> by default, this won’t work with my hacked together system. Also, Visual Studio 2012 is on the horizon, and by default it will create its own Documents\Visual Studio 2012\Projects folder, this is also incompatible with the relative path I use to find my feed folder during build.

What I need is some kind of “universal” way to “locate” a “resource”. Hmm, where have I heard those words before? Oh yes, the internet is based on this idea. The NuGet documentation explains how to set up an ASP.NET MVC site as a “read-only” remote feed. This is read-only from the perspective of the web in that there is no way to push new packages to the site over HTTP. You can update the packages by placing them into the site’s Packages folder. Essentially, this simple remote feed takes the concept of the local feed and wraps a web server around it. This option is not half bad, I could store the packages on my build server and configure my build automation to use a UNC path pointing at that folder, but it would be really sweet to have a more complete nuget.org style experience. There are a couple ways to do this.  Inspired by Damian Hickey’s post on his NuGet workflow, I decided today was the day to get it going.

Damian has a lot of cool tools in his pipeline, but today I’m going focus on one part and look at a package called ProGet by Inedo

Download the Bits

Here’s the ProGet overview page. You can read a little about the software and download. They have a free (beer) version as well as enterprisey offerings. The download page has a dead link to an installation guide (as of this writing anyway, hopefully that gets fixed soon.) The installation package comes in two flavors, a 60MB version that comes with SQL Server Express, and a 4MB version without the database. Since I already have a database available, I downloaded the smaller package, unblocked it, and copied it over the the build server.

Capture

Install the Bits

After starting the installer, I accept the EULA (which is surprisingly short and simple), then select an edition to install.

Capture1

I choose “ProGet Free” and the installer asks for my email address. I give it my junk mail address, and wait a moment while the installer talks to the mothership. Next, I accept the default installation directory, then its on to database configuration.

Capture2

I click “Test” but the connection fails. Although there is definitely a server installed, I’m not even sure if its running, so now its time to do some SQL Server troubleshooting.  I open the SQL Server Configuration Manager and see that the server is running and that TCP/IP connections are allowed. But I notice that its actually a SQL Express server, and that the ProGet installer is trying to connect to a (default) instance. I update the instance to SQLExpress and the connectivity test passes.

Capture3

Next, the installer asks whether I would like to use its integrated web server, or use IIS. Since I already have IIS up and hosting CruiseControl.NET’s web dashboard, I choose to use IIS. I can also choose the port to host ProGet on, but I leave the default 81.

Capture4

Looks like that’s all the installer wants to know, so I click the Install button. Installation takes about 2 minutes.

Capture5

I click “Launch ProGet” and the ProGet site launches in IE.

Capture6

Adding Packages

I think there’s no point in clicking the giant “Browse Packages” button since I don’t have any yet.  Later on I learn that ProGet will act as a type of proxy for NuGet.org, and would have shown me a bunch of remote packages if I had clicked there.  But I was more interested in adding my own packages anyway, so I clicked on “Add Package”. The site wants to authenticate, but also warns me that I haven’t changed the password for the default Admin user.

Capture7

I like how they say that they “took the liberty” of creating Admin for me.  It gives a nice “this is not your fault” feeling to the text.  I login with the default credentials, then click the “Administration” tab, then “Users and Groups” and finally “Edit” on the Admin user. I change Admin’s password and click “Save User”. Then I create a second administrator using my own name.

Update 2012/7/11: Now that you have created an admin, stay on the Administration tab, then go to “Licensing and Activation”.  Click the button that says “Activate ProGet”.  It’s still free, but if you don’t do this step then your server will stop working in about a week.

Back to the “Add Package” tab. I have the option of Uploading an existing package, using NuGet.exe to push to the repository (sweet), create a package right on the server, or pulling from a remote feed. I’ll try all of these except for “Create New Package”.

Capture8

Pull From Another Repository

Capture9

Just as an experiment, I’ll pull CompositionTests down from nuget.org. I fill out the requested information and check the “Download Dependencies” option. For “Feed URL:” I presume they mean the over all feed, not the specific path to CompositionTests and I copy the URL out of Visual Studio. After clicking “Install Package” I browse over to the “Packages” tab.

Capture10

The first three packages are CompositionTests and its dependencies. The rest of the packages are on Nuget.org (I presume). I didn’t expect to see remote packages, but the page indicates that what I’m seeing is not just local packages, but also “additional packages from any connectors”. The additional packages have a little plug overlay on their icon, indicating they are available via the connector. I click on “Administration” then “Feeds” and I can see that I do indeed have a connection to nuget.org by default.

Capture11

I can also see the “Feed Path” where ProGet stores the local packages, and we can see CompositionTests and friends stored there.

Capture12

Upload From Disk

Under my old system, my local package feeds are stored on my development workstations. So, I’ll open a browser on one of them and see if I can upload a package from the local feed to the remote feed. I hit a snag trying to login, but it just turns out that I need to allow JavaScript (using the correct password also helps).

Capture13

On the “Add Package” tab, I click “Upload From Disk”. Other than the target feed, all ProGet wants to know is where the file is. I choose one of my private packages: “TemporaryFile” (a little class I use with testing that wraps a temp file in an IDisposable container so that the file is deleted even if an exception is thrown). After I click “Upload File”. We can see that the file is stored on the server.

Capture15

And now appears in the feed.

Capture16

Push via NuGet.exe

After I click on “Push via NuGet Command Line Utility” ProGet displays instructions to push via the command line.

Capture17

Since I haven’t created any additional feeds, my <Feed Name> will be Default. Of course, <package path> will depend on the package I want to upload, but what about [API key]? Browsing around I don’t see it anywhere obvious in ProGet. Pushing without it won’t work, NuGet.exe requires an API key for the server. Using a fake value like “foo” also fails.

I poked around Inedo.com and one of the screenshots clued me in to the fact that the API key in ProGet is associated with the feed, not the user. By default it is blank.

Capture18

The ProGet documentation gives some insight into why the key goes with the feed and not the user, but no guidelines on the format of the key. I head over to www.guidgenerator.com and create a GUID and setup the feed to use it, but I still get a 500 error every time I try to push a package.

After poking around IIS, and eventually busting out Fiddler I still couldn’t get it to work so I used the “Live Help” button to open a chat with Inedo support.

Capture16

They were able to reproduce the problem on their side, and indicated it seemed to be a bug when using ProGet with the latest build of NuGet. They’re working on a fix. I found older versions of NuGet rattling around my hard drive (1.5 and 1.7) and still couldn’t get it to work. So I guess I’m stuck waiting for the update for the time being, that’s no fun.  I decided to go have lunch.

A Few Hours Later…

I get an email on my junk account explaining a feature of Buildmaster--one of Inedo’s other products that I never downloaded. I mistook it for a release announcement because I didn’t really read it, and even though ProGet isn’t mentioned in the email I decided to visit the ProGet download page. Sure enough, ProGet 1.0.6 was released today.

As an aside, it makes me sad that they sent me an email about something I haven’t expressed interest in, while failing to send me an email about something I am interested in. But I can’t fault them too much, that’s just the price you pay for free beer. And if this new release fixes my issue, then I’ll gladly receive their marketing emails in exchange for such good service.  (Not promising to read, just receive.)

Upgrading ProGet

Once again I download the smaller package. This time the installer asks if I want to update.

Capture19

I click the update button and ProGet strongly recommends that I backup the database. I let it do so and it fails. There is a button to submit an error report, so I click it. I fill out a little report and submit the issue.

Capture20

Being impatient, I decide to try again. Now, the installer acts like a new install and offers me the EULA again. Not good. Maybe my old install got borked. Yep, same old installation now. I follow the steps outlined above and wait while ProGet installs. It seems to have fewer steps this time, so I think it recognized that the database already existed. I click “Launch ProGet” at the end and the site launches. I click on “Browse Packages” and all the packages I added previously are still there. So, the install only suffered minor borking.  (As an aside, before I could even finish writing up this post, I got an email from their support asking if I had been able to resolve the issue, which included a suggestion on an alternate way to backup the database.)

Over on the admin tab, the credentials I set up previously still work and the API key I created is still associated with the default feed.

Push via NuGet.exe, Redux

Ok, do over time. Lets see if I can push packages with NuGet now.

I open a command window and navigate to my local package folder. This time I’ll try pushing my “Strings” package (a library of helpers for System.String… c’mon, you know you have one too.)

C:\...\PackageSource>NuGet.exe push Strings.1.0.4360.34765.nupkg API_KEY -Source http://dee:81/nuget/default 
Pushing Strings 1.0.4360.34765 to 'http://dee:81/nuget/default'... Failed to process request.
'You are not authorized to add a package to this feed.'. 
The remote server returned an error: (403) Forbidden.. 

So it still fails, but now it fails with a 403 instead of a 500. Note that replaced the API key with a placeholder. That’s more for the sake of brevity than security. Because I control the key, I can reveal it as long as I’m willing to replace it later.

Thinking I had an idea about fixing the 403 error, I go to “Administration” then “Privileges and Roles”. I create a new Role called “Publisher” and give it the “Feeds_AddPackage” privilege.

Capture21

Then I click “Add Privilege” and I grant “Publisher” to “Anonymous”. Lets see if that works.

C:\...\PackageSource>NuGet.exe push Strings.1.0.4360.34765.nupkg API_KEY -Source http://dee:81/nuget/default 
Pushing Strings 1.0.4360.34765 to 'http://dee:81/nuget/default'... 
Your package was pushed. 

Bam! It worked.  I love it when a plan comes together.

Capture22

Capture23

Final Thoughts

It would have been nice if the official install guide was online. However, it wasn’t to hard to figure out the basics. Even, if it hadn’t been my bad luck to hit a bug on day one, then I still would have needed to figure out how to let anonymous users upload packages. The only reason I was able to figure it out quickly was because I had gotten pretty familiar with the configuration options while debugging 1.0.5.

Lucky for you, you won’t have to deal with that bug, and I hope this guide will make your setup experience smoother than mine was. I’m looking forward to playing with this tool and seeing how I can integrate it with my build system. Up until now, I haven’t configured CruiseControl.net to create NuGet packages because it seemed like a pain when my system was based on local feeds. Also, I haven’t been using Package Restore with the build server since the server didn’t have access to the private packages. With ProGet in the mix, I’m hope to have that up and running soon.

Tips, Troubleshooting

Enable NuGet PackageRestore on CC.NET

Last week I decided to revisit my MSBuild/NuGet patterns (see 1 and 2) and see if I could make any improvements to what I had come up with before.  In particular, I wanted to integrate Brad Wilson’s gist on downloading NuGet at runtime.  I did that for a couple projects, including CompositionTests and it works great.

But last night, NuGet 2.0 came out and CompositionTests stopped building on my CruiseControl.NET server, along with another project I haven’t released yet.  I did what I usually do when something breaks first thing in the morning: I hit “Force Build” and see what happens.  But it still failed and eventually I went searching to see if there were any problems with NuGet 2.0.  Sure enough I found something, but its not a bug, it’s a feature!  NuGet 2.0 requires consent for package restore, because we all just know that the NSA is very interested in what packages we are using.  The NuGet team has been very open about this change and gave fair warning to get ready, which I read and ignored.

Well, I can’t ignore it anymore can I?

Symptoms

First and most obvious is a sad red circle in CCTray:

image

Like I said, normally I don’t even check the log before hitting “Force Build” but I already did that dance, so lets look at the log.  I formatted this to fit your screen, and pulled some paths out for brevity, but you get the idea:

<error file="...\CompositionTests\.nuget\nuget.targets"
        line="57"
        column="9"
        timeStamp="06/19/2012 23:36:45">
  <![CDATA[
    Package restore is disabled by default. To give consent, open the Visual Studio
    Options dialog, click on Package Manager node and check 'Allow NuGet to 
    download missing packages during build.' You can also give consent by setting 
    the environment variable 'EnableNuGetPackageRestore' to 'true'.
  ]]>
</error>
<error code="MSB3073"
        file="...\CompositionTests\.nuget\nuget.targets"
        line="57"
        column="9"
        timeStamp="06/19/2012 23:36:45">
  <![CDATA[
    The command ""...\nuget.exe" install "...\packages.config" -source "" -o 
    "...\packages"" exited with code -1.
  ]]>
</error>

Since we are working with a build server, checking a checkbox in package manager is not an option.  In this scenario, NuGet gives us the another way to provide consent via an environment variable.  Lets try that.

Cure

These steps will apply to Windows Server 2008 R2, because that’s what I’m running CC.NET on.

Set Environment Variable

  • Log on to the build server and open the Control Panel
  • Go to System & Security > System > Advanced System Settings
  • Click “Environment Variables”
  • Click “New…” under “System Variables”
  • Enter “EnableNuGetPackageRestore” as the name and “true” for the value.
  • Click OK > OK > OK.

image

Restart the CruiseControl.NET service

  • Open Control Panel > System & Security > Administrative Tools > Services
  • Select CruiseControl.NET and click “Restart” to restart the service.

image

Test

Use “Force Build” to force a failing project to start in CC.NET.

image

And you’re done!

Tips

Install NuGet Packages from the Cache

Why?

We all love NuGet, but like all cloud services, it is only available when the cloud is available. If you are on the proverbial airplane, you cannot install new packages or update existing packages. In my case, I ride the train back and forth from school twice a week, which is not a bad commute (30 minutes each way.) It is just long enough that sometimes I feel like getting out my laptop and doing some work. Just last week I started a new project on the train and I wanted to install Moq and write a test, and I ran into this snag.

Since I already had a local feed configured, this was easy enough to resolve. I navigated to a project that already had the latest version of Moq installed, grabbed the nupkg from that solution’s packages folder, and dropped it into my local feed. Problem solved. I know from experience that doing this would not cause me any problems. When the Moq team releases the next update to Moq, NuGet will see that version on line and start offering that version instead of the copy in the local feed.

Around the same time, Rory Becker suggested to the world (via Twitter – @RoryBecker) that NuGet should use its cache as a package source. I thought that configuring this manually by hand would be possible, but did not look into it. With the NuGet.org outage today, David Fowler (@davidfowl) suggested the idea. Now everyone knows. Oh well, that will teach me to sit on an idea.

NuGetCache6

How To

Setting up local package sources is easy. The official guide is located here on docs.nuget.org, but you can follow along here to setup this specific scenario.

First, start Visual Studio and open the Package Manager Options:

NuGetCache5

Click on the “Package Sources” item. You can enter whatever makes sense to you as the name. The name “Cache” makes sense to me. You cannot follow David’s tweet too literally because the options page will not accept the %LOCALAPPDATA% variable. If you try, the Package Manager Options will complain with the message: “The source specified is invalid. Please provide a valid source.”

NuGetCache4

Instead, paste the path “%LOCALAPPDATA%\NuGet\Cache” into your Start Menu’s search box and press enter to open the folder:

NuGetCache3

Then copy the full path from the explorer window’s address bar and paste it into your Package Manager options:

NuGetCache2

Click the add button and this time the package manager should accept the new source:

NuGetCache1

That’s it, thanks for reading!

Tips

Tip: nuspec intellisense

I ran into this exact problem when playing with nuspec intellisense:

“The XML namespace actually contains a placeholder which is replaced during release. So don’t use the file from Codeplex.”

But Xavier Decoster has solved the problem by putting the nuspec XSD into a NuGet package.

Check out his post for details.

Coding

Manage Your MEF Parts with NuGet

Why?

With MEF you have the flexibility to compose applications without taking a reference to every required assembly. MEF’s flexibility is one of its most seductive features. But I see a dark side. Maybe I’m paranoid, but I miss the security of taking references. Before MEF, I never worried about getting my assemblies into the bin directory because MSBuild took care of that for me. Now I do worry about it, a little, and this is one of the reasons I’ve written about a method to test MEF composition.

I also really like NuGet. Most people compare NuGet to apt, but to me it’s always been “CPAN for .NET”. I guess that tells you a little bit about where I’m coming form. But whatever your background, you have to love a system that lets you say “Here is the thing I’m interested in using, you go get the rest.” But at first glance, MEF and NuGet don’t play well together (even though NuGet uses MEF!) NuGet makes the fundamental assumption that when a library exists in a NuGet package, then the intent when installing that package is to reference that library. I’m not saying that’s a bad assumption in general, it’s just not a very good assumption to make when dealing with libraries of MEF parts.

The good news is that NuGet can be used to create MEF friendly packages that don’t create references when installed, but do ensure that the parts are copied to the bin directory. You get runtime-only references, with all the NuGet package management goodness. I’ll be the first to admit that some of the techniques used to make this happen are hacky, but I’ve tested it and it works for me. So strap yourself in, and read on.

A Little Background

I’m going to start by showing the structure of a nuspec file which NuGet can use to make a MEF friendly package.

After showing the nuspec, I’ll show how to automate spec and package creation using MSBuild.

  • It will be helpful to know a little MSBuild. I wish I had a good resource, but I don’t. Somehow, I’ve just learned it though osmosis. This one looks nice. I mostly look at the reference when I have questions.
  • To create the MEF-friendly package, I’ll extend the recipe I wrote for creating a “Standard” NuGet package with MSBuild.
  • You will need the nightly build of the MSBuild Community Tasks.
  • There will be some XSLT. I can vouch for w3schools, since I used it as my primary reference for creating the XSLT used in this post.

Anatomy of a MEF Friendly Package

Here is the nuspec which builds a MEF friendly package for the CheesePizzaMaker assembly from my MEF talk.

<?xml version="1.0" encoding="utf-8"?>
<package>
  <metadata>
    <id>CheesePizzaMaker.MEF</id>
    <version>1.0.4441.28470</version>
    <authors>Jim Counts</authors>
    <owners>Jim Counts</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Makes Cheese Pizza</description>
    <copyright>Copyright 2012</copyright>
    <title>CheesePizzaMaker (MEF)</title>
    <dependencies>
      <dependency id="PizzaStore" version="" />
    </dependencies>
    <frameworkAssemblies>
      <frameworkAssembly assemblyName="System" targetFramework="" />
      <frameworkAssembly assemblyName="System.ComponentModel.Composition" targetFramework="" />
    </frameworkAssemblies>
  </metadata>
  <files>
    <file src="bin\x86\Release\CheesePizzaMaker.dll" target="content\Parts" />
    <file src="bin\x86\Release\CodeContracts\CheesePizzaMaker.Contracts.dll" target="content\Parts" />
    <file src="bin\x86\Release\CheesePizzaMaker.pdb" target="content\Parts" />
    <file src="NuGet\install.ps1" target="tools" />
  </files>
</package>

This nuspec file is meant to be the target of the “nuget pack” command. Since the target will not be a project file, NuGet will not fill any of the fields for us at runtime, so there are no replacement tokens like there were in the “standard” nuspec I wrote about before. But, you can avoid filling out most of the data by hand if you give NuGet an assembly to examine when it runs the “nuget spec” command. I’ll show you how to do that later in this post, or you can consult the NuGet docs. After generating the spec, I customized some fields:

  • Id – to distinguish the MEF friendly package, I added .MEF to the Id.
  • Title – I added the title field, and used a title that made it easy to distinguish in the Package Manager
  • Dependencies – I added the PizzaStore package as a dependency. This package contains the interface definitions shared between parts and their host. When the version field is blank, NuGet will look for the highest available version, and that’s the behavior I want, but you can specify a version if you like. Also, note that the PizzaStore package is a standard package; it will create a reference in the project where it is installed. Since it only contains interfaces, and not parts this is what we want. However, you could (in theory, I haven’t tried this yet) have MEF packages that depend on other MEF packages.
  • Framework Assemblies – Since this is a MEF friendly package, we know that the target project will need MEF. So, System.ComponentModel.Composition and System are both listed as dependencies. NuGet will add them to the project if they aren’t already there. You could leave this off, but then you would have to add the references by hand. Automation is smoother, take advantage of it.
  • Files – Finally we have the files section. We have the same three files that I included in the standard package, and one more file, which is the install.ps1 script which runs when the package is installed. Other than the PowerShell script, which we will look at in a moment, the big difference is where the files are located in the package. Instead of placing the files in the lib folder, as is standard, I’ve put them into the content folder. Furthermore, I’ve placed them in a subdirectory called “Parts”.

Because the libraries are in the content folder, NuGet will not add a reference to the files when the package is installed. However, it won’t copy them to the bin directory either, so placing the files into the content folder only solves half the problem. Install.ps1 solves the other half:

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

foreach ($runtimelib in $project.ProjectItems.Item("parts").ProjectItems)
{
    if(-not $runtimeLib.Name.EndsWith(".Contracts.dll"))
    {
        # Set to "Copy Always"
        $runtimelib.Properties.Item("CopyToOutputDirectory").Value = 1
    }
    else
    {
        # Change to "None"
        $runtimelib.Properties.Item("BuildAction").Value = 0;
    }
}

To make the MEF friendly package work, I’ve adopted the convention that the Parts folder contains MEF parts which should be copied to the bin directory. The only exception is the Contracts library, which also contains the MEF attributes for the assemblies they describe, and can cause cardinality mismatches if it is deployed to bin. By default, content files are placed directly in the project folder, the build action is set to “Content”, and the copy to output directory property is set to “Do not copy”. Because we specified a subfolder in the nuspec file, NuGet will create a “Parts” directory and place the files in there. To get the files copied to the bin directory, the PowerShell script enumerates through the contents of the Parts folder (which is a “ProjectItem” from MSBuild’s point of view) and change the value of the “CopyToOutputDirectory” property to 1 as long as the file doesn’t end with “.Contracts.dll.” In the enumeration for “CopyToOutputDirectory”, 1 means “Copy Always”, good luck on finding that documented anywhere (send me a link if you find it.)

In theory, the top half of the if-statement is all you need to make the package MEF friendly. But, I discovered that MSI files will include the Contracts library if you leave the Build Action equal to “Content.” Again, this will cause cardinality mismatch exceptions if you then use the MSI to install your application. What’s worse is that you will only see the problem in production. So, to save us from this headache, the PowerShell script will set the Build Action equal to “None” when it finds the Contracts library.

So that’s a MEF friendly NuGet package. When you install the package, your libraries will appear in the Parts folder. On build, your assembly and its pdb will be copied to a “Parts” folder in the bin directory. The only adjustment you need to make in your application is that you must include a DirectoryCatalog for this new subfolder in your composition. You might also have noted the hardcoded value for the package version. In the next section I’ll show how this number can be updated at runtime, but if you don’t want to read that, just know that this value can be overridden from the command line when calling “nuget pack”.

Automating with MSBuild

I’m sensitive to the needs of those who like to cut and paste, so here is a link to the NuGet folder for the CheesePizzaMaker on bitbucket.org. Do come back though, because automating the MEF friendly package is a little more complex than the standard package.

Consuming the Build Script in the Project

This step is just like consuming the standard build script.

  1. Unload your project.
  2. Edit your project.
  3. Update your project file’s “AfterBuild” target.

If you are unfamiliar with editing a project file, visit my previous article on creating NuGet packages with MSBuild for step-by-step instructions. If you are planning to build both types of packages (standard and MEF-friendly) then your AfterBuild target should look like this when you are done:

  <Target Name="AfterBuild">
    <MSBuild Condition="'$(Configuration)|$(Platform)' == 'Release|x86'"
       Projects="NuGet\NuGet.msbuild" />
    <MSBuild Condition="'$(Configuration)|$(Platform)' == 'Release|x86'"
       Projects="NuGet\NuGet.MEF.msbuild" />
  </Target>

Setup Support Files

We need to create several supporting files, two that enable the build script to customize the nuspec file for us, and one which we include in the nuget package. Finally, we include NuGet itself, for convenience (as discussed previously, this is my personal preference, but the build script will need to be adjusted if your preference differs.) You don’t need to add these files to the solution, but if you do, make sure that you set the Build Action to “None”.

  • NuGet.exe – Go ahead and create a folder called NuGet in your project, and save a copy of NuGet.exe in this folder.
  • Install.ps1 – This file is included in the MEF-friendly NuGet package tools folder. The generated nuspec will expect to find this file in the NuGet subfolder. So create a text file called install.ps1 and copy the contents of the PowerShell script into it (shown above and available on bitbucket.org).
  • Mefdata.xml – This file is a source file for an XmlMassUpdate task in the MEF-friendly build script. It contains all the custom elements except the dependencies. Some of the data is dummy data, which the script will update in a later step. Create this file in the NuGet folder.
<?xml version="1.0" encoding="utf-8"?>
<package xmlns:xmu="urn:msbuildcommunitytasks-xmlmassupdate">
  <metadata>
    <title>title</title>
    <frameworkAssemblies>
      <frameworkAssembly xmu:key="assemblyName"
         assemblyName="System" targetFramework="" />
      <frameworkAssembly xmu:key="assemblyName"
         assemblyName="System.ComponentModel.Composition" targetFramework="" />
    </frameworkAssemblies>
  </metadata>
  <files>
    <file xmu:key="src" src="AssemblyPath" target="content\Parts" />
    <file xmu:key="src" src="ContractPath" target="content\Parts" />
    <file xmu:key="src" src="SymbolPath" target="content\Parts" />
    <file xmu:key="src" src="NuGet\install.ps1" target="tools" />
  </files>
</package>
  • dependencydata.xslt – If the project has a “packages.config” file then it means that there are some NuGet packages installed in the project. The script uses this transform file to convert packages.config into an XmlMassUpdate source which contains the contents of the <dependencies /> node in the nuspec file. Create this file in the NuGet folder.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                exclude-result-prefixes="msxsl"
>
  <xsl:output indent="yes"/>
  <xsl:template match="/">
    <package xmlns:xmu="urn:msbuildcommunitytasks-xmlmassupdate">
      <metadata>
        <dependencies>
          <xsl:for-each select="packages/package">
            <dependency xmu:key="id">
              <xsl:attribute name="id">
                <xsl:value-of select="@id"/>
              </xsl:attribute>
              <xsl:attribute name="version"/>
            </dependency>
          </xsl:for-each>
        </dependencies>
      </metadata>
    </package>
  </xsl:template>
</xsl:stylesheet>

Now we’re ready to create the NuGet.MEF.msbuild script.

Create the Build Script

Create an XML file in the NuGet folder and call it NuGet.MEF.msbuild. You can download the complete file from bitbucket.org, but I will go through each section step by step here.

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
         ToolsVersion="4.0"
         DefaultTargets="default">
  <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
  <PropertyGroup>
    <NuGetApp>NuGet.exe</NuGetApp>
    <ProjectDir>$(MSBuildProjectDirectory)\..</ProjectDir>
    <PackageDir>$(ProjectDir)\..\..\..\PackageSource</PackageDir>
    <ReleasePath>bin\x86\Release</ReleasePath>
    <ProjectName>CheesePizzaMaker</ProjectName>
    <PackagesFile>$(ProjectDir)\packages.config</PackagesFile>
    <DependencyFile>$(MSBuildProjectDirectory)\dependencydata.xml</DependencyFile>
    <MefDataFile>$(MSBuildProjectDirectory)\mefdata.xml</MefDataFile>
    <XsltFile>$(MSBuildProjectDirectory)\dependencydata.xslt</XsltFile>
    <PackageId>$(ProjectName).MEF</PackageId>
    <MefNuSpecFile>$(ProjectDir)\$(PackageId).nuspec</MefNuSpecFile>
    <ReferenceLib>$(ReleasePath)\$(ProjectName).dll</ReferenceLib>
    <ContractLib>$(ReleasePath)\CodeContracts\$(ProjectName).Contracts.dll</ContractLib>
    <SymbolLib>$(ReleasePath)\$(ProjectName).pdb</SymbolLib>
  </PropertyGroup>

We start off by creating our project and importing the MSBuild Community Tasks. Next we setup some data used throughout the script. Some of these properties aren’t as clean as I’d like them to be, so there might be some refactoring in my future. Here are the highlights:

  • PackageDir – the script will move completed packages to this folder at the end of the process.
  • ReleasePath – relative path to the bin directory to pull files from.
  • ProjectName – if you don’t make any customizations to this process, then this is the only field you need to worry about updating.
  • PackageId – my convention is to suffix “.MEF” to the project name. You can setup your own convention here.
  • MefNuSpecFile – this is where the build script will put the customized nuspec file when it is done writing it.
  • ReferenceLib – this is the part library you want to package.
  • ContractLib – the Code Contracts reference assembly is optional, but you need to make some adjustments to this recipe if you don’t want to include it.
  • SymbolLib – the debugging symbols, also optional, but it’s useful to me in my packages.

The first targets follow the property section:

  <Target Name="clean">
    <Delete Files="$(PackageId).nuspec; ..\$(PackageId).nuspec; $(ProjectName).nuspec; $(DependencyFile)" />
  </Target>
  <Target Name="default" DependsOnTargets="MefSpec; MefPackage; MovePackages"/>

During script development, it’s nice to be able to reset everything, so the clean target will delete intermediate and output files. You can invoke it using the /t switch on the command line.

C:\PizzaStore\CheesePizzaMaker\NuGet>c:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe NuGet.MEF.msbuild /t:clean

The default target specifies which targets must be executed to build and deploy the package. There is nothing special about the name “default”. It is only the default target because it is specified in the DefaultTargets attribute in the project element. We could specify “clean” or “MefSpec” as the default, but that wouldn’t make much sense.

  <Target Name="MefSpec"
          Condition="!Exists($(MefNuSpecFile))"
          DependsOnTargets="CreateDependencyFile; CreateMefSpec; CleanMefSpec; MergeMefSpec; UpdateMefSpec">
  </Target>

Like “default”, the MefSpec target is a meta-target which specifies other targets to run. It also includes a condition which will skip the spec creation if a spec already exists. This means that you can further customize the generated spec by hand without worrying about overwriting your changes on the next build.

  <Target Name="CreateDependencyFile" Condition="Exists($(PackagesFile))">
    <XslTransformation
      OutputPaths="$(DependencyFile)"
      XmlInputPaths="$(PackagesFile)"
      XslInputPath="$(XsltFile)"
      />
  </Target>

CreateDependencyFile executes an XslTransformation task when “packages.config” exists. It applies dependencydata.xslt to packages.config and creates dependencydata.xml, which is an XmlMassUpdate source file.

  <Target Name="CreateMefSpec">
    <Exec WorkingDirectory="$(MSBuildProjectDirectory)"
          Command="$(NuGetApp) spec -AssemblyPath &quot;$(ProjectDir)\$(ReferenceLib)&quot;" />
    <Move SourceFiles="$(ProjectName).nuspec"
          DestinationFiles="$(MefNuSpecFile)" />
  </Target>

CreateMefSpec executes “nuget spec” to create a default spec file. We give NuGet the path to the parts assembly so that it can fill in some of the standard data for us. Note that this command is executed from the “NuGet” subfolder for two reasons. First, we want to avoid overwriting the standard nuspec file if it exists, I couldn’t see a way to specify the output file name from the NuGet command line. Second, NuGet will automatically use the csproj file to generate a tokenized spec file for us if we run the spec command from a directory which contains a csproj (or any other project) file. We don’t want a tokenized spec file, so we need to run from a folder where NuGet can’t see the project file. Ultimately, we want the MEF-friendly spec file in the project folder, so we move it there before finishing CreateMefSpec.

  <Target Name="CleanMefSpec">
    <XmlUpdate XmlFileName="$(MefNuSpecFile)"
               XPath="/package/metadata/licenseUrl"
               Delete="true" />
    <XmlUpdate XmlFileName="$(MefNuSpecFile)"
               XPath="/package/metadata/projectUrl"
               Delete="true" />
    <XmlUpdate XmlFileName="$(MefNuSpecFile)"
               XPath="/package/metadata/iconUrl"
               Delete="true" />
    <XmlUpdate XmlFileName="$(MefNuSpecFile)"
               XPath="/package/metadata/releaseNotes"
               Delete="true" />
    <XmlUpdate XmlFileName="$(MefNuSpecFile)"
               XPath="/package/metadata/tags"
               Delete="true" />
    <XmlUpdate XmlFileName="$(MefNuSpecFile)"
               XPath="/package/metadata/dependencies"
               Delete="true" />
  </Target>

In CleanMefSpec, I delete fields I don’t care about, and one field I intend to replace with XmlMassUpdate. If you have use of the different URLs, notes, etc., then you should not delete these fields, but update them in the UpdateMefSpec target.

  <Target Name="MergeMefSpec">
    <XmlMassUpdate Condition="Exists($(DependencyFile))"
       ContentFile="$(MefNuSpecFile)"
                   ContentRoot="/"
                   SubstitutionsFile="$(DependencyFile)"
                   SubstitutionsRoot="/" />
    <XmlMassUpdate Condition="Exists($(MefDataFile))"
                   ContentFile="$(MefNuSpecFile)"
                   ContentRoot="/"
                   SubstitutionsFile="$(MefDataFile)"
                   SubstitutionsRoot="/" />
  </Target>

MergeMefSpec performs one or two XmlMassUpdate tasks. If there was a packages.config file, then there should now be a dependencydata.xml file created by the “CreateDependencyFile” target. If so, MergeMefSpec will update the MEF-friendly nuspec with the dependencies. You might want to review the dependencies after the spec is written. This technique does no interdependency analysis of the packages in packages.config. It just takes a dependency on all of them. So if you are writing package A, and A depends on B, and B depends on C, then your packages.config will list B and C as installed packages. However, package A may not need a direct dependency on C. You can imagine a scenario where B is updated and no longer requires C, in which case package A doesn’t need to include it any more either, but your spec doesn’t know that. If you are worried about this scenario, your current option is to edit the spec by hand to remove the indirect dependencies. This is one of the hacky areas I would like to revisit in the future, but for now just be aware of it.

Next, MergeMefSpec uses XmlMassUpdate to merge in the “static” customizations from mefdata.xml that don’t depend on whether or not there are other NuGet packages installed in the project. At this point we have a template nuspec which needs to be updated with relevant data from the project.

  <Target Name="UpdateMefSpec">
    <XmlUpdate XmlFileName="$(MefNuSpecFile)"
               XPath="/package/metadata/id"
               Value="$(PackageId)" />
    <XmlUpdate XmlFileName="$(MefNuSpecFile)"
               XPath="/package/metadata/title"
               Value="$(ProjectName) (MEF)" />
    <XmlUpdate XmlFileName="$(MefNuSpecFile)"
              XPath="/package/files/file[@src='AssemblyPath']/@src"
               Value="$(ReferenceLib)" />
    <XmlUpdate XmlFileName="$(MefNuSpecFile)"
               XPath="/package/files/file[@src='ContractPath']/@src"
               Value="$(ContractLib)" />
    <XmlUpdate XmlFileName="$(MefNuSpecFile)"
               XPath="/package/files/file[@src='SymbolPath']/@src"
               Value="$(SymbolLib)" />
  </Target>

UpdateMefSpec replaces some defaults and dummy data with the real values. Here we update the id, the title, and the paths to the package files. The custom nuspec is now complete.

  <Target Name="MefPackage"
          Condition="Exists($(MefNuSpecFile))">
    <!-- Get the version number of the main assembly to pass to nuget cli -->
    <GetAssemblyIdentity AssemblyFiles="$(ProjectDir)\$(ReferenceLib)">
      <Output TaskParameter="Assemblies"
              ItemName="AsmInfo" />
    </GetAssemblyIdentity>
    <Exec WorkingDirectory="$(ProjectDir)"
          Command="&quot;$(MSBuildProjectDirectory)\$(NuGetApp)&quot; pack &quot;$(MefNuSpecFile)&quot; -Verbose -NoPackageAnalysis -Version %(AsmInfo.Version)" />
  </Target>

Next up is MefPackage, where we build the MEF-friendly package. MefPackage first examines the parts assembly using a GetAssemblyIdentity task. This task places the assembly information into the property specified by the ItemName attribute; in our case it is called “AsmInfo”. Next we execute “nuget pack”. Our target is the nuspec file. I use Verbose because I like it. NuGet will not be happy that we have put dll files in the content folder and issues warnings suggesting that we might want to put them in a lib folder. Since the whole point of this exercise is to distribute libraries as content rather than references, I’ve suppressed the analysis step using NoPackageAnalysis. Finally, we specify the Version flag and give it the version data supplied by the GetAssemblyIdentity task.

  <Target Name="MovePackages"
          Condition="Exists($(PackageDir))">
    <!-- Using command line because I want to be sure to get the most up to date list of *.nupkg -->
    <Exec WorkingDirectory="$(ProjectDir)"
          Command="move /y *.nupkg &quot;$(PackageDir)&quot;" />
  </Target>
</Project>

As with the standard nuget build script, MovePackages checks that the destination directory exists then uses the shell to move the packages to the destination. I found that it was much easier to use the shell because it will get the most recent list of *.nupkg files in the source folder, and will happily overwrite packages in the destination folder. Finally, we close the project element and the MSBuild script is done.

Test the Build

Switch to release mode and build your project. If everything is setup correctly, your packages should appear in the folder specified by the PackageDir property. If not, see my previous post for troubleshooting tips.

Test the Package

In the PizzaStore example, there is a dummy program that does nothing but serves as a place to simulate different composition scenarios. To test the package I removed the project reference to PizzaStore. There was no reference to CheesePizzaMaker since I used .bat files to move the dll files around during the MEF talk.

After removing the PizzaStore reference I setup Visual Studio to use PackageDir as a package source, and then used the NuGet package manager in GUI mode to install the MEF package. As expected, NuGet created the Parts folder, set the Build Action and other properties, and also pulled in the dependency to PizzaStore and re-created the reference (this time as an assembly reference rather than a project reference).

Uninstalling the CheesePizzaMaker.MEF package also removed all the content files and the assembly reference.

Thanks for Reading

There you have it: MEF, now with NuGet. I’m sure there is a candy bar pun in there somewhere.