Multi-project setup with Nuget Packages - c#

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.

Related

How to Load .csproj file into .NET Core 3.0 using MSBuild NuGet

I have a very simple console project:
class Program
{
static void Main(string[] args)
{
var project = new Project(
"FishStory.csproj",
null,
null,
new ProjectCollection());
Console.ReadLine();
}
}
This is a .NET Core 3.0 console application, and it has Microsoft.Build (16.4.0) NuGet package referenced.
The .csproj file FishStory.csproj is found (I don't get an exception that the .csproj is missing), but I do get the following error.
Microsoft.Build.Exceptions.InvalidProjectFileException:
'The imported project
"C:\Users\vchel\source\repos\ForDave\ForDave\bin\Debug\netcoreapp3.0\Microsoft.CSharp.targets" was not found.
Confirm that the expression in the Import declaration "C:\Users\vchel\source\repos\ForDave\ForDave\bin\Debug\netcoreapp3.0\Microsoft.CSharp.targets" is correct, and that the file exists on disk. C:\Users\vchel\source\repos\ForDave\ForDave\bin\Debug\netcoreapp3.0\FishStory.csproj'
I'd expect that such a simple MSBuild test would "just work", but it seems like I'm missing something. What can I do to load this .csproj file?
I have catched the same exception while I have tried to load a project targeted to netcore31 platform.
But after that I have installed
Microsoft.Build.Utilities.Core(16.5.0)
Microsoft.Build (16.4.0)
nuget packages, there is no more the exception. The project is loaded successfully.
Maybe, it will help someone more.
It seems the NuGet package adds the necessary .dlls to use the Project object, but the various project types must have .target and .props files which are used when the Project .csproj is loaded.
To load my specific project, I had to add the following files to the output directory. I accomplished this by placing the files in my project and marking them as Copy if Newer.
I added the following files:
Microsoft.Common.targets
Microsoft.CSharp.targets
Microsoft.NETFramework.props
Microsoft.NETFramework.targets
In my case the .csproj is a MonoGame project, so I also had to add:
MonoGame.Build.Tasks.dll (not sure if I needed this or not)
MonoGame.common.props
MonoGame/v3.0/MonoGame.Content.Builder.targets
To add these files so they are copied to the output folder:
Add the file to your project (for .NET Core you just have to add the file to the directory)
Right-click on the file in the Solution Explorer and select Properties
Set the Copy to Output Directory to Copy if newer
I pulled the targets/props/.dll files from:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319
C:\Program Files (x86)\MSBuild\MonoGame\v3.0
I am guessing that other project types (such as an Android Xamarin project) may require different .targets files, which can be found here if using Visual Studio 2019 Community:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Xamarin
Finally, I also had to manually add the NuGet Package Microsoft.Build.Utilities.Core. Not sure why that wasn't automatically added when adding Microsoft.Build

Create multi-target nuget package from several csproj contained in different folders from nuspec file

I am trying to create a nuget package for a library which exists in 2 versions, each of them targeting two different .NET versions.
Here is my folder structure:
As you can see my nuspec file is one directory above my csproj (which are in the /net452 and /netcoreapp2.0 folders).
I am using the following command line to build my nuget package:
nuget pack .\my.nuspec -properties Configuration=Release -Build
The issue is that the build can not be achieved because the csproj files are not in the same folder as the nuspec file.
Please note that the packaging works fine when both projects have been priorly manually built.
I'm very new to this process and I'm not sure what I should do in that scenario, is there a simple way to reference the 2 csproj from the nuspec or - assuming I want to keep this folder structure - would I need to make a script that builds the projects first and then invoke nuget pack?
EDIT: To clarify my issue, I do have two different csproj files, contained respectively in /net452 and /netcoreapp2.0, and they compile the source code in their respective directory to produce two different dll. These two dll are then referenced in my nuspec file in order to offer my package in net452 or netcoreapp2.0 with the following syntax:
<files>
<file src="lib\**" target="lib" />
</files>
Note: after I manually compiled my two projects, the directory looks like this (note the lib folder that contains a net452 and netcoreapp2.0 folder with the appropriate version of my dll).
Not sure if understood correctly - you have one library and want to build it in two versions (net452 and netcore).
Did you try adding following items to *.csproj?
<PropertyGroup>
<TargetFrameworks>net45;netcoreapp2.0</TargetFrameworks>
</PropertyGroup>
Then you can have on project with two outputs from build

Patch assembly and nuget version of each project independently

I have a solution with multiple projects (each is a nuget package for some common utils).
I want to build all these projects in VSTS.
The problem each project has a unique version.
version.txt file is stored in each project's folder, and contains the version in format x.x.x
before build each project should be patched with this version
build and push nuget packages
VSTS contains task dotnet build which can build an entire solution or a concrete project. But I need to automate this process - once the new project was added it should be built automatically.
I didn't find the ready-to-use build task which can read the file and patch all parameters of csproj (FileVersion, AssemblyVersion, Version, PackageVersion), and do this per project.
It would be great to have this version.txt file to have a single point of configuration (instead of changing all the parameters)
I didn't find the ready-to-use build task which can read the file and
patch all parameters of csproj (FileVersion, AssemblyVersion, Version,
PackageVersion), and do this per project
Actually, you can get AssemblyFileVersion and AssemblyVersion easily by related task (such as Assembly Info Reader task).
You just need to specify the path for AssemblyInfo.cs file, then you can get the AssemblyFileVersion by the variable $(ASSEMBLYINFO.ASSEMBLYFILEVE), and get the AssemblyVersion by the variable $(ASSEMBLYINFO.ASSEMBLYVERSION). And you can use the version for the package.
BTW: the packed packages use it's AssemblyVersion by default. So if you want to packages use their AssemblyVersions, there is no need to do additional settings.
I did not find the solution so invented a new bicycle.
In each project folder there is a version.txt file with the version of exact package
Powershell scripts finds all version.txt files and uses the version from the file to patch .csproj file (package, assembly, whatever)
build all projects
In my scenario I don't want to add build number to the version so I have packages with the same version over builds. So I want to skip already exist packages
With Powershell script I do nuget list <package name> to check whether package already exists.
If not - pushing it to the repository.

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

Nuget packages not restoring correctly when Copying and including .NET projects from one solution to another

I have a need to copy a .NET project / class library from one solution to another.
Does a copy/paste and subsequent inclusion of the project in the new solution suffice?
Or are there any caveats?
(like generating a new Project GUID etc...)
The main reason I ask is because the nuget packages are not restoring and being added to references at all after I copy and include the csproj.
I faced the same problem, and it was because in the new Solution the NuGet Packages folder was in a different location relative to the project. To get around it I took the following steps:
Copy the project into the directory you want it to be in
Edit the csproj file so that all references to the Packages folder are correct relative to the new location
Add the project to the solution and build - packages will be restored

Categories