Twitter Feed Popout byInfofru

OverrideThis.com

Adventures in .NET Software Craftsmanship!

Enable NuGet Package Restore – When the basics fail!

Recently, checking in third party libraries “dependencies” into your source code repository has become a frowned upon practice. The reason being it increases the size of your repository, specially if you are using a DVCS, and every commit increases the size of the repository exponentially till the point when interacting with the repository takes valuable time away from the developers due to network and disk I/O use. 

 

In the .NET space the tool of choice for centralizing and managing external dependencies is currently NuGet (http://www.nuget.org).  NuGet is a Visual Studio extension that allows developers to right-click and add they’re favorite open source libraries from a centralized repository.   NuGet also provides the capability to enable automated  package restore capabilities (http://docs.nuget.org/docs/workflows/using-nuget-without-committing-packages), which means, that if your dependencies are not downloaded to your computer they automatically will be when you compile your code base from the Visual Studio IDE.  This feature ensures that even though we are changing the traditional model of managing external dependencies we are not changing the traditional “F5 Build” experience that most developers are familiar with and expect. 

 

However, there are some scenarios where this process fails, for instance when a NuGet package modifies the build by adding custom MSBuild Targets to your project files (.csproj). Visual Studio, or MSBuild for that matter, are not going to be able to load the .csproj to build your project since the build depends on the packages that the build package is going to download prior to compile.  If you followed what I said, there is a circular dependency between the build process and the NuGet packages, since now the build depends on the NuGet packages to run. One example of such NuGet package is PostSharp (http://www.postsharp.com), which is a very valuable AOP tool that needs to integrate into your build process to do its work, so I am not complaining just pointing it out. 

 

A Workaround

One possible workaround is to initialize the process of retrieving dependencies, or to use a term stolen from my co-workers blog, kick start the process  before you even open up Visual Studio.  There are many ways this could actually be accomplished but I choose to build a batch file (.cmd) and an MSBuild project file that will do all the work for you.

 

<!-- KickStart.msbuild -->
<Project DefaultTargets="KickStart"
    ToolsVersion="4.0"
    xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <NuGetExe Condition="$(NuGetExe) == ''">.\.nuget\nuget.exe</NuGetExe>
    </PropertyGroup>
    <Target Name="KickStart">
        <ItemGroup>
            <NuGetPackageConfigs Include="**\packages.config" />
        </ItemGroup>
        <Exec Command="$(NuGetExe) install %(NuGetPackageConfigs.Identity) -o packages" />
    </Target>
</Project>

 

The MSBuild file, in a nutshell, just finds the packages.config files in your solution using a relative path search and executes the NuGet command line executable to populate the packages folder.  Assuming you use regular Visual Studio conventions for where your project files (.csproj, .vbproj, etc.) are located, you should be fine by placing both these files right next to your solution (.sln) file.

 

@rem KickStart.cmd
SET MsBuildPath=C:\Windows\Microsoft.NET\Framework64\v4.0.30319
SET NuGetExe=.nuget\nuget.exe
%MsBuildPath%\MsBuild.exe kickstart.msbuild /t:kickstart /p:NuGetExe=%NuGetExe%

 

The batch (.cmd) file is just a shortcut for executing the MsBuild project file.

 

Conclusion

This is just one way to solve this issue, but hopefully the solution I have outlined helps you if you are ever faced  with the need to kick start your NuGet dependencies outside the Visual Studio IDE.  The good thing about this problem is that only relevant when you get a new clone of your repository at that point you just execute the kickstart.cmd file once or in your build server where this process should be happening continuously.