blog post image
Andrew Lock avatar

Andrew Lock

~5 min read

Use project.lock.json to troubleshoot dotnet restore problems

This is a quick post about how to troubleshoot problems using dotnet restore, where it is fails to restore packages due to an error in your project.json. I ran into it the other day and it caused me far too much frustration considering how simple the problem was!

I was working on an ASP.NET Core website that had been created using dotnet new and had been manually updated. When I started working on it, I ran dotnet restore to restore all the packages from NuGet. Most packages restored correctly, however near the bottom of the log there was the following error message:

info : Committing restore...
log  : Writing lock file to disk. Path: /Users/Sock/Documents/Projects/TestWebsite/src/TestWebsite/project.lock.json
log  : /Users/Sock/Documents/Projects/TestWebsite/src/TestWebsite/project.json
log  : Restore failed in 4087ms.

Errors in /Users/Sock/Documents/Projects/TestWebsite/src/TestWebsite/project.json
    Package Microsoft.DotNet.ProjectModel 1.0.0-rc3-002886 is not compatible with netcoreapp1.0 (.NETCoreApp,Version=v1.0). Package Microsoft.DotNet.ProjectModel 1.0.0-rc3-002886 supports:
      - net451 (.NETFramework,Version=v4.5.1)
      - netstandard1.6 (.NETStandard,Version=v1.6)
    One or more packages are incompatible with .NETCoreApp,Version=v1.0.

My first thought was that there was an incorrect reference to Microsoft.DotNet.ProjectModel in the project.json. This was an RC2 app, and there was clearly a reference to 1.0.0-rc3-002886 in the log which what was failing to restore, however on inspection, there was no explicit reference to it in the project.json anywhere. That meant it had to be being pulled in as a dependency of another package, I just needed to figure out where. This is the file I was working with:

{
  "buildOptions": {
    "emitEntryPoint": true
  },
  "dependencies": {
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.0-rc2-final"
  },
  "frameworks": {
    "net451": {},
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "version": "1.0.0-rc2-3002702",
          "type": "platform"
        }
      },
      "imports": [
        "dnxcore50"
      ]
    }
  },
  "publishOptions": {
    "include": [
      "web.config"
    ]
  },
  "tools": {
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": {
      "version": "1.0.0-*",
      "imports": "portable-net45+wp80+win8+wpa81+dnxcore50"
    }
  },
  "scripts": {
    "postpublish": "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%"
  }
}

Now, you may spot the issue immediately. Looking at it now it seems obvious, but at the time I was tearing my hair out trying to work out what was going on.

I checked all the references in the dependencies section, but they all point to *-rc2-final which is correct. Then I checked all the dependencies under each frameworks node - there's only one in this case, Microsoft.NETCore.App - but again, all looked good.

Trying a different tack, I searched the dotnet restore log for 'ProjectModel', but there was only the existing error message we had, no indication of what the parent dependency was or anything.

It was then I had a mini-revelation - the project.lock.json file! Anyone working on ASP.NET Core will probably have seen this file, but as it's just used by the NuGet infrastructure behind the scenes, you may not have even looked in it. This file helps to manage all the package dependencies for a project, and the local location of all the files.

A quick search in project.lock.json, for 'ProjectModel', and the culprit instantly revealed itslef:

{
  ...
  "tools": {
    ".NETCoreApp,Version=v1.0": {
      "Microsoft.AspNetCore.Server.IISIntegration.Tools/1.0.0-preview2-21125": {
        "type": "package",
        "dependencies": {
          "Microsoft.DotNet.ProjectModel": "1.0.0-rc3-002886",
          "Microsoft.Extensions.CommandLineUtils": "1.0.0-rc3-21125",
          "Microsoft.NETCore.App": "1.0.0-rc3-004312",
          "System.Diagnostics.Process": "4.1.0-rc3-24127-00"
        },
        "compile": {
          "lib/netcoreapp1.0/dotnet-publish-iis.dll": {}
        },
        "runtime": {
          "lib/netcoreapp1.0/dotnet-publish-iis.dll": {}
        }
      }
    }
  },
 ...
}

So the "Microsoft.DotNet.ProjectModel": "1.0.0-rc3-002886" dependency was being pulled in by the package Microsoft.AspNetCore.Server.IISIntegration.Tools. Looking back at the project.json, you can see that the version number I used was 1.0.0-*. I needed version 1.0.0-preview1-final, but this will pull the highest version of a 1.0.0 package it can find in the configured feeds.

I had been playing with a lot of the cutting edge stuff up to the RC2 release, and so I had two feeds configured in my NuGet.config file

The first of those feeds is the normal NuGet feed, but the second is a CI MyGet feed, containing the latest packages from the CI process. As I had used the open-ended version number, NuGet looked in both feeds for the highest 1.0.0 version package, and found version 1.0.0-preview2-21125 of Microsoft.AspNetCore.Server.IISIntegration.Tools on MyGet and preferentially pulled in that package. That has a dependency on Microsoft.DotNet.ProjectModel version 1.0.0-rc3-002886, which unfortunately requires netstandard1.6, where netcoreapp1.0 only supports netstandard1.5, hence the error.

So how to fix it? Well, there are two pretty easy options:

  1. Remove the MyGet feed from NuGet.config
  2. Specify a specific version in project.json

If you remove the MyGet feed, then dotnet restore will only use packages from NuGet. The highest version of IISIntegration.Tools on there is 1.0.0-preview1-final, which is the one I needed.

Alternatively, you can specify the specific version of the package you need in your project.json, and then you know (almost) which package you'll be getting! Unless you really do want everything to be pulling the very latest packages, I'd suggest that this is the option you should plump for preferentially (though of course, you could always remove the other feed if you are not using it).

So, for completion sake, this is the final project.json, with the explicit dependency version listed in the tools section, which now completes successfully with a call to dotnet restore:

{
  "buildOptions": {
    "emitEntryPoint": true
  },
  "dependencies": {
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.Kestrel.Https": "1.0.0-rc2-final"
  },
  "frameworks": {
    "net451": {},
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "version": "1.0.0-rc2-3002702",
          "type": "platform"
        }
      },
      "imports": [
        "dnxcore50"
      ]
    }
  },
  "publishOptions": {
    "include": [
      "web.config"
    ]
  },
  "tools": {
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": "portable-net45+wp80+win8+wpa81+dnxcore50"
    }
  },
  "scripts": {
    "postpublish": "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%"
  }
}

Summary

So, in conclusion, if you are having trouble with dotnet restore, keep in mind the following points:

  1. Use specific versions of dependencies, at least when using CI build feeds that are likely to be in a high state of flux and can lead to the situation I found.
  2. Don't forget to look everywhere dependencies are listed in project.json - dependencies, frameworks/dependencies and tools
  3. Check which feeds dotnet restore is using - it lists them after you run a restore, and which files it used to find the feeds.
  4. If all else fails, take a look in project.lock.json and work out what's going on!
Andrew Lock | .Net Escapades
Want an email when
there's new posts?