How to set dynamic path to nuget references? - c#

Here is the sample project structure:
{ ProjectA }
{ packages } <-- packages are created here
{ ProjectA }
- ProjectA.csproj <-- references ProjectB and C.
- packages.config
- ProjectA.sln <-- contains all projects: A, B and C.
{ ProjectB }
- ProjectB.csproj
- packages.config
{ ProjectC }
- ProjectC.csproj
- packages.config
*{ packages} <-- *When I manually paste packages here. So one level above ProjectB.csproj file, then ProjectB compiles.
ProjectA solution has all three projects: A, B and C. ProjectA reference ProjectB and ProjectC.
When I compile ProjectA (projects B and C are compiled as well), all nuget packages are downloaded into {packages} folder on the same level as solution file. The problem is that ProjectB is not compiling. Yes... only ProejctB. I'm not even gonna investigate why only one project compiles although their configuration is exactly the same. Anyway...
In both ProjectB and C, when I expand References dlls from nuget are seen as they were missing (with the yellow rectangle). Somehow ProjectC compiles anyway, but ProjectB doesn't. The errors says it can't find the reference which is clearly in the packages folder.
My question is, how do I program/configure that sentance (psuedo code):
"Dear ProejctB, Please look for the references in the package folder generated on the same level as the solution file. The solution file, which is trying to compile you right now. Thank you"
PS. So technically, the path to the dll (reference) will be kinda dynamic. It will change depending on which solution file is opening/compiling the project. Is it possible?

The easiest way to fix it is by setting HintPath to:
<HintPath>$(SolutionDir)\packages\...
in .csproj files of ProjectB and ProjectC. It literally means: "look for the references in the package folder generated on the same level as the solution file. The solution file, which is trying to compile you right now"
This problem was reported multiple times. I believe it was fixed here. There is also NuGetReferenceHintPathRewrite, but I didn't test it.

Since packages.config is slowly becoming deprecated, you could migrate your projects from packages.config to ProjectReference, where the NuGet packages are specified inside the csproj file and a shared global location is used to store the packages (and there aren't any references with HintPath that would need changing).
In VS 2017 version 15.7, there will be an option to migrate in the context menu of the references node (already available in the preview):
PackageReference is already supported in VS 2017 since around 15.1 or 15.2, only the migration tool is in preview.
For new projects, VS 2017 (current version!) you can already select the default package reference style and allow for choosing it for new projects:

Nuget 3.x has packages.config concept and in this package name & version are mentioned at 2 place (In package.config and in .csproj file)
Reference in package config should be like this:
<package id="NewtonsoftJson" version="9.0.1" targetFramework="net46" />
Hint path in csproj should be like this:
<HintPath>..\packages\NewtonsoftJson.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
Here "..\packages" says go one level up(means at solution level) and look for "packages" folder.
You should verify that hint path is exists or not. and Package version should be same (9.0.1) in both the files(package.config and .csproj)
As your Porject C compiles successful, it seems some issue in the packages which is used by only ProjectB.
If you are still facing issue, please provide below detail for further analysis.
"package config"
"ProjectB.csproj"
msbuild compilation log, to know that in which package you
are facing issue.

Related

Nuget package not found after restore VS 2019 16.5.0

I've been fighting with nuget all morning, trying to get a solution that builds in the UI AND from the command line. Here's the latest problem, which I haven't made any headway on:
I'm running nuget restore on the solution file. This works, all referenced packages are restored - I can see the files in the /packages folder under the solution folder.
I'm building with devenv command line - I have to because this solution contains project types that msbuild doesn't support.
The first project that references a nuget package, fails to compile with ...cs(3,7,3,17): error CS0246: The type or namespace name 'Newtonsoft' could not be found (are you missing a using directive or an assembly reference?)
The project builds (and rebuilds, and rebuilds with the package folder cleared out) just fine in the UI, but the command line build isn't seeing the restored packages.
The build that's failing is in a CLEAN folder on the same computer where I'm doing the UI build, so it's get from source control, nuget restore, devenv build.
Things I've tried
Looking for bad hint paths in the project file (saw this in another question/answer). These references don't appear in the project file at all - trying to add them produces an error saying that the reference can't be added because it's already added automatically by the build system.
Verifying that files do exist after restore.
Doing the same steps from a command line in the SAME folder where the UI is building. This works fine.
What am I missing? this shouldn't be so hard..
UPDATE: The solution consists of 14 projects: 9 C# class libraries, 2 c# applications, 1 reporting services project and 2 WiX installer projects. All C# projects target Net472, NOT Core. The key part of the solution structure appears to be:
Project A references
Newtonsoft.Json via nuget
Project B references
Project A
Newtonsoft.Json via nuget
Other packages via nuget
During build, project B fails to compile due to the lack of a reference to Newtonsoft.Json. Project A and all of the other nuget packages are supplied to the compier as references. Again, all nuget packages are in fact restored - Project A finds Newtonsoft.Json, project B does not.
In the detailed msbuild log output, this is the only mention of Newtonsoft.Json in the build of project 10 (Project B above):
10> Dependency "Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed".
10> Resolved file path is "...ProjectA\bin\Release\Newtonsoft.Json.dll".
10> Reference found at search path location "...ProjectA\bin\Release".
10> For SearchPath "...ProjectA\bin\Release".
10> Considered "...ProjectA\bin\Release\Newtonsoft.Json.winmd", but it didn't exist.
10> Required by "...ProjectA\bin\Release\ProjectA.dll".
10> Required by "C:\...ProjectA2\bin\Release\ProjectA2.dll".
10> Found related file "...ProjectA\bin\Release\Newtonsoft.Json.xml".
10> The ImageRuntimeVersion for this reference is "v4.0.30319".
(Folder and project names have been obscured)
A couple things going on here, finally got a solution that works. Why this built in the IDE is anyone's guess - it's adding some extra secret sauce to make things work (more than just the automatic nuget restore).
I tried changing all projects to use PackageRef instead of packages.config. That caused nuget restore to fail with an obscure msbuild error that I didn't try to diagnose.
I noticed that SOME of the nuget packages were referenced in the .csproj files with ordinary Reference elements, but some of them were not (specifically, Newtonsoft.Json in "Project B" - and some others that I hadn't noticed due to B failing).
To correct the situation:
Remove ALL use of PackageRef elements - change back to packages.config in ALL projects
Make sure the each of the nuget -provided DLLs is referenced in the .csproj files. You have to do this by editing the csproj file by hand - the IDE won't let you add the missing references.
I'm assuming that this is a temporary situation and that in the long run the solution will be to use PackageReference everywhere.
you already checked the files app.config and packages.config, and the dotnet framework version?
Nuget package not found after restore VS 2019 16.5.0
devenv /build command line does not have the job to restore nuget packages by default. However, there are such options in VS IDE so that it will restore packages first and then build. But these do not work in command line.See this similar issue.
But you still want to use devenv to build your project and since you use a framework project with packages.config, I suggest you could use nuget.exe.See this.You can try these:
1) download nuget.exe from this link and then configure its local address to PATH in the environment variable and make sure that you can call nuget from CMD.
2) open vs command prompt, cd the path of the solution and then type this first:
nuget restore
Then you can type your devenv command line and I am sure that this will execute without any errors.
devenv xxxx.sln /rebuild
Besides,you can add a custom target in any xxx.csproj file of your solution like this:
<Target Name="restoresolution" BeforeTargets="BeforeBuild">
<PropertyGroup>
<nugetpath>C:\tools</nugetpath> /////the local path of the nuget.exe
</PropertyGroup>
<ItemGroup>
<slns Include="$(MSBuildProjectDirectory)\..\**\*.sln" />
</ItemGroup>
<Exec command="$(nugetpath)\nuget restore %(slns.Identity)" />
</Target>
Then you can run devenv xxxx.sln /rebuild directly.

Managing Nuget packages for C# project present in multiple solutions

I am now on the phase of refactoring madness of a big project which has a lot of legacy and unstable modules. I've decided to split the solution that currently has ALL projects (so around 20 and there will be more because of unit test projects that would surely come in next months) chained in it to make it more independent and granular.
With this approach there are modules e.g. API clients that needs to be either referenced or added in multiple solutions.
The problem is that Nuget packages are getting restored only on the solution that it was added originally for the first time. So the simplest example:
Solution A:
------ ProjectA
------ APIClient
Solution B:
------ ProjectB
------ APIClient
Since we are not including packages folder it causes problems with Nuget packages:
Clone the repo.
Open Solution B, build it and restore the Nugets for solution.
Errors with packages of ClientAPI in Solution B.
Go to Solution A build it and restore the Nugets for solution
Get back to Solution B.
Nugets are restored for ClientAPI in Solution B and errors are gone.
Is there a way to somehow:
Make the project using different path for each solution?
Maybe chain solutions in build to make Solution A always build with Solution B? But that sounds like loosing some benefits of splitting this one big solution to smaller ones.
Use any other approach to make it more granular and yet do not suffer problems with the necessity of rebuilding all? I've heard of private Nuget feeds, would that be an answer to this problem if my config allows that?
My config:
VCS: TFS with TFVC
IDE: Visual Studio Proffesional 2017
Default package management format: Packages.config
Managing Nuget packages for C# project present in multiple solutions
Thanks for you reply. I have reproduced this issue with two solutions, SolutionA with Project APIClient. And SolutionB, add the existing project APIClient in the SolutionA to the SolutionB.
Then if we restore the nuget package on the SolutionB, package in the project APIClient in the SolutionB will be restored in the \packages folder in the SolutionB folder by default rather than in the SolutionA folder.
In this case, the project APIClient still missing the .dll reference in the SolutionB, you still have to go to SolutionA and restore the nuget packages. That the reason why you got that issue.
To resolve this issue, you could add a NuGet.Config file next to the SolutionA and SolutionB with the following content:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="repositoryPath" value="C:\Packages" />
</config>
</configuration>
So, the \packages folder not related to the solution file.
Besides, if you are interested, you can try to convert the packages.config to the packagereference for the project APIClient, with this setting, the nuget package will be saved in the global packages folder, C:\Users\<UserName>\.nuget\packages.
Hope this helps.
Why do you not add package in the solution B ?
What package mode do you use ?
If you use "Package reference" mode, you must add package information in csproj of solution B.
If you use "Package config" mode, you must add package information in package.config file of solution B.

Multi-project setup with Nuget Packages

I have a visual studio solution that has two sub-projects, and these sub-project's use the same nuget packages. I have many years experience with C++ projects, but I am still relatively new to the .net world and nuget packages. I'm trying to achieve the following goals simultaneously.
Have my Master solution file in the projects root folder (see directory structure below)
Have each sub-project (including the .csproj file) contained in their own sub folders
Have only one location that contains a list of all of the packages. I don't like having copies of the same packages.config file in each sub-folder. Would like to have just one at say the Master.sln file level since all of the projects use the same packages and I want to ensure they use the same versions of the same packages.
I also noticed that the .csproj files end up containing a copy of what is in the packages.config file. Is there any way to have the packages list be only in one place without copies? Like ONLY in the packages.config file and not in the .csproj file?
Here is my project directory structure
{projects root}
Master.sln
packages.config {is it possible for this file to be at this level}
Proj1
Proj1.sln {do not want solution at this level}
Proj1.csproj
Program.cs
packages.config {do not want at this level}
Proj2
Proj2.sln {do not want solution at this level}
Proj2.csproj
Program.cs
packages.config {do not want at this level}
At the moment, if I compile either of the Proj1.sln or Proj2.sln files in VisualStudio the "packages" folder is created and the project compile correctly. However if I open the Master.sln (which contains the two sub projects) and compile, then the "packages" folder is created at the same level as the Master.sln file, but the projects don't build, I'm assuming because they can't find the packages.
Any help on this would be appreciated.
Multi-project setup with Nuget Packages
I am afraid you have to copy of the same packages.config file in each sub-folder, that because NuGet team deprecated solution level packages in NuGet 3.0:
https://github.com/NuGet/Home/issues/522
And the default nuget version for Visual Studio 2017 is 4.0 and above.
So, you could not have just one packages.config at say the Master.sln file level.

How .Net/VisualStudio handles having projects dependencies each with different nuget target for same nuget packages

I have a web service project in .Net 4.6.1 let's call it Project X, which has 2 project references(both class libs), let's call them Project A and B.
A has this in packages.config:
<package id="NLog" version="4.5.3" targetFramework="net35" />
While X and B has this in their packages.config:
<package id="NLog" version="4.5.3" targetFramework="net461" />
Now when I ran this command in project X's solution:
Update-Package –reinstall nlog -ignoreDependencies
And further, I build X's solution, and then run X.
Now i want to know will code flows in project X using project A or B work fine for any nlog based logging they have inside code of A or B?
If answering this will need more explanation then request to please share any reference link which will help me understand this kind of setup and nuget target resolution for client app referring dependencies with a different nuget target for given nuget package.
Thanks
Edit:
IMHO The suggested question as this being duplicate of is not valid as that talks about scenarios when solution has projects with different nuget versions, which is not my case.
As my question is about both projects having same nuget version but different targetFramework.
Like for A it is targetFramework="net35",
while for B and X it is targetFramework="net461".
But all 3 projects A,B and X using same version i.e. 4.5.3.
Sorry the config i had earlier given showed versions as different but that wasn't my intention to talk about hence have edited to make version same.
So question is again how a project referring 2/more projects dependencies each of those using same version but different targetFramework gets addressed during build/execution of client app i.e. X here.
Is it like X will have nuget dll with highest targetFramework picked up and copied to it's bin? if not what happens then?
Is it like X will have nuget dll with highest targetFramework picked up and copied to it's bin? if not what happens then?
The project X will have nuget .Net 461 dll picked up and copied to it's bin, but not because of the highest targetFramework. That because the project X reference the nuget package NLog directly with target framework 461.
You can change MSBuild project build output verbosity to Normal or above, Tools->Options->Projects and Solutions->Build and Run->MSBuild project build output verbosity. In the output window, you can notice that the NLog.dll under the net45 copy to the project x bin folder:
And the NLog.dll under the net35 copy to the project A bin folder:
To check more info about this issue, I recommend you can check following thread:
MSBuild doesn't copy references (DLL files) if using project dependencies in solution
Hope this helps.

How does 'DNU RESTORE' determine if a dependency is a project reference rather than a package reference?

I'm getting my knickers in a twist with 'project' versus 'package' (ie Nuget package) references in asp.net 5.0. I'd really like for someone to explain a bit more fully the way references are pulled in in asp.net 5.0. How does a 'dnu restore' determine if something is a project reference rather than a package reference?
I had thought that a reference would be pulled in as a project if the projects were in the same directory, but this is clearly not the whole story. It does appear that you can have a deeper directory nesting and still pick up the project reference.
Here is an outline of my common project structure:
I've got a set of projects, some of which reference one another. There are libraries called TextHelpers and MathHelpers and a project called MainProject. The libraries live in a folder called Libraries, and the MainProject lives in a folder called Tools. This separation is necessary as Libraries and Tools belong to different Git repos:
Root/Libraries/TextHelpers.Project1 - version 1.0.0-*
Root/Libraries/TextHelpers.Project2 - version 1.0.0-*
Root/Libraries/MathHelpers.Project1 - version 1.0.0-*
Root/Libraries/MathHelpers.Project2 - version 1.0.0-*
Root/Tools/MainProject - version 1.0.0-*
Usually MainProject references the libraries as Nuget packages from a private Nuget repository (just a folder on the file system) which serves the libraries.
While I'm building MainProject, however, sometimes I need to make a change to one of the library projects, or sometimes I'd like to step into the files without using a Nuget symbol server. For this reason, I'd like to switch to referencing the (live) projects rather than from the (static) Nuget packages. How would I do this?
I've discovered this much so far: if I have a global.json file, a 'dnu restore' creates a project.lock.json with 'project' rather than 'package' references. Is this the whole story?
dnu and dnx look in the following folders:
The folder where the current project is (that means the parent folder of the folder containing the project.json of the current project). E.g. if you have repo/src/project1/project.json it will look in repo/src
Any other folder included in global.json
Then the algorithm is really naive: if it finds a folder with the name matching the package in any the folders mentioned above it will assume those are the sources for that package.
For example, if you have
src/P1/project.json
src/System.Collections/project.json
and in src/P1/project.json you have a reference to System.Collections, it will use src/System.Collection instead of the NuGet package System.Collections. Projects take precedence over packages.
Caveats:
Since the algoritm looks in the current folder and everything in global.json you might be able to reference some projects from one folder but not another. If in my previous example you'd add a test/T1/project.json project but src is not in global.json then the projects in src will reference System.Collections the project while T1 will reference the package (installed in the global packages folder).
There's no verification to see if the project reference is actually that package. If the name matches, it's a match. So an empty project could replace any package.
If you have multiple project with the same name you can get in trouble.
Hope this helps and answers your question.
Side note: with dotnet (the tool replacing dnx) you can specify for every reference if you want the project or the package to have higher priority.

Categories