Patch assembly and nuget version of each project independently - c#

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.

Related

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

MsBuild does not find restored NuGet-Packages on Visual Studio Online

I try to build a solution stored in an external GIT-Repository on Visual Studio Online.
It has the following steps:
1: Git Restore - Works
2: NuGet Restore - Works
3: Build - Does NOT work
My first guess when looking at the logs is that MsBuild is not looking for the Packages where NuGet had stored them.
Some Lines from NuGet Restore:
2018-03-14T21:10:11.0352862Z Completed installation of AngleSharp 0.9.9
2018-03-14T21:10:11.0353230Z Adding package 'AngleSharp.0.9.9' to folder 'D:\a\1\s\packages'
2018-03-14T21:10:11.0353563Z Added package 'AngleSharp.0.9.9' to folder 'D:\a\1\s\packages'
2018-03-14T21:10:11.0354972Z Added package 'AngleSharp.0.9.9' to folder 'D:\a\1\s\packages' from source 'https://api.nuget.org/v3/index.json' 'Microsoft.SharePointOnline.CSOM.16.1.7317.1200' to folder 'D:\a\1\s\packages'
Some lines from MsBuild:
018-03-14T21:10:21.2105399Z PrepareForBuild:
2018-03-14T21:10:21.2105793Z Creating directory "bin\Release\".
2018-03-14T21:10:21.2424947Z Creating directory "obj\Release\".
2018-03-14T21:10:30.3569560Z ResolveAssemblyReferences:
2018-03-14T21:10:30.3570425Z Primary reference "AngleSharp, Version=0.9.9.0, Culture=neutral, PublicKeyToken=e83494dcdc6d31ea, processorArchitecture=MSIL".
2018-03-14T21:10:30.3670272Z ##[warning]C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(2041,5): Warning MSB3245: Could not resolve this reference. Could not locate the assembly "AngleSharp, Version=0.9.9.0, Culture=neutral, PublicKeyToken=e83494dcdc6d31ea, processorArchitecture=MSIL". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.
My solution/packages structure is:
....\mysolution\myproject\myproject.csproj
....\mysolution\myproject\packages.config
Current Config:
So how can I change the Nuget and/or msbuild-behavior to make this work?
(Update): To clear this up: I have this problem with every package. They all are in the packages.config, each one is downloaded from Nuget, but each one also isn't found from MsBuild
(Update2) The Commands generated are currently the following:
NUGET:
D:\a\_tool\NuGet\4.4.1\x64\nuget.exe restore D:\a\1\s\AweCsomeO365\packages.config -PackagesDirectory D:\a\1\a\packages -Verbosity Detailed -NonInteractive -ConfigFile D:\a\1\Nuget\tempNuGet_22.config
MSBUILD:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\msbuild.exe" "D:\a\1\s\AweCsomeO365\AweCsomeO365.csproj" /nologo /nr:false /dl:CentralLogger,"D:\a\_tasks\VSBuild_(GUID)\1.126.0\ps_modules\MSBuildHelpers\Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll";"RootDetailId=(GUID)|SolutionDir=D:\a\1\s\AweCsomeO365"*ForwardingLogger,"D:\a\_tasks\VSBuild_(GUID)\1.126.0\ps_modules\MSBuildHelpers\Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll" /p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation=D:\a\1\a /p:ReferencePath=D:\a\1\a\packages /p:platform="anyCPU" /p:configuration="Release" /p:VisualStudioVersion="15.0" /p:_MSDeployUserAgent="VSTS_(GUID)_build_4_22
I replaced the GUIDs; tempNuGetConfig is something that seems to be generated by VSTS dynamically
Still. even if the log states that nuget stores the packages
Added package 'AngleSharp.0.9.9' to folder 'D:\a\1\a\packages'
MsBuild does not seem to find them there:
For SearchPath "D:\a\1\a\packages".
2018-03-16T13:57:42.4625155Z Considered "D:\a\1\a\packages\AngleSharp.winmd", but it didn't exist.
2018-03-16T13:57:42.4625456Z Considered "D:\a\1\a\packages\AngleSharp.dll", but it didn't exist.
2018-03-16T13:57:42.4625730Z Considered "D:\a\1\a\packages\AngleSharp.exe", but it didn't exist.
VSTS-Configurationvalues:
MsBuild: /p:ReferencePath=$(Build.StagingDirectory)\packages
Nuget-DestiantionDirectory: $(Build.StagingDirectory)\packages
(update3): I have no solution file, but only a csproj-file in that repository
The issue was that inside the project there was a hintpath for the packages directing to a location that was not within the GIT-Repository (and shouldn't):
<Reference Include="AngleSharp, Version=0.9.9.0, Culture=neutral, PublicKeyToken=e83494dcdc6d31ea, processorArchitecture=MSIL">
<HintPath>..\..\AweCsome365Test\packages\AngleSharp.0.9.9\lib\net45\AngleSharp.dll</HintPath>
</Reference>
My original approach was to define a target directory to NuGet and a Source Directory for MSBuild to use another location to the packages that both understand.
The issue though (as far as I understand) is, that NuGet always creates a subfolder-structure "./packages/{PackagesName}/lib/net45/{file}" and MSBuild does not look recursivly when setting "./packages" as source path.
The above is just an explanation for the future guy running into the same problem
So my solution was to mimic the local behavior for nuget and changing the output directory to match the HintPath (even if there is no "AweCsome365Test")-directory in the repository:
(I will leave this question open as this solution smells fishy. If anyone has a better solution that allows to chain nuget and msbuild without using the HintPath I am happily willing to spend my bounty on it)
I believe that your MSBuild "ReferencePath" parameter is not correct. you are telling MS Build that all your references (nuget packages and their dlls included) are going to be located at "D:\a\1\a\packages" but that is not where nuget will download and store the packages and dlls. Nuget will download and extract files into D:\a\1\a\packages\{packageName}\{version}\lib\{environment}\package.dll. I think you need to remove that last parameter (ReferencePath) from your MSBuild arguments.
I also noticed that your PackageLocation parameter is not the same as the destination for the NuGet restore task, do you need to add the "\packages" to that parameter like the destination in the restore task?
Change the nuget restore destination directory to $(Build.SourcesDirectory)\packages and remove the msbuild ReferencePath parameter.
The answers here are largely right. However it's worth noting another cause that can result in this behaviour. My toolchain was using Azure DevOps which is basically the same as Visual Studio Online, just a few years later.
Cause:
Reference your project from a different solution (cross-repo), for instance for debugging purposes
Update NuGet references in the problematic project from the external place you referenced it from
What this does is make use of the solution location for packages when the package gets installed.
For .Net core/standard projects, using Update-Package -reinstall appears to fix things. However, for .Net Framework projects, even though packages.json may get rebuilt, the <HintPath /> node in the .csproj gets left as is - with a reference to a packages folder that Azure will never create.
Simple fix:
Right click on the offending solutions locally, and choose Unload
Right click on the unloaded project, choose edit .csproj
Find any hintpaths that look like ../../OtherRepo/packages (the slash in use may vary), and change them to ../packages
Confirm the solution does build locally still
Push the changes to Azure, and cross your fingers
This approach will fix the issue caused by consolidating / updating packages from the wrong place rather than requiring a change to the build pipeline to spoof that location (which in may case, wasn't working very well either).

Nuget & dotnet on linux - using/package a provided package

perhaps Im getting old but Im really confused on how to use a nupkg on Linux. Resolving and installing dependencies/adding libs for C is easier for me (never would thought I would say so).
I got a package from a vendor (YYYYY_linux.3.0.77.nupkg) and want to run their example code (version for windows with visual studio worked out of the box) but they told me their linux pack would also work.
What I did:
dotnet init
... coding ...
dotnet restore
dotnet build
/home/tobiass/code/XXXX/Program.cs(27,11): error CS0246: The type or
namespace name 'YYYYY' could not be found (are you missing a using
directive or an assembly reference?)
Afterwards I tried two things:
1.
I edited NuGet.Config
dotnet restore
The nupkg shows up as a feed.
But I still get the same error.
2.
I also tried to create a local feed
mono nuget.exe add ../YYYYYYY_linux.3.0.77.nupkg -source ./
but it always results in
The requested feature is not implemented.
What is the correct way on Linux to add a library? Must it be also a part of project.json? Some config in .nuget?
Best,
Tobias
I suspect your project is not a .NET Core project so you should be using nuget.exe instead of dotnet.
So first I would take a look at the example code. Does it have a .csproj file? Does it have a packages.config file? Does it have a packages folder with the .nupkg file in it already? If so then nothing needs to be done and it should just compile.
From the error message one or more of the above are not correct. If the project file (.csproj) has references to the files in the NuGet package and there is an existing packages.config file then all you need to do is restore the package. To do that you need to put the NuGet package somewhere so it can be restored. You could simply just copy the .nupkg file into ~/.local/share/NuGet/Cache/ which is the machine cache for all NuGet packages and then restore it into the project by running nuget restore Path/To/YourSolution.sln.
If the project does not have a packages.config file then you would need to install it into the project. The simplest way would be to use MonoDevelop. That has built-in support for adding NuGet packages to projects.
Otherwise you could just unzip the .nupkg file and copy the files where they need to go into the solution's packages directory based on the information in the .csproj file.

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.

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