Solution inter-dependencies and NuGet

Feb 29, 2012 at 2:11 PM

Hello!

So I'm in need of some advice/something.

I have a solution that I'm putting a load of common code into for re-use within my organization. The projects in the solution build to DLLs that other bits of work can reference, and I'd like to use NuGet to distribute/maintain them using an in-house NuGet feed. 

I'll use the following examples:

  • Utilities.LIB - Houses various non-specific utility classes.
  • Logging.LIB - Houses an abstracted logging framework

My solution  structure is as follows:

  • CommonCode.sln
    • Logging.LIB
      • References log4net (NuGet)
      • References Utilities.LIB (Project Reference)
    • Utilities.LIB

The Utilities.LIB project contains utility classes that a consumer can use independently of the Logging.LIB project. If all you want to use is Utilities.LIB, then you can use the Utilities.LIB NuGet package and everything's fine.

However, since the reference to Utilities.LIB in Logging.LIB is a project reference, NuGet doesn't pick it up as a dependency and therefore there's no real indication that you need to reference Utilities.LIB when you want Logging.LIB functionality.

My initial thoughts were to make a NuGet packaging powershell script that is tied into our build script, but is there a better way of doing this a bit more gracefully?

Thanks :)

  - kaitlin

Mar 1, 2012 at 12:44 AM

I think you're doing something similar to what I'm doing, where you are creating multiple packages from the same solution. At build time you have project references between your classes, but you're building NuGet packages where you want the project references replaced by package dependencies in the generated packages.

I'm doing this by explicitly adding the dependency information in the .nuspec file for the project that is dependent on other project you are also generating a package for. So, in your example, In the .nuspec file for Logging.LIB, I'd add this inside the metadata element:

<dependencies>
      <dependency id="Utilities.LIB" version="1.0.0.0" />
</dependencies>

This SHOULD add the dependency for you. A couple of caveats:

  1. I was having problems getting the .csproj based nuget pack work the way I wanted (our official builds have a different msbuild $(OutDir) specified than the normal bin/$Release$ path and I was fighting so much trying to get the .csproj based packaging to find things in the right places that I decided the .csproj packaging was causing more pain than they were preventing for my scenario), so I moved to just explicitly specifying everything in the .nuspec and packing it directly. I believe that the .csproj based packaging should merge in dependencies specified in the .nuspec, but YMMV.
  2. Still struggling with this one - I want the dependency version specified in Logging.LIB to match the version of the Utilities.LIB package that I'm also building so that when updating to a new Logging.LIB, you would also get the new Utilities.LIB. My current approach for this is to modify the NuGet.targets to pass an additional property when doing the pack (e.g. nuget pack -p "OutDir=c:\somepath;GlobalPackageVersion=2.1.232" Logging.nuspec), then Logging.nuspec looks something like:
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
  <metadata>
    <id>Logging.LIB</id>
    <version>$globalpackageversion$</version>
    .
    .
    .
    <dependencies>
      <dependency id="Utilities.LIB" version="$globalpackageversion$" />
      <dependency id="log4net" version="2.0.0" />
    </dependencies>
  </metadata>
  <files>
    <file src="$outdir$\Logging.LIB.*" target="lib\net40" />
  </files>
</package>

Hope this is helpful.

If anyone has other approaches, I'm all ears. It's turning into a bunch of custom work to get building multiple related packages in the same solution to work.

Mar 1, 2012 at 7:26 AM

I'm actually also handcraft the nuget packages myself, because of the lack of project reference -> nuget dependency automation is missing (which at some point was promised in version 1.6 (but got pushed back) as far as i remember)

but gonna use the property functionality to get the dependency version correct...

Mar 3, 2012 at 6:02 AM

@dm_tolerance Correct, there's no project reference to NuGet dependency detection.

I generally have a {solution}.msbuild file for large solutions with multiple projects (and which result in multiple NuGet packages), and add a target to that MSBuild file that's responsible for generating all my NuGet packages, by <Exec>ing to nuget.exe, after dropping all the final .dlls into a packaging directory. I don't know if that would be helpful to you.

Mar 5, 2012 at 10:45 AM

Well thanks for all that folks. It'd be really handy to have nuget automagically resolve project references as nuget packages but it'd mean you'd have to pre-define the projects that are going to be published using nuget, which is a little hard to predict programmatically.

I think my approach of "do a powershell script" and parsing the project XML info and all the relevant packages.config files is going to be the way forward...

  - k

Mar 16, 2012 at 9:35 AM

It doesn't help for resolving the project references, but I just added a work item to add something like an -IncludeDependencies option to the pack command. With this you could point at a packages.config file when packing a .nuspec file and have the dependencies in that file added to your package.

This is already happening if you use the .csproj when packing, but as discussed above using the .csproj also brings a lot of other baggage. If you would also like to see automatically including the correct dependencies while still having the control of a direct .nuspec file, please vote for the work item.

http://nuget.codeplex.com/workitem/2015

Developer
Mar 17, 2012 at 2:02 AM
That's non-trivial to do without having the actual packages in disk. When we add dependencies to your built package, we pick the minimal set needed since packages.config explicitly lists each dependency.

Sent from my Windows Phone

From: ReedRector
Sent: 3/16/2012 2:36 AM
To: David Fowler
Subject: Re: Solution inter-dependencies and NuGet [nuget:346720]

From: ReedRector

It doesn't help for resolving the project references, but I just added a work item to add something like an -IncludeDependencies option to the pack command. With this you could point at a packages.config file when packing a .nuspec file and have the dependencies in that file added to your package.

This is already happening if you use the .csproj when packing, but as discussed above using the .csproj also brings a lot of other baggage. If you would also like to see automatically including the correct dependencies while still having the control of a direct .nuspec file, please vote for the work item.

http://nuget.codeplex.com/workitem/2015

Mar 20, 2012 at 11:51 PM
Edited Mar 20, 2012 at 11:58 PM

@dfowler - I have no problem with requiring that the packages referred to by the .config file must be present. Although taking a look, you probably need the .csproj to find the path to where the package is actually located.

The primary thing I'm trying to accomplish is not having to manually keep the dependencies versions in my .nuspec in sync with the actual versions of the dependecies I'm using. Updating the nuget reference on some external component and forgetting to also update the new version number in my .nuspec would result in out of date references in my package that could be hard to detect in testing the package.

Since version changes are more likely to happen with existing package dependencies than adding new packages, I'm fine with manually keeping track of the top level dependency in my .nuspec.

At the simplest, all I really want is if I have this in my .nuspec:

    <dependencies>
      <dependency id="AspNetWebApi.Core" version="4.0.20126.16343" />
      <dependency id="Nebula-System.Diagnostics.Tracing" version="$version$" />
    </dependencies>

and this in my packages.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="AspNetWebApi.Core" version="4.0.33333.33333" />
  <package id="System.Net.Http" version="2.0.20126.16343" />
  <package id="System.Net.Http.Formatting" version="4.0.20126.16343" />
  <package id="System.Web.Http.Common" version="4.0.20126.16343" />
</packages>

 

that the version for AspNetWebApi.Core used for packaging uses the version from the pacakges.config instead of the one specified in the .nuspec. Basically any ids in the .nuspec dependencies that match an id in the packages.config will use the version from packages.config.

Maybe even an extension to the <dependency> specification in the .nuspec to make this all more explicit:

    <dependencies>
      <dependency id="AspNetWebApi.Core" versionFromConfig=".\packages.config" />
      <dependency id="Nebula-System.Diagnostics.Tracing" version="$version$" />
    </dependencies>

What do you think of that?

Dec 27, 2012 at 3:14 PM

I have built a post build command line to build a solution with project references into nuget packages. If projects have a nuspec file it builds the reference nodes in the nuspec accordingly based on the project references. You don't even need to add references to the nuspec file manually.

I wrote a blog article on how to setup a solution here:
http://candordeveloper.com/2012/12/12/nuget-package-build-a-solution-of-projects/

And a solution with this implemented can be found on github here:
https://github.com/michael-lang/candor-common