I have an ASP.NET Core application that i wish to build on a jenkins machine with MSBuild 15.
When i try to build i get the following error:
C:\Program Files\dotnet\sdk\2.1.502\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(198,
5): error NETSDK1004: Assets file 'C:\sync\Src\Util\myUtil\ob
j\project.assets.json' not found. Run a NuGet package restore to generate this file
I understand that i need to do nuget restore somehow, but i failed to make it work.
My build process:
Running a batch filed with the following command:
call "%VS150COMNTOOLS%VsDevCmd.bat"
MSBuild DailyBuild.proj /t:DailyBuild /p:VersionNumber=%2 /l:FileLogger,Microsoft.Build.Engine;logfile=Build.log
The DailyBuild.proj file look like this:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SourcesPath>$(MSBuildProjectDirectory)\..\..\</SourcesPath>
<CSCleanProperties>BuildType=Clean;Configuration=Release;IsFormalBuild=true</CSCleanProperties>
<CSBuildProperties>BuildType=ReBuild;Configuration=Release;PauseBuildOnError=false;PublishWebSites=true;VersionName=myProd-$(VersionNumber)</CSBuildProperties>
</PropertyGroup>
<Target Name="DailyBuildWithClean">
<MSBuild Projects="$(MSBuildProjectDirectory)\Make.proj" Targets="Clean" Properties="$(CSCleanProperties)"/>
<MSBuild Projects="$(MSBuildProjectDirectory)\Make.proj" Properties="$(CSCleanProperties)"/>
<MSBuild Projects="$(MSBuildProjectDirectory)\Make.proj" Targets="FormalBuild" Properties="$(CSBuildProperties)"/>
</Target>
<Target Name="DailyBuild">
<MSBuild Projects="$(MSBuildProjectDirectory)\Make.proj" Targets="SW;PreparePackFolder" Properties="$(CSBuildProperties)"/>
</Target>
</Project>
The Make.proj is a proj file containing definitions for many applications to be built, one of them is my ASP.NET Core app.
How do i fix this problem? thank you.
SOLUTION EDIT:
Thanks to solution by Martin Ullrich:
Added in the DailyBuild.proj the target Restore, also added in the Make.proj a target called restore as suggested
(IE:
<Target Name="Restore">
<MSBuild Projects="$(SourcesPath)\my.sln" Targets="Restore" />
</Target>
)
Add -r (-restore//Restore) to your MSBuild command to trigger a restore before the main build.
The restore parameter will build the Restore target, clear internal caches and then run the rest of the build as specified.
Since you build a custom MSBuild project, you then need to add a Restore target to it:
<Target Name="Restore">
<MSBuild Projects="$(SourcesPath)\my.sln" Targets="Restore" />
</Target>
(or alternatively add another Restore target on the make.proj file and forward it from there to the solution or individual projects that you need to be restored)
Be careful using Restore Nuget packages directly in MS build task configuration.
This option is deprecated, as mentioned here for Azure DevOps. (However, I am not sure how context-dependent that is.)
(Important) This option is deprecated. Make sure to clear this checkbox and instead use the NuGet Installer build step.
Source Link: MSBuild
However, I already used that step (in TFS), so this obviously would not fix it for me.
I tried removing the packages-folder in Source Control Explorer as mentioned here, but that did not fix it either.
Inspired by this, I upgraded the TFS NuGet Installer build step to use Nuget 4.0 (in "Advanced" options), and that did fix it. (Maybe in combination with the removal of the packages-folder?)
Simply rebuild your project in another location(directory/folder ) and run your solution it works 100%.
Related
I'm trying to publish my C# project to an executable in order to distribute it. However, I've referenced 'Interop.IWshRuntimeLibrary' and since including it, my project publishes but then crashes on execution with:
An assembly specified in the application dependencies manifest was not found:
package: 'Interop.IWshRuntimeLibrary', version: '1.0.0.0'
path: 'Interop.IWshRuntimeLibrary.dll'
So far I have tried:
Setting the Copy Local and Embed Interlop Types properties for Interop.IWshRuntimeLibrary to every combination of true/false.
Setting the below tag to true/false in the .csproj file.
<PublishWithAspNetCoreTargetManifest>
Installing the System.Runtime.InteropServices NuGet package.
My .csproj file currently looks like this:
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>Project</RootNamespace>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<COMReference Include="IWshRuntimeLibrary.dll">
<Guid>f935dc20-1cf0-11d0-adb9-00c04fd58a0b</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<WrapperTool>tlbimp</WrapperTool>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
</COMReference>
</ItemGroup>
Other references in the project, like to Newtonsoft work fine. I've consulted every thread I can find across the web pertaining to this. The closest I came to another thread describing my problem was Could not load file or assembly Interop.IWshRuntimeLibrary? but I found no useful info there either.
Ideally, I want to just click publish and publish to a folder on my desktop - preferably as the single .exe but the whole folder is fine if it works. I am unaware if I am perhaps missing a step somewhere as I've never used the publish function before. I'm at a loss for what to try next. Thanks.
How are you publishing at the moment?
You should be able to run the publish command with a flag to tell it to publish as a single file :
dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true
More info here : https://dotnetcoretutorials.com/2019/06/20/publishing-a-single-exe-file-in-net-core-3-0/
But as for your particular issue. When publishing as a single file (Which you may already be doing), there is some level of treeshaking involved to try and limit which dependencies it's publishing. In some cases, if you are referencing a library that is loaded using reflection or similar, then ILLinker doesn't know that it's actually being referenced and used.
To get around this, you can add to your csproj file the following :
<ItemGroup>
<TrimmerRootAssembly Include="Interop.IWshRuntimeLibrary" />
</ItemGroup>
Then publish your project like so :
dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true /p:PublishTrimmed=true
More info on how ILLinker works here : https://dotnetcoretutorials.com/2019/06/27/the-publishtrimmed-flag-with-il-linker/
I have seen version.props file in some open source projects here and here.
The content is the following:
<Project>
<PropertyGroup>
<VersionPrefix>0.0.1</VersionPrefix>
<VersionSuffix></VersionSuffix>
</PropertyGroup>
</Project>
I understand this has to do with building projects and version numbers, easy.
My question is how can I increase the version numbers?
I have looked at dotnet cli tools and commands, didnt see any reference about that.
Can you pleaze give me the codez? I mean , help me understand how I can work this version.props file?
This file is include in each project file : <Import Project="..\version.props" /> directly or indirectly throught an other import. And version is updated by hand.
But you can also use dotnet msbuild with /p:Version={your version number}:
dotnet msbuild /t:build /p:Version=1.0.0
Or with publish target for exemple:
dotnet msbuild /t:publish /p:Version=1.0.0
I'm trying to write a plugin system with .NET Core, and one of my requirements are to be able to distribute the plugin DLL along with its dependencies to the user for install.
However, I can't figure out how to include my NuGet dependencies as a build artifact and have them output to the build folder, without having to use dotnet publish as a hack. Is there some way I can specify this in the .csproj file (project file)?
You can add this to a <PropertyGroup> inside your csproj file to enforce copying NuGet assemblies to the build output:
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
However, note that the build output (bin/Release/netcoreapp*/*) is not supposed to be portable and distributable, the output of dotnet publish is. But in your case, copying the assemblies to the build output is probably very useful for testing purposes. But note that you could also use the DependencyContext api to resolve the DLLs and their locations that are part of the application's dependency graph instead of enumerating a local directory.
You can use PostBuildEvent to automate module deployment on build.
To get NuGet assemblies in build folder add in csproj of your module
<PropertyGroup>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
Define what module files you want where using Include/Exclude (modify path as necessary)
<ItemGroup>
<ModuleFiles
Include="$(TargetDir)*.dll"
Exclude="$(TargetDir)System*.dll;$(TargetDir)Microsoft*.dll"
DestinationPath="$(SolutionDir)src\MyProject\Modules\MyModule\%(Filename)%(Extension)">
</ModuleFiles>
</ItemGroup>
Reset your build folder to default and add PostbuildEvent
<Target Name="PublishModule" AfterTargets="PostBuildEvent" Inputs="#(ModuleFiles)" Outputs="#(ModuleFiles->'%(DestinationPath)')">
<WriteLinesToFile File="$(SolutionDir)src\[YOURAPP]\app_offline.htm" />
<Copy SourceFiles="#(ModuleFiles)" DestinationFiles="#(ModuleFiles->'%(DestinationPath)')" />
<Delete Files="$(SolutionDir)src\[YOURAPP]\app_offline.htm" />
</Target>
I'm including app_offline to recycle app if it's already running to avoid file in use errors.
Adding
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
didn't work, but adding this to the Framework .csproj file:
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
did.
I am using .NET 5 and here is my solution to my similar issue.
Structure:
Project-A (Contained Selenium Nuget References, and selenium code)
Project-B (A unit test project, which calls methods in Project-A)
Issue:
When building the solution, the chromedriver.exe file was appearing in the Project-A bin folder, but would not get copied to the Project-B bin folder, so the unit tests could not execute. An exception was thrown saying chromedriver.exe was not found.
Solution:
Modify the attribute in Project-A for the Selenium ChromeDriver NuGet package reference to only consider 'contentfiles;analyzers' as private assets. The default value for this is 'contentfiles;analyzers;build' when not specified. This now means it is okay to flow the output files of the build to parent referencing projects, but not contentfiles or analyzers, where as 'build' was also previously considered a private asset and would not flow through to parent projects.
Before (in Project-A.csproj):
<ItemGroup>
<PackageReference Include="Selenium.Support" Version="3.141.0" />
<PackageReference Include="Selenium.WebDriver" Version="3.141.0" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="87.0.4280.8800" />
</ItemGroup>
After (in Project-A.csproj):
<ItemGroup>
<PackageReference Include="Selenium.Support" Version="3.141.0" />
<PackageReference Include="Selenium.WebDriver" Version="3.141.0" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="87.0.4280.8800">
<PrivateAssets>contentfiles;analyzers</PrivateAssets>
</PackageReference>
</ItemGroup>
I found this information in this link:
https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#controlling-dependency-assets
Hope this helps someone! Good luck.
I "solved" (created work around) this in simpler way.
In post build
dotnet publish "$(ProjectFileName)" --no-build -o pub
xcopy "$(ProjectDir)pub\3rdPartyProvider.*.dll" "$(OutDir)"
pub is the folder where you want your published stuff go for staging
NOTE: depending on what version of dotnet.exe you use, command --no-build may not be available.
For example, not available in v2.0.3; and available in v2.1.402. I know that VS2017 Update4 had v2.0.3. And Update8 has 2.1.x
Update:
The setup above will work in the basic debug environment but to put it into build server/production environment more is needed. In this particular example that I had to solve, we build Release|x64 and Release|x86 separately. So I accounted for both. But to support the post build dotnet publish command, I first added RuntimeIdentifier to project file.
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutputPath>..\..\lib\</OutputPath>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<OutputPath>..\..\lib\</OutputPath>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
</PropertyGroup>
Why I needed it and why you can get away without it? I needed this because my build program is set to intercept warning MSB3270, and fail the build if it appears. This warning says, "hey, some files in your dependencies are of wrong format". But do you remember the goal of this exercise? We need to pull package dependency DLLs. And in many cases it doesn't matter if this warning is there because following post build does not care. Again, this is my build program that cares. So, I only added RuntimeIdentifier to 2 configurations I use during production build.
Full Post build
if not exist "$(ProjectDir)obj\$(ConfigurationName)" mkdir "$(ProjectDir)obj\$(ConfigurationName)"
xcopy "$(ProjectDir)obj\$(PlatformName)\$(ConfigurationName)" "$(ProjectDir)obj\$(ConfigurationName)" /E /R /Y
if $(ConfigurationName) == Release (
dotnet publish "$(ProjectFileName)" --runtime win-$(PlatformName) --no-build -c $(ConfigurationName) -o pub --no-restore --no-dependencies
) else (
dotnet publish "$(ProjectFileName)" --no-build -c $(ConfigurationName) -o pub --no-restore --no-dependencies
)
xcopy "$(ProjectDir)pub\my3rdPartyCompany.*.dll" "$(OutDir)" /Y /R
Explanation: dotnet publish is looking for obj\Debug or obj\Release. We don't have it during the build because build creates obj\x64\Release or obj\x86\Release. Line 1 and 2 mitigate this issue. In line 3 I tell dotnet.exe to use specific configuration and target runtime. Otherwise, when this is debug mode, I don't care about runtime stuff and warnings. And in the last line I simply take my dlls and copy then into output folder. Job done.
In conjunction with the above answer:
I've got this working great in the Post-build event command line: in Visual Studio.
It loops over a selection of dlls (System*.dll and Microsoft.dll)*, and then skips the deletion of specific dlls. System.Data.SqlClient.dll and System.Runtime.Loader.dll
for %%f in ($(OutDir)System*.dll $(OutDir)Microsoft*.dll) do if not %%f == $(OutDir)System.Data.SqlClient.dll if not %%f == $(OutDir)System.Runtime.Loader.dll del %%f
I have just started looking into msbuild, because I want to make my own build scripts. For now I am able to create build scripts that compiles only one project, but how do I handle dependencies?
For example what if I have two projects that gets build with these two msbuild scripts?
projectA.xml
projectB.xml
How do I tell msbuild that when I am executing projectB.xml that it should first execute projectA.xml?
I have googled alot on this, but it does not seem to get anything that a starter like me understands. I would be more than happy with a link to an article describing this, or maybe just a small code example.
The reason why I want this control is because of a library I am building. The library consists of several projects. A developer should be able to pull the source code for the library down and build only the libraries that he wants.
Actually I want to be able to build .net modules from the different projects. That is why I want to be able to run a customized msbuild script.
If you create a solution with the two projects you can target the .sln file with msbuild, rather than directly building the projects, it should take care of project dependencies :)
But that's if you're using standard .csproj projects...
Ok I looked at a project I'm working on, and it's like this:
<ItemGroup>
<ProjectReference Include="..\SomeFolder\SomeProject.csproj">
<Project>{1A94B405-2D01-4A09-90D5-A5B31180A03B}</Project>
<Name>SomeProjectNamespace</Name>
</ProjectReference>
</ItemGroup>
And here's an MSDN page about references. Scroll down till you find ProjectReference...
I setup my build scripts so that I have a few common targets that do not do anything, but use DependsOnTargets to setup project dependencies and run the build.
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- ************************************************************************************************ -->
<!-- Targets that run the builds -->
<!-- ************************************************************************************************ -->
<Target Name="AutoBuild" DependsOnTargets="BuildProject1;BuildProject2;BuildInstallers">
<OnError ExecuteTargets="NotifyFailure" />
</Target>
<Target Name="FullCompile" DependsOnTargets="BuildProject1;BuildProject2">
<OnError ExecuteTargets="NotifyFailure" />
</Target>
<!-- Build Project 1 -->
<Target Name="BuildProject1">
<!-- Use MSBuild task and point it to build project1.csproj, project1.sln or whatever your projects is -->
</Target>
<!-- Build Project 2 -->
<Target Name="BuildProject2">
<!-- Use MSBuild task and point it to build project2.csproj, project2.sln or whatever your projects is -->
</Target>
<Target Name="BuildInstallers">
<!-- Whatever logic you have for building installers -->
</Target>
</Project>
In MSBuild issue #2887 a similar situation is discussed. The thread also reveals a link to official ProjectReference Protocol.
You dont need to build using the sln. If you use project references in your csproj then the dependency order is taken care of by MSBuild.
Try it. Automajically.
You do not need to sort the dependency order in your msbuild script.
I've got an MSBuild script that is just about doing everything that I need it to do apart from my post-build step (see a previous question that I asked: MSBuild conditional Exec?).
What I'm looking to do is build many csproj files and optionally perform post-build steps if and only if the project was built. I don't want to perform my post-build step all the time or else the timestamp on my final output will be modified unnecessarily (and it makes the build process very time consuming for no reason).
In my MSBuild script I've got something like the following for each of my csproj files:
<Target Name="ProjectName">
<MSBuild Projects="PathToProject" Properties="Configuration=$(buildtype)" />
</Target>
Edit:
I think what I really want to do is detect when the CoreCompile task runs for each project. If there were some way to check for this in a condition?
Any ideas?
I'm new to MSBuild so maybe I'm on completely the wrong track!
Thanks,
Alan
You can also do it based on the configuration selected in your build process. For CI, you should always use "Release" or "Production" (you can define your own).
<Exec Condition="'$(ConfigurationName)'=='Release'" Command="your command goes here ..."/>
After much searching for a simple solution to this problem I didn't find one and ended up coming up with a solution of my own that works but may not be the best solution. However, I wanted to share it with anyone else that is having the same problem so that you can at least have a working solution and hopefully saving you a lot of head banging.
To recap, what I wanted to do was run a command line tool after my project was built but only if the assembly was updated (i.e. the timestamp changed). I didn't want to put this into the post-build section of every project because I only wanted the post-build to happen on our build server (not development machines).
I didn't find any way of doing this externally in my main .proj file and did end up altering the post-build section of each .csproj file. However, I prefixed it with an if condition something like this:
if '$(ExecuteCommand)' == 'true' command.exe
This means that the command will never be executed on the development machine but when I invoke the build from my .proj file I can set that flag to true like this:
<!-- Define common properties -->
<PropertyGroup>
<ExecuteCommand>true</ExecuteCommand>
</PropertyGroup>
<Target Name="YourTarget">
<!-- Build project -->
<MSBuild Projects="Path to project" Properties="ExecuteCommand=$(ExecuteCommand)" />
</Target>
As I said, I don't think it is the most graceful solution but it certainly works and will be sufficient for me for the time being. However, I'd still be interested to hear what the proper way of achieving this is so that I can improve my script.
Thanks,
Alan
If you can add the following to each of your projects:
<Target Name="DoStuffWithNewlyCompiledAssembly">
<Exec Command="command.exe" />
</Target>
... then you only need to add a property:
<Target Name="Name">
<MSBuild Projects="" Properties="TargetsTriggeredByCompilation=DoStuffWithNewlyCompiledAssembly" />
</Target>
This works because someone smart at Microsoft added the following line at the end of the CoreCompile target in Microsoft.[CSharp|VisualBasic][.Core].targets (the file name depends on the language and MSBuild/Visual Studio version).
<CallTarget Targets="$(TargetsTriggeredByCompilation)" Condition="'$(TargetsTriggeredByCompilation)' != ''"/>
So if you specify a target name in the TargetsTriggeredByCompilation property, your target will run if CoreCompile runs-- and your target will not run if CoreCompile is skipped (e.g. because the output assembly is already up-to-date with respect to the code).