C# Library project being used in multiple projects - c#

I have a library project used in multiple applications. Let's call this Library1. Library1 has its ownNuGet package dependencies. When I setup a project, ProjectA, using Library1, it specified a HintPath for each .dll that Library1 depended on. Let's say this HintPath was "..\etc.dll".
I now have Library2, which depends on Library1, and ProjectB that depends on Library2 (and Library1). I have a hierarchy like this:
ProjectB
--Library2
----Library1
But the other project uses Library1 directly, like so:
ProjectA
--Library1
When opening either ProjectB, the packages are being resolved in "ProjectB\packages", which is two folders up from the library depending on it, meaning it should be looking in "....\etc.dll" rather than "..\etc.dll" specified in the HintPath.
Is there a way I can specify a HintPath depending on the parent project, or any kind of workaround that will allow this to work without me having to manually change each of my .dll reference paths? Perhaps a file I could add to the parent project?

You can create a NuGet.Config file can specify the repositoryPath which allows you to override the default location where NuGet packages are downloaded to for the project.
<configuration>
<config>
<add key="repositorypath" value="Packages" />
</config>
</configuration>
The repositoryPath is relative to the NuGet.Config file's directory.
NuGet will look for this file based on the solution you open so you would need to place it so that either one or all of your solution's use this file. A simple way is to put it in a directory that is a parent of both solutions but you can add it for each solution or just the one.
If the solution is in c:\a\b\c then NuGet will look for the file in these locations in the order specified, finally falling back to the one in your user profile.
c:\a\b\c.nuget\nuget.config
c:\a\b\c\nuget.config
c:\a\b\nuget.config
c:\a\nuget.config
c:\nuget.config
After setting this up you may need to reinstall the NuGet packages so the correct hintPaths are added to your project.

Related

Copy a file to other project using Nuget package

I am trying to get my head around how Nuget works when creating packages and must admit that I cannot grasp it.
To generalize my task, it is to include a file in the Nuget package, create that Nuget package and when installed as a dependency in other project, the file is shown there in the project structure or somewhere to be manipulated with.
This file is a central .DotSettings file which would then propagate to all the C# repositories and solutions.
Where I am now
I have a .dll project, I have my content folder where the file is and I specify that within the .csproj file as such:
<ItemGroup>
<Content Pack="True"
PackagePath="\"
Include="content\test.DotSettings" />
However, when this is Nuget packed and this dependency is installed in another project, I cannot see this file in the project/dependencies/packages folder, where I would like it to be (and I suppose it should be there, right?)
The workaround I have now is that I reference this file from within the users/nuget/packages folder, however, I do not fancy this solution that much.
So, the main question:
Is there a way to copy the file so that when the dep is installed, the file is shown at the top level project folder structure? if so, what am I missing?
misc questions:
As I understood it, I can write my own .nuspec file and specify it there somehow, but when I did that, at build it always overrides it with its own autogenerated .nuspec file. Is this a wrong way to take at all and should I not create my own .nuspec?
What about the .target and .props file, what is that for and do I need to bother with those in my task or not at all? From what I understood, I should be good with my .csproj file and be able to define it all within it.
TIA!

Custom Nuget package shows missing dependency error

I have two class libraries in a single solution (.NET Core). One of them (cl1) is a main library and it depends on another library (cl2). I have added a .nuspec file with the required metadata only (no dependencies, no files) for the cl1 project in the project folder (same location of .csproj file) and I have set GeneratePackageOnBuild propery to true.
Whenever I am building the class library (cl1), the .nupkg is created automatically in the debug/release folder.
When I check the generated .nupkg file, I am see two strange things:
The generated .nuspec file is different than what I have added in the project folder
cl2 is mentioned as a dependency in the newely generated .nuspec file, but the DLL for cl2 is not included in the lib folder of the .nupkg. So, whenever I consume this package in another solution, I am getting the error No packages exist with this id in source(s) for the cl2.
I have surfed in internet, but was not able to find a proper solution for the above error.
And I have added a .nuspec file [...] in the project folder(same location of .csproj file)
You have to specify the path to your own NuSpec file in the .csproj using the NuspecFile tag, otherwise it will be ignored and the package will be created with the metadata from the .csproj file instead, see reference. You need to use either a relative or an absolute path to the file, for example:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<NuspecFile>cl1.nuspec</NuspecFile>
</PropertyGroup>
</Project>
The generated .nuspec file is different than what I have added in the project folder
As already stated, your NuSpec file is probably not included. However, even if it is, there can be differences, because some information, e.g. source file locations are unnecessary and the target locations are in most cases given by the internal package file structure itself, so it is not there because it is redundant.
cl2 is mentioned as a dependency in the newely generated .nuspec file, but the dll for the cl2 is not included in the lib folder of the .nupkg. So, whenever I consume this nupkg in other solution, I am getting error " No packages exist with this id in source(s)" for the cl2.
Dependencies are meant for packages. So when NuGet restores the package it searches for other packages that this package depends on, here cl2, but there is none, hence the error. When packing a project, referenced projects are not included in the package. That is an open issue and there are workarounds that you can try.
The most reliable, but inconvenient solutions are to avoid the issue at all.
Only use a single project, everything will be included in the package
Pack each project on its own and use the generated package instead of the referenced project

Best way to maintain .NET project dependencies and updated binaries in large multi solution application

I know this is a vague question, but I spent hours of searching and couldn't find a solution.
I have a class library project - A
I have another class library project - B
B has a reference to A
I have another console application project - C
C has a references to both A and B.
Now, what happens is:
A's code is being updated. A is being rebuilt.
Now B needs to get that new A binary, and then B needs to be rebuilt.
Now C needs to get that new A binary AND that new B binary.
Now imagine that I maintain several projects, each in its own solution, and that chain of dependencies is longer.
What is the best way to maintain all those binaries and keep them up to date?
How can I make sure that C always has the most up-to-date versions of A and B?
One solution I found is to create a nuget server in which there will be a nuget package for A and for B,
and when A or B's binaries are updated, new nuget packages will be rebuilt, and because C will use these nuget packages, it will always have the most up-to-date binary versions of A and B.
We work with SVN but I don't see how it can help managing dependencies between projects.
Any suggestion/direction will be very helpful
Thanks
The dependency chain you are describing is handled differently in different Visual Studio versions what depends on type of the project you are using. In old C# project version (pre VS 2017) when project reference is used (it is displayed in meta folder of the project as a references) and Visual Studio is unable to track and copy dependencies of project reference. This is why it was necessary to have your project C to reference both project A and project B.
Whereas in new format of csproj in Visual Studio 2017 when dependencies are used instead of references MSBuild is capable of traversing whole dependency tree and will handle properly situation where your project C references only project B which references project A. All required by application assemblies will be built and copied into output directory of project C.
In both cases there is no need to use NuGet server.
Now imagine that I maintain several projects, each in its own solution, and that chain of dependencies is longer.
What is the best way to maintain all those binaries and keep them up to date? How can I make sure that C always has the most up-to-date versions of A and B?
Once you have broken your dependency chain handled easily by MSBuild by separating your projects into separate solutions your build system lands in unsupported directly by Visual Studio territory. For pure managed .NET applications I would avoid that at any cost. For examples of building large, complex managed projects have a look at Roslyn compiler.
To solve that problem without using NuGet server at all - and it is my recommendation - you can create tree of dependencies spanning through solution boundaries by referencing directly from projects of one solution their dependencies (projects) from another solution. This will make your build much easier to manage (and it is particularly important for CI and DevOps solutions) and expand.
If you cannot modify current project/solution structure just create a new one as an overlay over existing project/solution structure and configure it properly. You will end up with one solution/project system which is perhaps easier to work with during code editing and testing and a second one which spans all maintained projects which is better suited for building whole application.
If the above option is not working just modify your all projects to output all final artifacts to one common output directory (move bin of every project to common top level bin directory, you may want to move obj intermediate directories as well).
If the choice of the NuGet server is a must the easiest way to do it it is to use common output directory and use NuGet.config in all projects consuming dependent projects by pointing them to new package source.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- NOTE: Leave this file here and keep it in sync with list in dir.props. -->
<!-- The command-line doesn't need it, but the IDE does. -->
<packageSources>
<clear/>
<add key="private NuGet" value="file:///e:/src/myproject/.nuget" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<config>
<add key="repositoryPath" value="..\packages" />
</config>
<packageRestore>
<!-- Automated package restore in VS does not work at this time with
this project and it causes build failures in VS. Disable it. -->
<add key="automatic" value="false" />
</packageRestore>
</configuration>
In the above NuGet.config file:///e:/src/myproject/.nuget points to main directory of your NuGet server (simple file system directory) where all .nupkg(s) are stored - it will require setting common output directory for nupkg(es) from all projects. This will not work on network shares yet as this nuget.client feature is under development right now. See nuget.clinet pull request which is still open at the time of writing Adding support for Network Share Hosted Package Source and compatability with generic build tools.
If you want to use full blown NuGet server first I would seriously consider using it as an external service i.e. myget.org. They have free plan if your packages can be public or paid plans if you want to keep your packages private.
Finally if you want to use your very own NuGet server go to NuGet project site and choose one you would prefer. NuGetGallery - equivalent to current nuget web site or smaller one NuGet.Server and follow installation instrcutions.
I have my own local NuGet repository so I think that my method should work on some shared network disk where you will have newest nuget packages.
First you need to install nuget standalone. You will download it from official website and you will have nuget.exe. I suggest adding it to the folder which will be added to system PATH environment variable. By doind this it will be accessible from your computer everywhere just by typing 'nuget'.
Now you need to get to the folder where is your .csproj file from your library.
Initialize your .nuspec file by typing nuget nuspec
You should have file [project_name].nuspec. Open it and add this line as second line of file after <xml> tag. It's weird that nuspec do not add this automatically.
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
authors tag and description tag on my computer could not be fetched from .csproj file so i needed to input values there manually.
I defined post-build event to my .csproj file as this:
nuget.exe pack $(ProjectPath) -IncludeReferencedProjects -OutputDirectory "D:\programowanie\nugetPackages"
powershell.exe D:\programowanie\nugetPackages\install.ps1
First command packs your project files into .nupkg files and send them directly to nugetPackages folder on disk D (there you could use some shared network drive).
-IncludeReferencedProjects description from specification:
Indicates that the built package should include referenced projects either as dependencies or as part of the package. If a referenced project has a corresponding .nuspec file that has the same name as the project, then that referenced project is added as a dependency. Otherwise, the referenced project is added as part of the package.
Install.ps1 contents:
nuget init D:\programowanie\nugetPackages D:\programowanie\nugetServer\
It creates folder structure in NugetServer directory for my packages and copy .nupkg files to those folders.
Now you need to add new package source inside your viual studio. You just enter path to the D:\programowanie\nugetServer\ in my case and name. You do it here:
I created solution for my .csproj library. I do not know if I done it by accident or is it really needed.
It was my first approach to having my own nuget package folder to maintain dependencies. I think that my solution is still not very good and lack a lot of automation. If you would like to have more info on the topic i suggest to stick with oficcial guidelines.
I do not have so complicated dependencies as in your case. But maybe creating solution which includes all of those libraries and definining good build order will enable to automatically build and deploy them to nuget server with my method.

Nuget prevent generating packages folder in solution

I hava a solution which contains two Project.
/Solution
.sln
.nuget.config
/ProjectA
.csproj
.nuspec
/ProejctB
.csproj
.nuspec
When I add a dependency ProjectA via nuget.
Project structure is become something like this:
/Solution
.sln
nuget.config
/packages
.nupkg
/lib
.dll
/ProjectA
.csproj
.nuspec
packages.config
/ProejctB
.csproj
.nuspec
Basically, Visual Studio create a packages.config file and put dependency there. And, dependency is added to /packages folder. Also, .csproj content changes.(A Reference added which has a relative path to dll inside /packages folder.)
I have two question.
1- Inside nuget.config file I have put following line. So I expect nuget will use default local repository instead of creating a /packages folder in solution. How can I prevent creation of a /packages folder in solution. Instead I would like to use "%userprofile%\.nuget\packages".
<add key="globalPackagesFolder" value="%userprofile%\.nuget\packages" />
2- When I add the dependency as nuget package. Still .csprj file is changed and dll's related path is added there as a reference with relative path. Is it ok? Isn't auto generated packages.config enough. Why also this file is updated.
1- Inside nuget.config file I have put following line. So I expect nuget will use default local repository instead of creating a /packages folder in solution. How can I prevent creation of a /packages folder in solution. Instead I would like to use "%userprofile%.nuget\packages".
You should use below settings in the NuGet.Config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<config>
<add key="repositoryPath" value="%userprofile%\.nuget\packages" />
</config>
</configuration>
You can check the test result from below screenshot, the packages is add to the "%userprofile%\.nuget\packages" folder:
Note: Take care the uppercase and lowercase for the file name and restart the VS after add it.
2- When I add the dependency as nuget package. Still .csprj file is
changed and dll's related path is added there as a reference with
relative path. Is it ok? Isn't auto generated packages.config enough.
Why also this file is updated.
Not, because the Package.config and the HintPath in the .csproj file have different role. The Package.config is used by NuGet to manage the Packages, and the HintPath in the .csproj is used by the Visual Studio reference the path of the Dll file. Both files are need to be updated, otherwise Visual Studio will throw the error "Can not find the reference..."

Build, pack up and deploy for multiple platform targets

I'm looking forward to setup an environment/configuration that allows me to build and deploy a custom library for multiple platforms / targets, such as build configurations and/or .NET framework versions. For this, I've laid out the following structure:
MyProject.sln
src\
File1.cs
File2.Net30.cs
MyProject.Net40.csproj
MyProject.Net30.csproj
MyProject.Net45.csproj
All project files are included in the solutions and built at once. Each project contains the source files for the framework it targets and/or all files where as different .NET versions are compiled conditionally (using compiler directives, e.g. NET35, NET34_OR_GREATER). Additionally, each project file contains the following msbuild directives:
<OutputPath>bin\$(Configuration)\$(Platform)\$(TargetFrameworkVersion)\$(TargetFrameworkIdentifier)\</OutputPath>
<BaseIntermediateOutputPath>obj\$(Configuration)\$(Platform)\$(TargetFrameworkVersion)\$(TargetFrameworkIdentifier)\</BaseIntermediateOutputPath>
<DocumentationFile>bin\$(Configuration)\$(Platform)\$(TargetFrameworkVersion)\$(TargetFrameworkIdentifier)\$(AssemblyName).xml</DocumentationFile>
This allows me to build them all at once by routing the output into different directories.
Now, that's all for building. However, I'm really stuck with deployment, especially related to NuGet. I've created a .nuspec where I include every dependency manually:
<file src="bin\Release\AnyCPU\v4.0\MyProject.dll" target="lib\net40-client\EIT.Foundation.dll" />
<file src="bin\Release\AnyCPU\v4.0\MyProject.xml" target="lib\net40-client\EIT.Foundation.xml" />
<file src="bin\Release\AnyCPU\v4.5\MyProject.dll" target="lib\net45\MyProject.dll" />
This works fine, but is really tedious. So first question: Is there any way to hook up the files automagically?
And my second problem: Sometimes my libraries have NuGet dependencies themselves. For project dependencies, a packages.config is automatically created in the same folder as the project when downloading NuGet dependencies. The packages.config not only contains the dependency or its version used in the project, but also which framework version of the dependency is required. This is a bit of a problem since every project file (for each framework target) resides in the same folder, so they would need to share the same packages.config file somehow. I'd tried relocating the project files to a different structure like this:
MyProject.sln
target\
net40\MyProject.Net40.csproj
src\
File1.cs
... however then I'm unable to preserve the folder structure in my source folder (if there's any) because the project files only allow me to include files, not folders (they are being automatically included.) Is there any way around this or is NuGet simply not suited for multi-target builds?
Whilst NuGet supports creating a NuGet package for a particular project it is targeted for single projects. The command is NuGet pack YourProject.csproj so I suspect it will not help you. Using a .nuspec file is probably the only way to get this working.
NuGet supports multiple projects in the same directory if you rename the packages.config file. Each packages.config file should be named after the project. So in your example the following should work:
packages.MyProject.Net40.config
packages.MyProject.Net30.config
packages.MyProject.Net45.config

Categories