I have a solution file with a class library and a couple of windows services. All the services have a project reference to the class library.
In my build file I'm building each service in release mode, zipping the files and copying the zip files to a webserver where our production servers can download the zip files from.
The problem is that only the first services is built and deployed. All others fail with a CSC : error CS0006: Metadata file "classlibrary.dll" could not be found.
I've made a test solution that reproduces the problem. One empty class library, and two empty console applications, both with references to the class library.
Is it because the temp directory is the same? It works fine with web projects and the same temp directory.
And then this build file.
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildCommunityTasksPath>$(MSBuildProjectDirectory)\Tools\MSBuildCommunityTasks</MSBuildCommunityTasksPath>
</PropertyGroup>
<Import Project="Tools\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<PropertyGroup>
<ExtensionTasksPath>$(MSBuildProjectDirectory)\Tools\MSBuild.ExtensionPack\</ExtensionTasksPath>
</PropertyGroup>
<Import Project="Tools\MSBuild.ExtensionPack\MSBuild.ExtensionPack.tasks" />
<PropertyGroup>
<ProjectName>MSbuild test</ProjectName>
</PropertyGroup>
<Target Name="DeployAll" >
<Message Text="DeploymentPackage $(ProjectName)" />
<PropertyGroup>
<TempDeploymentDirectory>$(MSBuildProjectDirectory)\DeploymentPackage\</TempDeploymentDirectory>
<ProjectFile1>ConsoleApplication1\ConsoleApplication1.csproj</ProjectFile1>
<ProjectFile2>ConsoleApplication2\ConsoleApplication2.csproj</ProjectFile2>
</PropertyGroup>
<RemoveDir Directories="$(TempDeploymentDirectory)" />
<MSBuild Projects="$(ProjectFile1)" Properties="Configuration=Release;OutDir=$(TempDeploymentDirectory)" Targets="Clean;Build"/>
<!-- Zipping copying files removed for readability -->
<RemoveDir Directories="$(TempDeploymentDirectory)" />
<MSBuild Projects="$(ProjectFile2)" Properties="Configuration=Release;OutDir=$(TempDeploymentDirectory)" Targets="Clean;Build"/>
</Target>
</Project>
Building the classLibrary before each application worked for the demo project, but not for the real project.
The solution in my project, was to use a different output directory for each service.
Related
I am having an issue trying to implement compiler-based code analysis in my C# .NetFramework solution. I decided to use Microsoft.CodeAnalysis.NetAnalyzers nuget package with some custom .editorconfig ruleset that I do not want to keep directly in the consuming project. I created another nuget with the .editorconfig and the idea is to copy the file to each consuming project before it is built in order to trigger the analysis (during build).
I tried an approach (described here) where the .editorconfig is copied to csproj location in a beforeBuild task defined in .props file
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="('$(Configuration)' == 'Debug')">
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
</PropertyGroup>
<ItemGroup>
<EditorConfigFilesToCopy Include="$(MSBuildThisFileDirectory)..\content\.editorconfig" />
</ItemGroup>
<Target Name="CopyEditorConfig" BeforeTargets="BeforeBuild">
<Message Text="Copying the .editorconfig file from '#(EditorConfigFilesToCopy)' to '$(MSBuildProjectDirectory)'"></Message>
<Copy
SourceFiles="#(EditorConfigFilesToCopy)"
DestinationFolder="$(MSBuildProjectDirectory)"
SkipUnchangedFiles="true"
UseHardlinksIfPossible="false" />
</Target>
</Project>
Unfortunately, the file seems to be copied too late as the msbuild ignores it during the build itself and does not fail due to CA violations as I would expect. If the file had been copied manually before running msbuild, it works.
Do You have any idea why it is like that and how to handle this issue properly?
I currently have a .NET Framework Application whose build process I'm trying to automate using jenkins. Is there a way to specify the tests in a Target in the Start-up project file so that I can specify a command like:
msbuild /t:Test
and it will run the tests?
I would recommend you create a new proj file, with Test Target.
For example, you will create a file at your repository root, call it jenkins.build, and put the following code in it:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Test">
<ItemGroup>
<UnitTests Include="$(WorkingFolder)\**\bin\$(Configuration)\**\*.UnitTests.dll;" Exclude="$(WorkingFolder)\**\*Microsoft.VisualStudio.*;"/>
</ItemGroup>
<PropertyGroup>
<VSTestPath>"C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe"</VSTestPath>
<VSTestCommand>
$(VSTestPath) #(UnitTests->'"%(FullPath)"', ' ')
</VSTestCommand>
</PropertyGroup>
<Exec Command="$(VSTestCommand)" ContinueOnError="false" />
</Target>
</Project>
Then call this file with msbuild jenkins.build /t:Test.
(Of course, this file is defined a lot of things that are environment-dependent.)
I have a NuGet package called "Contoso.Library" with a targets file: "/build/Contoso.Library.targets"
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.0" />
</ItemGroup>
</Project>
However, when I try and build a project containing this I get the following error:
Importing the file "C:\Program Files\dotnet\sdk\2.1.2\Sdks\Microsoft.NET.Sdk\Sdk\Sdk.targets" into the file "C:\Users\rb.nuget\packages\contoso.library\1.0.0\build\contoso.library.targets" results in a circular dependency. C:\Users\rb.nuget\packages\contoso.library\1.0.0\build\contoso.library.targets
I have confirmed that if I rename the targets file to "contoso.library.targets.xxx" this error goes away, demonstrating that the targets file is where the problem lies.
For reference, here is the project file of the project consuming Contoso.Library:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net46</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Contoso.Library" Version="1.0" />
</ItemGroup>
</Project>
Turns out the answer is actually really simple - just drop the "Sdk" attribute from the Project element in the targets file:
<Project Sdk="Microsoft.NET.Sdk">
becomes
<Project>
The same error and the same solution (thanks #RB. !), but I was using Directory.Build.props file instead of a targets file.
My error:
Importing the file "C:\Program
Files\dotnet\sdk\3.1.401\Sdks\Microsoft.NET.Sdk\Sdk\Sdk.props" into
the file "<snip>\Directory.Build.props" results in a circular
dependency
Exact solution:
I removed the Sdk="Microsoft.NET.Sdk" attribute from the Directory.Build.props and the projects rebuild correctly.
HTH!
We have a nuget package we developed and use internally. One package has addtional unmanaged DLL's that need to be deployed. In VS2015, I right-click on the web application project and publish to a test server. None of the unmanaged DLL's in the package were published, but they are in the bin folder on my machine.
Here's what I'm trying in the package targets file:
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="ExtraFilesPublishTarget">
<Message Text="########### NUGET DEPLOY ###########"/>
<ItemGroup>
<DistFiles Include="$(MSBuildThisFileDirectory)..\lib\dist\**\*.*"/>
<FilesForPackagingFromProject Include="%(DistFiles.Identity)">
<DestinationRelativePath>\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
<Target Name="DistBuildTarget" AfterTargets="Build">
<ItemGroup>
<DistFiles Include="$(MSBuildThisFileDirectory)..\lib\dist\**\*.*"/>
</ItemGroup>
<Microsoft.Build.Tasks.Copy SourceFiles="#(DistFiles)" DestinationFiles="#(DistFiles->'$(OutputPath)\%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
<PropertyGroup>
<copyallfilestosinglefolderforpackagedependson>
ExtraFilesPublishTarget;
$(copyallfilestosinglefolderforpackagedependson);
</copyallfilestosinglefolderforpackagedependson>
<copyallfilestosinglefolderformsdeploydependson>
ExtraFilesPublishTarget;
$(copyallfilestosinglefolderforpackagedependson);
</copyallfilestosinglefolderformsdeploydependson>
</PropertyGroup>
</Project>
When I publish, I see the NUGET DEPLOY message, but the next line in the output window is "Target "ExtraFilesPublishTarget" skipped. Previously built successfully."
The link above (http://blog.mjjames.co.uk/2012/10/deploying-non-project-files-with-web.html) solved my problems.
I did have another issue with targets not found. To save time in testing, I would edit my .targets file in the packages folder for my solution. If you add or rename a target in the local .targets file, VS2015 won't find the change since it caches the target names. You have to close down VS or reinstall the package to it to be found. You can change the elements within the target, you just can't change the name of the target or add a target.
I have a separate database project that I’d like to build within the same solution and then reference the created dacpac. When I try adding the database project it builds fine and the dll is added to the secondary project file, but the dacpac is not.
Is there a way that I can have the dacpac copied into my main project through the msbuild? I keep on thinking that there should be a way to modify either the sqlproj file or csproj file so that the dacpac is included as one of the project outputs. My knowledge of msbuild is not extensive, I’ve not been able to figure it out.
It seems to me that I need to add the dacpac somehow to say the '#(ReferenceCopyLocalPaths)' item but I have not been able to figure it out. Any tips or suggestions would be appreciated.
I tried doing something a little like what is referenced here MSBuild - ItemGroup of all bin directories within subdirectories by doing:
<Target Name="AfterBuild">
<Message Text="#(MainAssembly)" />
<!--<DacPacs Include="%(ProjectReference.Directory)**" />-->
<ItemGroup>
<DacPacs Include="%(ProjectReference.Directory)**/*bin*/*.dac" />
</ItemGroup>
<Message Text="#(ReferenceCopyLocalPaths)" />
<Message Text="DacPacs: #(DacPacs)" />
<Message Text="Target Database: $(TargetDatabase)" />
</Target>
which gives nothing for DacPacs (when the wildcard is added). Also I tried referencing one of the item groups from the sqlproj file but it comes out empty to:
In the project properties, you can add a pre-build event command line to get a copy of the dacpac file.
Or you can just add it in the csproj :
<PropertyGroup>
<PreBuildEvent>copy "$(SolutionDir)DatabaseProject\bin\$(ConfigurationName)\DatabaseProject.dacpac" "$(ProjectDir)\DatabaseProject.dacpac"</PreBuildEvent>
</PropertyGroup>
This will only work if the database project was built first, so you should add a dependency. Right clic on the solution and select Project Dependencies..., then select the main project and check that it depends on the Database project.
Add this to your csproj:
<ItemGroup>
<Content Include="..\DatabaseProject\bin\Debug\DatabaseProject.dacpac">
<Link>DatabaseProject.dacpac</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
This solution worked for me with a .NET 6 project which references a .sqlproj project using Micrsoft.Sql.Sdk. Assume there are two projects: DacpacDepender (.NET 6 project) and Dacpac (SQL project).
In DacpacDepender.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- some properties redacted for brevity -->
<TargetFramework>net6.0</TargetFramework>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>
<ItemGroup>
<!-- Ensures build order, the DACPAC is _guaranteed_ to exist when included -->
<ProjectReference Include="..\Dacpac\Dacpac.sqlproj">
<!-- Companion to .sqlproj CopyBuildOutputToOutputDirectory=false -->
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<!-- Suppresses a warning about this project not being compatible with SQL project -->
<SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<!-- Use `$(Configuration)` to reference the DACPAC output location regardless of build configuration. -->
<Content Include="$(ProjectDir)..\Dacpac\bin\$(Configuration)\Dacpac.dacpac" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>
In Dacpac.sqlproj:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build">
<Sdk Name="Microsoft.Build.Sql" Version="0.1.3-preview" />
<PropertyGroup>
<!-- some properties redacted for brevity -->
<!-- Prevents outputting the DLL (some may need it) -->
<CopyBuildOutputToOutputDirectory>false</CopyBuildOutputToOutputDirectory>
<CopyOutputSymbolsToOutputDirectory>false</CopyOutputSymbolsToOutputDirectory>
<Name>Dacpac</Name>
<NetCoreBuild>True</NetCoreBuild>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>
</Project>
Please note that <RestorePackagesWithLockFile /> is not strictly necessary but ensures dotnet restore --locked-mode works, which is a nicety for reproducible builds.