{"id":753,"date":"2013-08-22T13:29:00","date_gmt":"2013-08-22T13:29:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/dotnet\/2013\/08\/22\/improved-package-restore\/"},"modified":"2021-09-30T17:23:53","modified_gmt":"2021-10-01T00:23:53","slug":"improved-package-restore","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/improved-package-restore\/","title":{"rendered":"Improved Package Restore"},"content":{"rendered":"<p>As we\u2019ve <a href=\"http:\/\/blogs.msdn.com\/b\/dotnet\/archive\/2013\/06\/12\/nuget-package-restore-issues.aspx\">previously explained<\/a> we receive various reports on how our NuGet packages don\u2019t play nicely with NuGet\u2019s package restore feature. In this blog post I\u2019ll talk about an update <a href=\"http:\/\/www.nuget.org\/packages\/Microsoft.Bcl.Build\/1.0.10\">we shipped<\/a> to our infrastructure package <strong>Microsoft.Bcl.Build<\/strong> that reduces the impact.<\/p>\n<h2>The Issue<\/h2>\n<p>To recap, some of our packages need to participate in the build in order to work properly. Examples of tasks that require build participation include generating binding redirects or selecting the appropriate native dependency based on the CPU architecture the build is producing.<\/p>\n<p>Build participation is implemented by adding an import to an MSBuild .targets file. Generally, build participation isn\u2019t optional which is <a href=\"http:\/\/blogs.msdn.com\/b\/dotnet\/archive\/2013\/06\/12\/nuget-package-restore-issues.aspx\">why we decided<\/a> not to use <a href=\"http:\/\/docs.nuget.org\/docs\/release-notes\/nuget-2.5#Automatic_import_of_msbuild_targets_and_props_files\">NuGet\u2019s feature to add a target file import<\/a>. NuGet will add the import with a condition that checks whether the .targets file already exists, i.e. whether the NuGet package was already restored.<\/p>\n<p>Both solutions aren\u2019t ideal:<\/p>\n<ul>\n<li>A non-optional import ensures that building will fail when packages are missing because the imported target file can\u2019t be found. However, this also means that you can\u2019t open the solution in Visual Studio (see picture below). Also, the error message isn\u2019t really actionable as it doesn\u2019t include any instructions on how to fix the issue.<\/li>\n<li>An optional import allows the project to load and build. However, even if you have package restore enabled, the first build may not work because by the time the project was build, the targets file was still missing. This can result in build breaks or \u2013 even worse \u2013 the build may succeed but with incorrect outputs.<\/li>\n<\/ul>\n<p><img decoding=\"async\" class=\"aligncenter size-full wp-image-20074\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2013\/08\/2744.OldError.png\" alt=\"\" width=\"377\" height=\"191\" srcset=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2013\/08\/2744.OldError.png 377w, https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2013\/08\/2744.OldError-300x152.png 300w\" sizes=\"(max-width: 377px) 100vw, 377px\" \/><\/p>\n<p style=\"padding-left: 30px;\"><em>The imported project &#8220;&lt;solution-path&gt;packagesMicrosoft.Bcl.Build.1.0.8toolsMicrosoft.Bcl.Build.targets&#8221; was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.<\/em><\/p>\n<h2>The Improvement<\/h2>\n<p>We\u2019ve updated <strong>Microsoft.Bcl.Build<\/strong> to use a different approach. The new version will use a conditional import similar to what <a href=\"http:\/\/docs.nuget.org\/docs\/release-notes\/nuget-2.5#Automatic_import_of_msbuild_targets_and_props_files\">NuGet\u2019s automatic import feature does<\/a>. This will always allow the project to load in Visual Studio.<\/p>\n<p>However, <strong>Microsoft.Bcl.Build<\/strong> also adds a target to your project that will run after the build is finished. This target checks whether the current build restored packages and if so fail the build with an actionable error message:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter size-full wp-image-20075\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2013\/08\/6574.NewError.png\" alt=\"\" width=\"1139\" height=\"164\" srcset=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2013\/08\/6574.NewError.png 1139w, https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2013\/08\/6574.NewError-300x43.png 300w, https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2013\/08\/6574.NewError-768x111.png 768w, https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2013\/08\/6574.NewError-1024x147.png 1024w\" sizes=\"(max-width: 1139px) 100vw, 1139px\" \/><\/p>\n<p style=\"padding-left: 30px;\"><em>The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see <a href=\"http:\/\/go.microsoft.com\/fwlink\/?LinkID=317568\">http:\/\/go.microsoft.com\/fwlink\/?LinkID=317568<\/a>.<\/em><\/p>\n<p>Building a second time will fix this error. Please note that this error will only appear if packages were missing so it\u2019s not like you always have to build twice.<\/p>\n<p>This solution doesn\u2019t address build server \/ continuous integration (CI) scenarios. In order to successfully use package restore on the build server, you have two options:<\/p>\n<ol>\n<li>Check-in the .targets file.<\/li>\n<li>Explicitly run NuGet package restore prior to building your project\/solution.<\/li>\n<\/ol>\n<h2>NuGet 2.7<\/h2>\n<p>Prior to version 2.7, NuGet makes package restore a bit more complicated than most people would like it to be:<\/p>\n<ol>\n<li>First of all you need to manually enable it for the solution. This will add a NuGet.exe, NuGet.config and NuGet.targets file to your solution and you are expected to check those files in.<\/li>\n<li>Explicitly running package restore for the solution isn\u2019t a single step. You need to run a command for each project, such as <code>nuget.exe install .Project1packages.config<\/code>.<\/li>\n<\/ol>\n<p>NuGet 2.7 makes this a lot easier:<\/p>\n<ol>\n<li>You no longer need to enable package restore explicitly \u2013 when building in VS all <a href=\"http:\/\/docs.nuget.org\/docs\/release-notes\/nuget-2.7#Automatic_Package_Restore_in_Visual_Studio\">packages are restored automatically<\/a>.<\/li>\n<li>Running package restore on a build machine <a href=\"http:\/\/docs.nuget.org\/docs\/release-notes\/nuget-2.7#Simplified_Package_Restore_from_the_Command-Line\">is now super easy<\/a>. You only need to check-in NuGet.exe (nothing else) and you can put it wherever you want. It can even be in a well-known location on your build server and excluded from every solution if desired. Prior to the build you simply run <code>nuget.exe restore pathtomysolution.sln<\/code>.<\/li>\n<\/ol>\n<p>Also, the NuGet team is talking to all major providers of build\/CI servers (incl. TFS) so that at some point the second step can be handled automatically by the build servers. For more details, have a look at the <a href=\"http:\/\/docs.nuget.org\/docs\/release-notes\/nuget-2.7\">NuGet 2.7 release notes<\/a> and the <a href=\"http:\/\/docs.nuget.org\/docs\/reference\/package-restore\">new Package Restore documentation<\/a>.<\/p>\n<h2>Summary<\/h2>\n<p>The new version of <strong>Microsoft.Bcl.Build<\/strong> will ensure that solutions containing our packages will load successfully even if packages aren\u2019t restored yet. This affects all .NET NuGet packages that depend on it, such as <strong>Microsoft.Net.Http<\/strong>, <strong>Microsoft.Bcl<\/strong>, and <strong>Microsoft.Bcl.Async<\/strong>.<\/p>\n<p><strong>Microsoft.Bcl.Build<\/strong> will give an actionable error message in cases the package was missing by asking you to build again.<\/p>\n<p>When coupled with <a href=\"http:\/\/docs.nuget.org\/docs\/release-notes\/nuget-2.7\">NuGet 2.7<\/a> where package restore is automatic in Visual Studio and isn\u2019t implemented through MSBuild, the experience is transparent and smooth. However, this doesn\u2019t address build server scenarios yet so you still need run <code>nuget.exe restore solution.sln<\/code> prior to build, or check-in the .targets file if preferred.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As we\u2019ve previously explained we receive various reports on how our NuGet packages don\u2019t play nicely with NuGet\u2019s package restore feature. In this blog post I\u2019ll talk about an update we shipped to our infrastructure package Microsoft.Bcl.Build that reduces the impact. The Issue To recap, some of our packages need to participate in the build [&hellip;]<\/p>\n","protected":false},"author":335,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685],"tags":[30,43,104,110],"class_list":["post-753","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","tag-announcement","tag-bcl","tag-nuget","tag-portable-class-libraries"],"acf":[],"blog_post_summary":"<p>As we\u2019ve previously explained we receive various reports on how our NuGet packages don\u2019t play nicely with NuGet\u2019s package restore feature. In this blog post I\u2019ll talk about an update we shipped to our infrastructure package Microsoft.Bcl.Build that reduces the impact. The Issue To recap, some of our packages need to participate in the build [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/753","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/335"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=753"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/753\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=753"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=753"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=753"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}