What Does It Really Mean to Install a NuGet Package In a .NET Core Project Within Visual Studio

You’ve ran into it countless times – you open a C# project in Visual Studio and you get to see “Restoring packages for <project_name>.csproj“:

It takes a few seconds usually, then goes away. You continue working for hours, sometimes days, never to encounter the message again. Then – out of the blue – it’s displayed again. There doesn’t seem to be any logic to when this pops up. You might be cloning a Git repository storing a C# project, and moments after, Visual Studio generates the message. Why is there anything to be restored, as we’ve just cloned the full source code for a C# project ? Or you decide to use a different target framework for your project, and sure enough the message comes again. Why is this so ? Decided to install a NuGet package to your project ? – the operation that will be run will be a “package restore”. What is there to restore as you’ve just installed a single package only ?

And the ultimate situation: you create a brand new .NET Core project in Visual Studio, and immediately after it’s done, you still get a message that packages are being restored for your new project. But what packages ? No one selected any NuGet package to be installed yet !

So what’s with this package restore and what really happens deep-down when this occurs ?

TL;DR (I just need the exact steps that occur when installing a NuGet package to a .NET Core project from within Visual Studio. No theory, no intro. Now !): Skip right to step-by-step list in this section of this post.

What are we going to tackle in this post and in what order:

To avoid discussing only theory, we’ll follow along with a specific example: one simple .NET Core C# project that uses the CommandLineParser NuGet package. As a matter of fact, we’ll just use the quickstart example at the package’s nuget.org page to build a .NET Core C# project in Visual Studio. We’ll look at what exactly happens when the NuGet package is installed and when the project is subsequently built. This specific NuGet package (CommandLineParser) has been chosen since it has no dependencies, which will simplify the discussion later on.

But first, a list of what to expect from this post, and what are the assumptions going forward. Don’t worry if some of the terms don’t make sense for now – they’ll all be explained later on.

Assumptions / Expectations

  • What NuGet is and what it’s used for is not the goal of this post. For an intro to NuGet there’s a very good article here. There’s also a nice 5-video explanation on Channel9 here. As for what nuget.org is, this is explained here
  • We’ll be using PackageReference only, as we’re dealing with a .NET Core project, which by default uses this style of package management format
  • We’re building a “Console Application” .NET Core 3.1 project, which will result in an .exe produced as well (alongside the assembly’s .dll). For further details about the executable file and what it actually contains see this post
  • The Windows operating system will be the main focus of the post, with MacOS referenced in a few places only
  • Visual Studio 2019 16.5.1 is used on Windows, and Visual Studio for Mac 8.5.2 is used on MacOS
  • Only the Visual Studio built-in NuGet Package Manager UI is discussed. All the possible clients that can handle NuGet packages on various platforms are listed here, but they’re not in the scope of this post
  • NuGet dependencies are not discussed in this post, but are left for a future one
  • We’ll consider both checkboxes in NuGet Package Manager to be ticked (when this won’t be so, it’ll be clearly flagged):
Figure 1 – NuGet Package Manager settings in Visual Studio

Anatomy of a NuGet Package

First thing’s first: what is a NuGet package ? There’s quite some documentation around the format of a NuGet package, ranging from up-to-date info here (showing the subfolders than can exist within) to articles that showed up in the MSDN Magazine when this was in full swing here. Simply put, a NuGet package is just a zipped folder whose content matches specific requirements in terms of composition, that had its extension changed from .zip to .nupkg.

The package format allows for quite a few features to be built in, but we’ll just look at the basics, by sticking to the CommandLineParser NuGet package that we decided to use in the beginning. Here’s the content of the NuGet package (.nupkg file) for the current version at the time of this writing (2.7.82, as of Apr 2020):

Figure 2 – Raw content of the unpacked .nupkg file

Let’s go over some of the items above*:

  • lib folder: contains the assemblies and optionally the XML documentation files for each such assembly, grouped under each platform targeted. The name of the platform is codified as a target framework moniker (TFM) using the conventions here (eg netstandard2.0 is the string for .NET Standard 2.0)
  • <packageId>.nuspec: contains package metadata, such as version, title, author, description, dependencies, etc. Full structure here
  • license information
  • .signature.p7s: if the package’s author opted, it contains the signature applied. It will also contain a counter-signature applied by nuget.org (details here)

The format listed above is how the package exists while in transit (eg on the nuget.org servers, or just downloaded on a client machine). Once retrieved, the .nupkg file is unpacked and installed locally under a slightly different format. Among the files present, there’s a few extra as opposed to what we’ve looked at before* :

  • The .nupkg file itself
  • <packageId>.<packageVersion>.nupkg.sha512: the SHA of the .nupkg file itself
  • .nupkg.metadata: contains the hash of the package, excluding the signatures

How do we get from a .nupkg file to a locally deployed NuGet package containing the files listed above ? We’ll see this in detail a bit later. But first, a few underlying concepts that need to be grasped.

Package Management Formats

In the beginning we said we’re going to use the CommandLineParser NuGet package within a .NET Core C# project. So how does our C# project knows which NuGet packages it uses ? It needs to be able to somehow reference the NuGet package we’re going to install. How this information is stored is called a package management format. There are 2 types:

  • PackageReference: this is a section right within the .csproj file, containing the list of NuGet packages referenced
  • packages.config: a file with this name is stored within the project folder, and it’s this file that contains the list of the NuGet packages referenced

Why would we care about the type of package management format our project uses ? Because there are further implications to how the project and the NuGet mechanism interoperate. For one, as stated here, “in packages.config based projects, the packages are installed in a folder relative to the project file. However in PackageReference, the packages are consumed from the global-packages folder, which can vary from machine to machine“. Another implication: here it’s stated that “In NuGet 4.0+, restore also happens automatically when you make changes to a SDK-style project (typically a .NET Core or .NET Standard project)“. The feature referenced – the package restore – will be extremely important further on.

On the other hand, projects.config as a package management format is no longer actively developed, plus it has a range of other disadvantages listed here.

So which one should we choose for our project ? Well it turns out that this decision is made for us: by default a .NET Core project will use the SDK style project format (source here), which in turn uses the PackageReference format. This can be seen quite clearly by looking inside the project file (.csproj). Here’s how this will look once the CommandLineParser NuGet package is installed within the project (notice line 1 and 9 in particular) :

Figure 3 – The project file after the CommandLineParser NuGet package is installed

What is a NuGet Package Restore ?

What is the mysterious Package Restore then ? As per this link, “Package Restore tries to install all package dependencies to the correct state matching the package references in your project file (.csproj) or your packages.config file“. In other words, it uses the information in the project configuration files to install the required packages. Should those packages rely on other packages being installed first, it will install those in turn.

How does this translate to our project ? The NuGet package restore will simply install the CommandLineParser NuGet package that we’ve seen referenced in the .csproj above. As there’s no dependency to this package we’re installing, no extra work will be involved with installing other packages.

Let’s see next the actual process of installing this NuGet package. We’ll track it in detail, from the very beginning.

What Happens ?

So you go in Visual Studio’s NuGet Package Manager UI, leave the default nuget.org source selected, browsed to the desired package, chose the version you’re after, tick the project(s) where you’d like this installed and you hit “Install” *. What’s the sequence of actions that Visual Studio invokes next ? Let’s follow the official workflow described here:

First, the NuGet package must be located and installed locally on the system:

  1. <project_name>.csproj.nuget.dgspec.json is updated* in the obj folder to include the package being installed as a reference. The fact that the exact package name and version is stored within this file at the very beginning of the process might come as a surprise, but remember that we’re initiating the process of deploying the NuGet package from a window (NuGet Package Manager) where we’ve specifically chosen the package and its version
  2. If the NuGet package isn’t already on the system – meaning it’s neither in the global-packages folder, nor in the http-cache – then it is retrieved first:
    • index.json for the target NuGet package is retrieved. This file contains the list of versions available for this particular package*
    • The chosen version is appended to the URL and to the name of the .nupkg file to be retrieved
    • The .nupkg file is retrieved and placed in a temporary folder
  3. If the package has just been retrieved, it’s next installed in the http-cache folder. This folder resides in %localappdata%\NuGet\v3-cache, as per this link. Just as the link states, the files within have a .dat extension, each corresponding to a package. As in our scenario the package was pulled directly from nuget.org, all the .dat files ever retrieved from there are grouped under one single subfolder
  4. The package is unpacked within a folder named after the package id and the version initially chosen. This folder is placed under the global-packages folder, which resides in %userprofile%\.nuget\packages. The package’s folder contents have already been discussed previously
  5. Package dependencies are retrieved and installed next at this point, but since our selected NuGet package doesn’t have any dependency, there is nothing to be done here
  6. A check is performed whether the framework used by the project – which for our sample is .NET Core 3.1 – is compatible with any of the platforms supported by the package

At this point a popup window gets displayed, asking for confirmation before moving on:

Figure 4 – Confirmation that NuGet can proceed installing the package

Second, now that the NuGet package is installed locally, our C# project is next configured to reference it. There are 2 major steps of interest to us here, that occur in the following order:

  1. The project’s .csproj file is updated to include a PackageReference entry for the NuGet package that has been recently installed
  2. The project.assets.json file – referred to as the “package dependency graph” in the official workflow doc and stored within the obj folder – gets updated* to include the new package as a dependency. This file simply lists the dependencies of our C# project, as stated here

The local package installation is captured in Visual Studio’s “Package Manager” output window*, which provides good insight to the process. Here’s the said output log below, generated from the moment the NuGet package installation is initiated within the NuGet Package Manager until it completes:

Listing 1 – Visual Studio’s Package Manager output log after installing the CommandLineParser NuGet package

Note that at this point the .csproj file on disk is not yet updated to include a reference to the NuGet package. Its contents are very much the same as before starting the whole workflow. Yet if you double-click the project name in Solution Explorer, which subsequently opens the .csproj file – there’s a new reference to the NuGet package we’ve just installed, just as the expected outcome back in figure 3. Why the discrepancy ? One just needs to save the file within Visual Studio in order for the new version of the .csproj file (known so far to Visual Studio only) to be committed back to disk.

This concludes the process of installing the NuGet package and integrating it with the project.

Overall, notice how this whole workflow is actually a NuGet package restore operation, which we’ve discussed previously: the project configuration is made to reference the package we’re installing, and then the package is installed automatically. This is captured in the official workflow doc: “Simply said, the different NuGet tools typically create a reference to a package in the project file or packages.config, then perform a package restore, which effectively installs the package“. Where things slightly differ is that in the “traditional” package restore the project configuration file (.csproj) is modified first, and based on the new package references defined within, the corresponding packages are subsequently installed. But as we’ve seen above, Visual Studio does things a bit different, whereby the .csproj file is modified last*, after the NuGet package is installed. This is stated however clearly in the same official workflow doc: “If the installation tool is Visual Studio or the dotnet CLI, the tool first attempts to install the package. If it’s incompatible, the package is not added to the project file or packages.config“. The compatibility check is the one done in step 6 under the first group of steps, and it’s the gate-keeper to the second group, which includes updating the .csproj.

The Final Product

How does our application actually get to use the newly installed NuGet package ? When dealing with references to other assemblies, one usually expects to find the module files (.dlls) within the app’s output folder. So you might rightly wonder how will the .dll file corresponding to the assembly present within the NuGet package be used by our code at run time; after all, without the types defined within the .dll file, it’s impossible for our application to run. The NuGet package’s assembly we’re after is located for now only in lib\netstandard2.0\CommandLine.dll* within the packet’s folder hosted within the global-packages folder.

You might also ask yourself what was the point of generating the project dependency graph (project.assets.json) previously, as that wasn’t actually used in any way so far.

The 2 answers are below, as invoking a build operation against the Visual Studio solution containing our C# project results in the following:

  • The NuGet package’s assembly is copied to our project’s output folder. As specified here, “For executable projects targeting .NET Core 3.0 and later, library dependencies are copied to the output folder. This means that if there isn’t any other publish-specific logic (such as Web projects have), the build output should be deployable*. The same docs link continues: “Building requires the project.assets.json file, which lists the dependencies of your application. The file is created when dotnet restore is executed. Without the assets file in place, the tooling can’t resolve reference assemblies, which results in errors“. This explains why this particular file was generated previously
  • Our own application is built, complete with the executable (.exe) host, its own assembly (.dll) and the runtime and dependency .json files

The No-Op Restore

Looking back at the “Package Manager” output log in listing 1 in the section describing the installation workflow you see 2 blocks of operations, with each block completion marked by a ==Finished== text. The first block contains all the operations corresponding to the NuGet package restore discussed before – just notice line 22 telling us that project.assets.json is written to disk. So what’s with the second block that also mentions a NuGet restore in the output log then ?

This actually corresponds to a no-op restore. What is this ? One of NuGet’s wiki pages explains clearly: “the VS Client currently has a non-configurable no-op implemented. The primary goal of this feature is to optimize restore so that if the restore result is up-to-date, the corresponding restore operation is not executed“.

Why is this no-op restore kicking in though, as opposed to the “full” package restore ? Well, the thing is that project.assets.json has already been updated to its final value. Same with the .csproj file, so there’s no change that happened which would justify a full package restore, which will have to generate the project’s dependency graph (which project.assets.json is) and consume time.

So we have this no-op restore, which simply marks the package restore operation as having taken place, but doesn’t go ahead and do any meaningful work simply because the relevant configuration input hasn’t changed. But what triggers this no-op restore in the first place ? It would have been even more efficient to do nothing, than to invoke this no-op restore.

The answer has to do with the type of project we’re using. And as it was discussed in the “Package Management Formats” section, the .NET Core project is an SDK-style project, which in turn means that “restore also happens automatically when you make changes to a SDK-style project“. We did just install a NuGet package to it, so in a way we did make “changes”. And so we’re bound by the style of the project to do a package restore*. The fact that VS chooses a no-op restore under these conditions is the most efficient path.

Moving on to the build, we also get to see a no-op restore happening before the actual process starts. Here’s a trimmed version of the Build log, showing just the first few lines:

Listing 2 – Visual Studio’s Build output log for our sample project

So we had a no-op restore right after the “full” package restore, and now when starting the build we’re getting another one. And if you look closely, the same exact steps are performed as part of both no-op restores. So what’s triggering the latter ? The answer is that this is how NuGet works by default for a while now: “NuGet now always restores packages before building in VS” at (link here). And yet again, we can ask ourselves why would the build process require a package restore before it starts ? We actually have the answer from the previous section: “Building requires the project.assets.json file, which lists the dependencies of your application. The file is created when dotnet restore is executed. Without the assets file in place, the tooling can’t resolve reference assemblies, which results in errors“. And what generates the project.assets.json file ? A package restore. So this is why a package restore is mandatory to have occurred before a build*. So Visual Studio again takes the optimal path, and – since no actual changes occurred – does a simple no-op restore. How can one test this is so ? Simply disable the second tickbox of the NuGet restore settings in Visual Studio (which controls checking for missing packages), and then delete the project.assets.json file. Try to build the solution, and you’ll run into the message below, which captures exactly what we’ve just discussed:

C:\Program Files\dotnet\sdk\3.1.200\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.targets(194,5): error NETSDK1004: Assets file ‘C:\Users\malbert\source\repos\CmdParserTest\CmdParserTest\obj\project.assets.json’ not found. Run a NuGet package restore to generate this file.

You’ll actually get the same exact message thrown even if creating a blank new .NET Core project and trying to build, provided the same 2nd tickbox is not set (the NuGet restore settings in Visual Studio and their default values were shown back in figure 1 in the section dealing with the post’s assumptions). This also answers the question about the point of doing a package restore for a new project, which we’ve asked in the beginning of this article – the build process needs the dependency graph, which gets created by the package restore.

Why Use the Package Restore in the First Place ?

But why use the package restore feature ? After all, the .NET world managed assemblies way before NuGet became the Microsoft-supported mechanism for sharing code. Adding the required assemblies manually, as “classic” references within Visual Studio would get the required types within reach of our code, and allow us to safely compile. But there are downsides to this method.

Consider a simple C# project, that references one external assembly (.dll). Now assume the project is added to source control, eg to a git repository. Will this referenced .dll make it across to another machine that clones the repo ? Not really, as the referenced .dll will most likely get stored in the output folder, and won’t make it across by default when cloning the repo. The warning thrown right when opening the project on the other machine is:

Warning MSB3245 Could not resolve this reference. Could not locate the assembly “<assembly>”. Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.

We don’t run into the issue above with a referenced NuGet package that’s publicly available. As soon as the project makes it across another machine, the references within the project file (.csproj) will automatically trigger an automatic NuGet package restore, which as we’ve seen gets the package and its assemblies installed, and our project configured accordingly. And you’re not likely to miss the NuGet client at the destination: since NuGet is the official package management tool for the .NET world, and its client and tools are available on the various platforms where .NET is supported, simply opening/building the project on a different machine that doesn’t yet have the dependencies required will result in all of them being automatically retrieved, without any manual steps involved.

Remember the default NuGet Package Restore settings for Visual Studio for Windows, seen previously in figure 1 ? There’s a similar set of preferences for doing package restore on MacOS as well* – and it’s also set to “on” out-of-the-box:

Figure 5 – Visual Studio for Mac NuGet package settings

There’s yet another powerful reason to use the NuGet package restore: get all the underlying dependencies seamlessly deployed. We’ve only discussed in this post the simple example of a project having as dependency a single NuGet package. However this is not the norm – for example the current version of BenchmarkDotNet (0.12.1) relies on 15 NuGet packages; however those packages depend on other packages in turn. Overall there are 50+ NuGet packages that BenchmarkDotNet eventually depends on, with a range of minimum versions supported by each, all adding up to a complex matrix of inter-dependencies. Yet it takes NuGet less than 15 seconds to install everything, including downloading the .nupkg files.

We’ll finish off with some Q&A.

Q&A

Q: I’m trying to find the precise moment when the content of project.assets.json gets updated, but I’m having troubling doing so. Why can’t I find it ?
A: First a temporary file is created, that contains the new content. Then the SetRenameInformationFile function is invoked by devenv.exe to rename the temporary file to project.assets.json. Here’s the temporary file created first, then renamed:

Q: What is the process that writes the updated content of project.assets.json ?
A: It’s devenv.exe. You can see the process name in both snapshots for the previous question.

Q: If I remove the NuGet package’s assembly’s .dll file from the project’s output folder, the application still starts and runs just fine. Why is this so ?A: Copying the NuGet dependencies to the output folder is only done since .NET Core 3.0, as stated here. Why is this so ? Since .NET Core 3.0 the option of generating a runtime-dependent executable as the result of the build operation became available (this link on this very blog talks about it in detail); the whole point is being able to take the output, place it on a machine that already has the correct .NET Core framework and run successfully (keeping of course the same OS family – eg Windows). So aside from the framework itself, there’s nothing else preventing us from taking the content of the output folder and running it somewhere else. Not so with .NET Core pre-3.0, where the application could only be run using dotnet.exe <.dll file>, and the dotnet.exe restore (automatically invoked when running since .NET Core 2.0) required the correct NuGet package (either to be able to download it, or to be already present on the system). With .NET Core 3.0, the requirement for the NuGet package to be present or downloadable is no longer in place, as the assembly .dll is already present in the app’s own output folder. Should the assembly be missing from the app’s folder, then the previous functionality will still kick in and load the NuGet package from the global-packages folder. Here’s an output from VMMap that shows what assembly is mapped by our test application when the CommandLineParser assembly .dll is removed from the app’s folder right before starting the app:

Here’s the assembly loaded when the files are left as-is after the build completes:

Q: Is the content of the .nupkg file simply extracted to the global-packages folder, when installed locally ?
A: They’re slightly different. Here’s how it looks for CommandLineParser 2.7.82 (left: package folder, right: unzipped .nupkg):

Among the differences:

  • <packageId>.<packageVersion>.nupkg.sha512: the SHA of the .nupkg file itself (found only on disk, when deployed to the global packages folder)
  • .nupkg.metadata: contains the hash of the package, excluding the signatures (found only on disk, when deployed to the global packages folder)

Q: What is the workflow of installing a package, from the NuGet consumer perspective ?
A: This is nicely depicted here. The main diagram is shown below; notice that the main topic of this blog post is actually step 4:

Q: How can one see the details within a NuGet package ?
A: To look further into the various attributes of a .nupkg file – whether from local disk or from the nuget.org feed, there is a package explorer app (NuGet Package Explorer) built by a Microsoft employee at https://github.com/NuGetPackageExplorer/NuGetPackageExplorer

Q: What if one manually deletes the obj folder within the project’s folder ? Is the package restore or the build impacted in any way ?

A: Even if the obj folder is deleted, the next time the solution is loaded, the project.assets.json will be recreated (as part of the NuGet restore, along with other files (within the same obj folder) as well. The fact that a NuGet restore is performed can be easily seen from the Package Manager output window in Visual Studio. Rebuilding the solution will also recreate the obj folder. Note that this will only work if both checkboxes in NuGet Package Manager are ticked, as showed back in figure 1 in the Assumptions section.

Q: I’m seeing the CommandLineParser NuGet package currently (as of Apr 2020) targets – among other frameworks – .NET Standard 2.0 (NuGet page here). What does this mean exactly ?
A: .NET Standard 2.0 means both .NET Core (>=2.0) and .NET Framework (>=4.6.1) are supported. You can find details about this here.

Q: There’s a “temp” folder mentioned here. Is it ever used during the package install (+ no-op restore) process in Visual Studio, as seen in this article ?

A: It is, but mostly to put in place some locks, based on the ProcMon analysis of the install that I’ve done.

Q: Are you sure that modifying the .NET Core project is what causes the package restore ?
A: Yes. There’s a reference to this as well here.

Q: Can the NuGet automatic package restore be disabled ?
A: Yes. All you have to do is disable the 2 checkboxes in the VS settings, as described here. Once you do, the process described in this article changes as follows: first, the no-op restore that occurred after the package was installed no longer happens, with a explicit message in the Package Manager output log. Here’s the log after the NuGet package in our project is installed:

Secondly, concerning the second no-op restore – the one that usually showed up before the build – no longer occurs too. In the Build output log you’ll just get to see the actual build process, without any reference whatsoever to any package restore.

Q: I’ve browsed to the various folders corresponding to the various TFM (target framework monikers) underneath the lib folder within the CommandLineParser 2.7.82 package, and all I get to see – along one .xml documentation file – is just one other CommandLine.dll file. As this .dll extension only works with Windows, does it mean that this project cannot be successfully built and ran on another OS (eg Linux, MacOS, etc) ?
A: You’ll be able to run successfully on other OSes. After all, one of the goals of .NET Core is portability. Here’s the quickstart CommandLineParser code running just fine on a MacBook, after the NuGet package was successfully installed using Visual Studio for Mac. Notice the title of the terminal window containing our own app’s .dll :

Q: What controls the verbosity of the Package Manager output window ?
A: The Build verbosity setting in Visual Studio also controls the Package Manager output window level of information:

Q: What is the bitness of the CommandLine.dll assembly within the NuGet package that we’ve just installed ?
A: Since our project is .NET Core 3.1, the NuGet installer went for the assembly image within the netstandard2.0 folder (.NET Standard 2.0 is the only option that supports .NET Core for the current version of the CommandLineParser package, among the subfolders in the package’s lib folder). Using corflags.exe against this .dll file shows that the assembly in question was compiled for AnyCPU (the results for the other possible platforms are depicted here):

Q: Where can I find more information about the 2 package management formats, and about the SDK-style projects ?

A: PackageReference is described here. projects.config is described here. And the various types of SDK style projects are discussed here.

Q: I’ve noticed that even if both NuGet package restore Visual Studio settings are set to disabled, one can manually install packages to a project. Is this normal ?

A: The manual package installation that we’ve performed (in effect a package restore operation, as we’ve seen in the post) is not controlled by the 2 checkboxes in Visual Studio settings – those only refer to missing packages, affecting projects that are already referencing a NuGet package, but the respective package is not yet available on the disk. What we’ve done however was to add a new package to the project, meaning adding a new package reference within our project file.

Q: How do you know that <project_name>.csproj.nuget.dgspec.json is written to ahead of all the other steps described when installing a package ?A: The first hint is seen in the Package Manager output back in the “What Happens ?” section – the file is explicitly mentioned as being written to right near the beginning. Secondly, a lock for writing can be set against the file, and the NuGet installation started from scratch;  doing so will result in an exception thrown during the install process, right near the beginning. The lock can be set using the following code:

FileStream fileStreamLock;
string path = @"C:\Users\malbert\source\repos\CmdParserTest\CmdParserTest\obj\CmdParserTest.csproj.nuget.dgspec.json";
try
{
    Console.WriteLine(String.Format("Trying to get exclusive access to {0}", path));
    // Use FileShare.None as the last parameter instead if there's the need to restrict read access as well from another process
    fileStreamLock = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
    Console.WriteLine("Lock obtained");
}
catch
{
    Console.WriteLine("Cannot obtain lock. Exiting");
    return;
}

Console.WriteLine("Press a key to release the lock...");
Console.ReadLine();

Console.WriteLine("Releasing lock");
fileStreamLock.Dispose();

Q: How can one see the requests for package data going to nuget.org ?
A: You can use Fiddler to see the actual requests and responses that Visual Studio’s NuGet Package Manager gets from nuget.org. Alternatively your can use your favorite REST client (eg Insomnia, Postman, etc) to send the explicit requests that are captured in the Package Manager output log. Both ways are exemplified below:

Q: How can I determine the moment when the .csproj file gets updated, relative to the other steps described in the article’s workflow for installing a NuGet package ? Maybe it’s updated in the very first step !

A: Visual Studio’s Package Manager output window doesn’t really pinpoint exactly the moment the .csproj is updated. However we can use other tools to find out, by probing at various steps in the workflow for the file’s content. Whether it’s in the very beginning can be deducted by preventing or slowing down the retrieval of the NuGet packages themselves. Disabling the Internet connection won’t work, as the install process doesn’t start without it. We can use Fiddler however to insert a delay for requests to nuget.org (the snapshot below); and while these are processed, quickly open the .csproj file and take a look inside (remember that the project file is not committed to disk until it’s saved, so Visual Studio must be used by double-clicking the project name). Doing so will show that the file is not yet updated. So is it updated before project.assets.json is written to or after ? We’ve actually looked at how to set a lock against a file 2 questions above; so creating such a lock against the project.assets.json file will get the whole package restore process to “crash” when required to write to that specific file. Once the exception is thrown in the Package Manager output window (“System.IO.IOException: The process cannot access the file ‘C:\Users\malbert\source\repos\CmdParserTest\CmdParserTest\obj\project.assets.json’ because it is being used by another process”) after the rest of the steps logged so far (hint !), you can open the .csproj file from within Visual Studio – and you’ll get to see that it has already been updated at this point. Just remember that the file lock must be allowed to read at least, otherwise the whole install process fails from the very beginning, as read access is required initially for this file.

Q: I’m running into the error mentioned at the end of the “No-Op Restore” section of the article when trying to build the project, whereby “Assets file project.assets.json not found. Run a NuGet package restore to generate this file.“. How can I force a package restore from within Visual Studio ?
A: Either 1) put back the 2nd NuGet package restore option within the Visual Studio options or 2) open the Package Manager console and issue a dotnet restore. The information here conveys one extra method of fixing the problem involving msbuild.exe.

Q: Why call it NuGet “Package Restore” ?
A: I’m not aware of the historical reason of calling it so. Intuitively though, I’d dare to say it’s because it restores the NuGet packages according to the state specified by the project configuration file. Whether it’s a new project where a package is just installed (which results in the project configuration amended to reference the NuGet package first), or a project cloned to a different machine as part of a git repository (which copies across the project configuration data verbatim), the definition encompasses both cases and results in the same set of actions – namely restoring the packages so that they match the project config.

Q: Is it “project dependency graph” or “package dependency graph” ? I’m finding that even this article quotes both terms.
A: Most likely the right term is “project dependency graph”, and the other one is just a typo left in some of the few docs that still reference it.

Q: I’m worried that a NuGet package that I’ve installed / retrieved has been tampered with. How can I make sure that it’s legit ?
A: Within a NuGet package you’ll find a .signature.p7s file, which contains a signed hash of the package. This can be easily verified using the nuget.exe verify. An example below involving a modified CommandLineParser NuGet package that had its license.md file removed from within the .nupkg file (then repackaged back), and showing a failed check with a NU3008: The package integrity check failed. The StackOverflow thread can be found here.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s