I want to start using Microsoft.Net.Compilers to simplify work with our build server. However, I could only get it to work at a per-project level, by adding the package to all projects.
This is problematic because the package would have to be added to each new created project. This could lead to a case where the code compiles on the developer's machine (which has the latest compiler), but would fail on the build server. We have many projects (over 100), so this is relatively common.
Is there a way of using Microsoft.Net.Compilers at solution level?
If there is no supported way, is there a command line tool I would not have to install on the build server? Alternatively, is this not an intended usage of these tools?
If in VS 2017 (update 1, build numbers >= 15.1.*) you can use the MSBuild integrated PackageReference mechanism instead of packages.config which was previously only available for .net core and .net standard project types. See the PackageReference documentation as well as the NuGet blog post announcing the support, especially the section "What about other project types that are not .NET Core?".
The idea is to switch from installing a package and adding it to packages.config for restore to just specifying an MSBuild items in the csproj file. This can be set up for new projects in VS:
(animation is from the NuGet blog post linked above)
A new feature of MSBuild 15 is that it supports automatically including files in the directory hierarchy that have special names. Those are Directory.Build.props and Directory.Build.targets which will get included before (props) and after (targets) your project file's content (there is a bug with the .targets version for multi targeting projects for which a fix is about to be released).
If you create a Directory.Build.props file with the following content at the solution level, all projects in the directory hierarchy below it will inherit it's content and you can force a NuGet dependency onto each project:
<Project>
<ItemGroup>
<PackageReference Include="Microsoft.Net.Compilers" Version="2.1.0"/>
</ItemGroup>
</Project>
For existing projects in the solution:
Right-click your solution > Manage NuGet Packages for Solution...
... Or:
Tools > Library Package Manager > Manage NuGet Packages for Solution...
Then add it to all the projects by browsing for your package, then checking the top checkbox, and clicking install.
Source : https://stackoverflow.com/a/8653312/7007466
For the new projects:
Create a template mimicking the original one for each type of project you need (Console, Library etc...) and adding the package to it.
Create a project.
Note:
Use only valid identifier characters when naming a project that will be the source for a template. A template exported from a project named with invalid characters can cause compilation errors in future projects based on the template.
Edit the project until it is ready to be exported as a template.
As appropriate, edit the code files to indicate where parameter replacement should take place.
On the File menu, click Export Template. The Export Template wizard opens.
Click Project Template.
If you have more than one project in your current solution, select the projects you want to export to a template.
Click Next.
Select an icon and a preview image for your template. These will appear in the New Project dialog box.
Enter a template name and description.
Click Finish. Your project is exported into a .zip file and placed in the specified output location, and, if selected, imported into Visual Studio.
If you have the Visual Studio SDK installed, you can wrap the finished template in a .vsix file for deployment by using the VSIX Project template.
Source : https://msdn.microsoft.com/en-us/library/xkh1wxd8.aspx
If someone has an easier way than creating templates, I'll gladly take it.
On solution level, create CommonProjectBuildProperties.targets:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
<ItemGroup>
<PackageReference Include="Microsoft.Net.Compilers" Version="4.2.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
on each project, add:
<Import Project="../CommonProjectBuildProperties.targets"/>
this way you can manged any changes in one place
Related
I currently have a project in dotnet that has several different projects within it. I am attempting to move out one of the projects to a separate repo and replace it with a git submodule. The issue I'm having is how to remove the package from the original repo. I can delete the directory of the package and I updated the dirs.proj to not contain those proj files.
<Project Sdk="Microsoft.Build.Traversal">
<ItemGroup>
<ProjectFile Include="Proj1\dirs.proj" />
<ProjectFile Include="Proj2\dirs.proj" />
...
// Removed this line <ProjectFile Include="ProjBeingMovedToNewRepo\dirs.proj" />
</ItemGroup>
</Project>
However, when I try to build the resulting solution (msbuild dirs.proj), I get the following exception:
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.RestoreEx.targets(19,5): error :
The project file could not be loaded. Could not find a part of the path
'D:\git\Networking-Tycoon\src\ProjBeingMovedToNewRepo\ProjBeingMovedToNewRepo.csproj'. D:\git\Networking-Tycoon\src\ProjBeingMovedToNewRepo\ProjBeingMovedToNewRepo.csproj [D:\git\Networking-Tycoon\dirs.proj]
It isn't clear to me exactly why the nuget restoreEx targets is trying to pull that project that was removed or where I can update those settings. I tried to disable nuget auto restore and to clean the solution before building but so far have not had luck.
One other note is that the project that is being removed is still being referenced in the project elsewhere (I was planning on referencing the submodule for those later) but wanted to see if there was something more simple I was missing first. What would be the steps that would need to be taken to remove a project like this generally?
In Visual Studio, first close the solution.
Then goto Tools, Nuget package manager, Package Manager Settings.
Then Clear all Nuget cache.
That should clear the problem.
I am creating a nuget package from some code, but also need to deploy some tools with the package.
In a .nuspec file, I can do this with the <files> element, and this all works well.
However when using a .nuspec file, the packageReferences from the csproj file aren't included, and I am seeing some problems when including them manually (with the <dependencies> element).
The package created also always seems to restore as a .net framework package, even though it is targetting .net, as in this question.
I am hoping that all these problems would go away if I moved to using the .csproj format for specifying the nuget package details, but having read the docs I can't find out how to do it.
Does anyone know how it is done?
If not, can anyone shed any light on created a .net framework / .net core nuget package from a .nuspec file, that restores to the correct target version and respects package dependencies?
It's not easy to find/discover, but NuGet's MSBuild tasks docs page has a section called "including content in a package", which tells you about the PackagePath metadata on MSBuild items, that NuGet uses to copy files into the package.
So, in your csproj, you could have something like this:
<ItemGroup>
<None Include="..\MyTool\Tool.exe" PackagePath="tools" Pack="true" />
</ItemGroup>
and then your package will contain tools\Tool.exe. The Pack="true" attribute is required for None elements.
You can use MSBuild's globbing to copy entire directories, if that's easier. Include="..\MyTool\*". My MSBuild skills are not so advanced, so I don't know how to glob ..\MyTool\**\*, which means all files in all subdirectories, while maintaining the correct directory layout in the PackagePath="???" metadata. So the best I can suggest is one glob per directory.
Under .NET's older packages.config system for NuGet, I could constrain the possible versions of a package that are considered when packages are updated by using the allowedVersions attribute on the Package element
<package id="Newtonsoft.Json" version="10.0.3" allowedVersions="[10.0.3]" />
When update-package is run within Visual studio for a project including the above, no update will occur for Newtonsoft.Json because I've pinned to 10.0.3 using the allowedVersions attribute.
How can I achieve this under PackageReference? Applying semver syntax to the Version attribute only affects the version restored - it doesn't constrain updates. So if I specify the below PackageReference and run update-package, I will for example be upgraded to 11.0.1 if 11.0.1 is in my NuGet repository.
<PackageReference Include="Newtonsoft.Json" Version="[10.0.3]" />
Background
We rely on command line tooling to update packages because we have both fast moving internal packages (updated multiple times a day) and more stable low moving packages (eg: ASP.NET). On large codebases updating each dependency by hand in .csproj files is simply not scalable for us (and error prone). Under packages.config we can 'pin' the third party packages which we don't want upgraded and also update to the latest fast moving dependencies.
From this answer:
At the moment, this is not possible. See this GitHub issue for tracking.
The cli commands for adding references however support updating single packages in a project by re-running dotnet add package The.Package.Id.
From GitHub Issue 4358:
There is no PackageReference replacement for update yet, the command to modify references is only in dotnet.
You might want to weigh in on the open feature request GitHub issue 4103 about this (4358 was closed as a duplicate). Microsoft hasn't put a high priority on this feature (it was originally opened in October, 2016).
Possible Workarounds
Option 1
It is possible to "update" a dependency by removing and adding the reference. According to this post, specifying the version explicitly with the command will install the exact version, not the latest version. I have also confirmed you can add version constraints with the command:
dotnet remove NewCsproj.csproj package Newtonsoft.Json
dotnet add NewCsproj.csproj package Newtonsoft.Json -v [10.0.3]
What you could do with these commands:
Keep version numbers of packages around in a text file (perhaps just keep it named packages.config).
Use a script to create your own "update" command that reads the text file and processes each dependency in a loop using the above 2 commands. The script could be setup to be passed a .sln file to process each of the projects within it.
Option 2
Use MSBuild to "import" dependencies from a common MSBuild file, where you can update the versions in one place.
You can define your own <IncludeDependencies> element to include specific dependencies to each project.
SomeProject.csproj
<Project Sdk="Microsoft.NET.Sdk">
<IncludeDependencies>Newtonsoft.Json;FastMoving</IncludeDependencies>
<Import Project="..\..\..\Dependencies.proj" />
...
</Project>
Dependencies.proj
<Project>
<ItemGroup>
<PackageReference Condition="$(IncludeDependencies.Contains('Newtonsoft.Json'))" Include="Newtonsoft.Json" Version="[10.0.3]" />
<PackageReference Condition="$(IncludeDependencies.Contains('FastMoving'))" Include="FastMoving" Version="3.332.0" />
</ItemGroup>
</Project>
This has now been implemented as of https://github.com/NuGet/NuGet.Client/pull/2201. If you are using any version of NuGet 5, PackageReference semver constraints should now work as expected.
Pinning - Yet another workaround
This doesn't prevent the update but triggers a build error if one did and update. It won't help much with the use case of automated updates but it may help others that do manual updates and need some way of pinning.
<ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="2.13.*" GeneratePathProperty="true" />
</ItemGroup>
<Target Name="CheckPkgVersions" AfterTargets="AfterBuild">
<Error Condition="!$(PkgMongoDB_Driver.Contains('2.13.'))" Text="MongoDB.Driver must remain at version 2.13.* to be compatible with MongoDB 3.4.21" />
</Target>
Recently I have added all of our SSIS projects into a continuous integration pipeline. The projects are built using MSBuild in TeamCity, packaged and pushed to a nuget feed. We deploy them using Octopus and some hand cranked PowerShell built on the back os SQL server management objects (SMO). It all works, with the exception of one project. The project in question contains some script tasks which reference an external assembly. That assembly is built in the same pipeline and its assembly version numbers are updated by part of the process. The problem lies in the fact that the SSIS project now references a strong named dll in the GAC which does not exist because the version numbers have changed.
Does anyone know of a way to either updated the reference at build time on the CI server or override the version number at the point of deployment?
I know this post is quite old but it has been viewed a lot so here's a solution I have found.
You need to include a 'targets' file for the build.
Here's an example Targets file:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<E10BOs>C:\Integrations\E10 Uplifts\Epicor 10.2.600.3</E10BOs>
</PropertyGroup>
<Target Name="BeforeResolveReferences">
<CreateProperty Value="$(E10BOs);$(AssemblySearchPaths)">
<Output TaskParameter="Value" PropertyName="AssemblySearchPaths" />
</CreateProperty>
</Target>
</Project>
The property group E10BOS (and there can be more than 1) then defines the path to the dll's of the version you want to build against.
It needs to be saved as myTargetsFile.targets
Then in a regular VS project you could add this line to the project file (outside of VS in notepad)
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), myTargetsFile.targets))\myTargetsFile.targets" />
</Project>
This uses GetDirectoryNameOfFileAbove to search up the folder tree until it finds you targets file and then imports it. Very useful if you have a lot of different projects all requiring a version change and you don't have to figure out any relative paths!
In SSIS however this doesn't seem to work.
What does is hard-wiring the path to the targets file in the package .dtsx file, again edit it in notepad and add the following line (you will probably see the csharp entry near the end of the project tag as before:
<Import Project="C:\Integrations\E10 Uplifts\Epicor 10.2.600.3\myTargetsFile.targets" />
This will pass through the information of the project references into the scripts.
Then with all of you projects using a targets file changing the version is done by changing the path to the version folder you want them to use.
Hope that helps?
I'm completely new to WiX and setting up custom installers in general, so I apologise for the topic of the question!
I have a internal business application (a diary), which builds and works well, so I followed tutorials/official documentation as to adding the WiX project and referencing the Diary's csproj to it.
After then building and running this most basic version of a WiX installer, the output directory has a lone exe file, which crashes moments after loading with a File Not Found Exception.
My guess is that it has not built in either Crystal Report or NLog, both of which are referenced in my CSProj.
My question is this, how do I get WIX to include and build those project references to the output???
Any help is greatly appreciated!
/Antony
Unfortunately you will have to do some manual labor in order to get your projects right. I would take either of the two following approaches which require you to edit the .wixproj file:
Use HeatProject task. You will have to do this for all referenced projects and it will give you separate .wxs files for all of them. After this reference the component groups in those files in a feature of your WIX based setup.
<Target Name="BeforeBuild">
<HeatProject ToolPath="$(WixToolPath)" AutogenerateGuids="true" OutputFile="OutputFile.wxs" SuppressFragments="true" Project="ReferencedProject.csproj" ProjectOutputGroups="Binaries" />
</Target>
Use HeatDirectory task. Following will pick up everything in the bin folder of your project, including any binaries for the referenced projects, and give you a single .wxs containing UniqueComponentGroupName which can be included in any feature.
<Target Name="BeforeBuild">
<PropertyGroup>
<DefineConstants>BINFOLDER=PATH\TO\YourProject\bin\$(Configuration)</DefineConstants>
</PropertyGroup>
<HeatDirectory OutputFile="OutputFile.wxs" Directory="PATH\TO\YourProject\bin\$(Configuration)" KeepEmptyDirectories="true" DirectoryRefId="INSTALLFOLDER" ComponentGroupName="UniqueComponentGroupName" SuppressCom="true" SuppressFragments="true" SuppressRegistry="true" SuppressRootDirectory="true" GenerateGuidsNow="true" ToolPath="$(WixToolPath)" PreprocessorVariable="var.BINFOLDER" />
</Target>
Unlike the (now defunct) Setup Project project in older versions of Visual Studio, WiX does not do automatic reference detection. You'll have to add each referenced project to the WiX project manually, just as you did for the main project.