4
votes

My solution is configured to "restore packages", but one of its projects is failing to build:-

3>C:\Builds\1\xxxxx\xxxx.csproj(223,5): error : 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 ..\packages\System.Data.SQLite.Core.1.0.97.0\build\net45\System.Data.SQLite.Core.targets.

It might be a red-herring but the above error appears in the log before the package restore stuff, i.e.

2>RestorePackages:

Restoring NuGet packages...

Near the end of the offending project's .csproj file is this <Target> section, that appears to be generating the above error:-

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
<Import Project="..\packages\System.Data.SQLite.Core.1.0.97.0\build\net45\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.97.0\build\net45\System.Data.SQLite.Core.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('..\packages\System.Data.SQLite.Core.1.0.97.0\build\net45\System.Data.SQLite.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\System.Data.SQLite.Core.1.0.97.0\build\net45\System.Data.SQLite.Core.targets'))" />
</Target>

What's going on? And am I correct in my assumption that this check is happening before the solution's packages have even been restored (hence why it's failing)? How do I fix this?

Other projects in the solution (those that don't reference the SQLite core package) have their packages restored fine, and build successfully.

2

2 Answers

5
votes

What I discovered is that this relates to the approach you use to restore missing NuGet packages during a build. I'm using the well-known "Enable NuGet Package Restore" option (via right-clicking the solution). The problem is that the NuGet package in question ("System.Data.SQLite Core (x86/x64)") adds a pre-build step (the earlier element) which checks that this package has installed a a build target file called System.Data.SQLite.Core.targets.

Chicken and egg springs to mind - the packages haven't yet been restored, but a pre-build step is checking for the existence of a package's file!

The recommended approach for restoring NuGet packages now seems to be the newer "automatic package restore" feature. My understanding is that this restores NuGet packages before a build starts, avoiding the above issue. Unfortunately this feature isn't supported by TFS 2012. There is a workaround (detailed here) which involves creating an msbuild project file in your solution, which is responsible for restoring NuGet packages before proceeding to build the solution, but this was starting to feel messy.

For anyone interested (or familiar with SQLite.Net), this is what I did to solve my problem:-

I removed the "System.Data.SQLite Core (x86/x64)" package and added the package "System.Data.SQLite Core MSIL" instead. This only contains the managed System.Data.SQLite.dll assembly, and doesn't do anything clever with custom build targets.

This assembly has a dependency on the native SQLite.Interop.dll, but for some strange reason is designed to look for this in a [bin]\x86 or [bin]\x64 subfolder (depending on architecture). These interop DLLs were part of the original package that I removed; its build target (that was causing my problem) is responsible for copying the DLLs to these subfolders.

To get around this I added the x86 & x64 interop DLLs to my project, like this:-

FooProject
  \x86
     SQLite.Interop.dll
  \x864
     SQLite.Interop.dll

I made sure their Build Action was "Content", then changed their Copy to Output Directory setting to "Copy always". The project folder structure is retained when "Content" files are copied to the output folder, so it's a handy way of creating the [bin]\x86 and [bin]\x64 subfolders, and their respective DLLs.

0
votes

In my case, I check the postistion in the .csproj indicate does have the System.Data.SQLite.Core.targets file, then I restart the computer and restart the visual studio, then build success without error.