I have several XSLTs used in my ASP.NET web application.
I want these files to be compiled to dll whenever I build the project.
Currently, I'm compiling the xslts manually by invoking xsltc.exe from vs2010 tools command prompt.
How can I add msbuild task for xsltc.exe so that it will generate assembly whenevr i build my project?
I'm using .NET 4.0.
That works but doesn't really wrap the tool in a MSBuild friendly way.
I came up with this (which was good enough to get by).
<!-- The Transform File Names... -->
<ItemGroup>
<XsltcTransform Include="Transform1.xslt">
<!-- And the generated .Net Class name. -->
<Class>Transform1Class</Class>
</XsltcTransform>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- Sadly using $(OutDir) MUST come after the Import of CSharp.targets -->
<PropertyGroup>
<XSLTCOutputDll>$(OutDir)xslts.dll</XSLTCOutputDll>
</PropertyGroup>
<Target Name="FindXSLTC">
<PropertyGroup>
<XSLTC>"$(TargetFrameworkSDKToolsDirectory)xsltc.exe"</XSLTC>
</PropertyGroup>
</Target>
<Target Name="XSLTC" Inputs="#(XsltcTransform)" Outputs="$(XSLTCOutputDll)" DependsOnTargets="FindXSLTC">
<Exec Command="$(XSLTC) /out:"$(XSLTCOutputDll)" #(XsltcTransform -> ' /class:%(Class) %(FullPath) ')" />
</Target>
<Target Name="BeforeResolveReferences" DependsOnTargets="XSLTC">
</Target>
These targets will let you compile multiple transforms into one DLL.
Running XSLTC before "BeforeResolveRefereneces" is necessary so that you can have an assembly reference to the generated DLL.
<PropertyGroup>
<WinSDK>C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin</WinSDK>
</PropertyGroup>
<Target Name="Build">
<Exec Command="%22$(WinSDK)\xsltc.exe%22 /out:$(OutputPath)\_PublishedWebsites\xyzapp\bin\Xslts.dll /class:ABC %22$(MSBuildProjectDirectory)\xyzapp\a.xslt%22 /class:DEF %22$(MSBuildProjectDirectory)\xyzapp\b.xslt%22 /class:GHI %22$(MSBuildProjectDirectory)\xyzapp\c.xslt%22"/>
</Target>
Related
I set CopyLocalLockFileAssemblies to true and want to filter the output. So I used the following code:
<Target Name="FilterCopyLocalItems" AfterTargets="ResolveLockFileCopyLocalProjectDeps">
<ItemGroup>
<ReferenceCopyLocalPaths Remove="#(ReferenceCopyLocalPaths)" Condition="'%(Filename)' == 'Microsoft.Extensions.DependencyInjection.Abstractions'" />
</ItemGroup>
</Target>
But this code did not work, how can I put a filter on the output?
Your target FilterCopyLocalItems is to remove the reference dll from the output folder.
I wonder if you means that the target cannot be executed.
For me, I used the below xml code in my net core project which installed the nuget package Microsoft.Extensions.DependencyInjection.Abstractions.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
<Target Name="FilterCopyLocalItems" AfterTargets="ResolveLockFileCopyLocalProjectDeps">
<ItemGroup>
<ReferenceCopyLocalPaths Remove="#(ReferenceCopyLocalPaths)" Condition="'%(Filename)' == 'Microsoft.Extensions.DependencyInjection.Abstractions'" />
</ItemGroup>
</Target>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.6" />
</ItemGroup>
</Project>
You can find the target under the Detailed output build log.
Enter Tools-->Options-->Projects and Solutions-->Build and Run-->set MSBuild project build output verbosity to Detailed.
And you can see the target by searching its name under the detailed output log while you build it.
It will prevent the Microsoft.Extensions.DependencyInjection.Abstractions.dll being generated in the output folder.
Update 1
Actually, you may do some extra operation which causes the target ResolveLockFileCopyLocalProjectDeps not to be triggered. Due to the lack of your detailed project structure and CSPROJ file, I did not notice that.
For your situation, the target ResolvePackageDependenciesForBuild works well.
So in your side, you should use this:
<Target Name="FilterCopyLocalItems" AfterTargets="ResolvePackageDependenciesForBuild">
<ItemGroup>
<ReferenceCopyLocalPaths Remove="#(ReferenceCopyLocalPaths)" Condition="'%(Filename)' == 'Microsoft.Extensions.DependencyInjection.Abstractions'" />
</ItemGroup>
</Target>
Besides, when you execute the target, please do not add <ExcludeAssets>Runtime</ExcludeAssets> under the PackageReference of your nuget package, its effect is actually the role of your target FilterCopyLocalItems. At runtime, remove the related package.dll in the output folder. See this document.
So you should delete it to avoid reuse.
I'm generating some .cs files using node.exe before the compilation, which I then include in my project.
I call node.exe and define the steps for the generation via CSProj. After migrating the CSProj to the new format <Project Sdk="Microsoft.NET.Sdk"> the files are constantly being generated, erased and generated again while Visual Studio is open (tested with VS2017 and VS2019).
This is my targets file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
...
</PropertyGroup>
<Target Name="SetVariables">
<ItemGroup>
<_NodeJsExe Include="$(MSBuildThisFileDirectory)..\..\..\Node.js.redist\*\tools\win-x64\node.exe"/>
</ItemGroup>
<PropertyGroup>
<__NodeJsExe>#(_NodeJsExe);</__NodeJsExe>
<NodeJsExe>$(__NodeJsExe.Substring(0, $(__NodeJsExe.IndexOf(';'))))</NodeJsExe>
</PropertyGroup>
</Target>
<Target Name="ProblemHere" BeforeTargets="TransformDuringBuild;PrepareForBuild;CoreCompile" DependsOnTargets="SetVariables;CleanFilesBeforeBuild">
<Exec Command=""$(NodeJsExe)"..." />
</Target>
<Target Name="CleanFilesBeforeBuild">
<ItemGroup>
<Ts2LangFiles Include="$(GeneratedFolder)\**\*.cs" />
</ItemGroup>
<Delete Files="#(Ts2LangFiles)"/>
</Target>
</Project>
Anyone knows what the problem is?
Found out that Visual Studio is building some targets at design-time.
If I add this to my custom target, the files stop being constantly generated by MSBuild:
<Target Name="ProblemHere" Condition="$(DesignTimeBuild) != true And $(BuildingProject) == true" BeforeTargets="TransformDuringBuild;PrepareForBuild;CoreCompile" DependsOnTargets="SetVariables;CleanFilesBeforeBuild">
I just have yet to understand if this is a bug in Visual Studio or if the problem is mine and I'm using the targets like I'm not supposed to.
I'm trying to use the target event "BeforeBuild" in .csproj (vs2017), but it's not working. Someone would know what is wrong:
<Project DefaultTargets="BeforeBuild" Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<Target Name="BeforeBuild">
<Message Text="Test123"></Message>
</Target>
</Project>
The expected result is a message: Test123 on output.
[]s
BeforeBuild dosen't working in csproj
That because Before/AfterTarget in csproj gets overridden by SDKs target file.
if you're using the new Sdk attribute on the Project element, it's not possible to put a target definition after the default .targets import. This can lead to targets that people put in their project files unexpectedly not running, with no indication why unless you examine the log file and see the message that the target has been overridden.
dsplaisted have filed Microsoft/msbuild#1680 for this issue. As a workaround, you can do the following:
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
<PreBuildEvent />
</PropertyGroup>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<Target Name="BeforeBuild">
<Message Text="Test123"></Message>
</Target>
Or:
<Target Name="test" BeforeTargets="Build">
<Message Text="Test123" />
</Target>
From the official docs:
Warning
Be sure to use different names than the predefined targets listed in
the table in the previous section (for example, we named the custom
build target here CustomAfterBuild, not AfterBuild), since those
predefined targets are overridden by the SDK import which also defines
them. You don't see the import of the target file that overrides those
targets, but it is implicitly added to the end of the project file
when you use the Sdk attribute method of referencing an SDK.
I currently have a build setup as follows, allowing me to embed all references DLLs as embedded resources in my assembly. This operates at the AfterResolveReferences target and works flawlessly. It also allows me to produce a single executable which doesn't need any additional DLLs to launch (since it loads these at runtime).
Now, I would like to include the PDB information as well. I already do this with all referenced assemblies, but not the assembly I am building, since that is (for obvious reasons) produced after that target.
To recap:
I am building AssemblyA.exe.
It has AssemblyB.dll and AssemblyC.dll as references, so these are included in AssemblyA.exe as embedded resources during build.
After building AssemblyA.exe, MSBuild also produces a AssemblyA.pdb file.
This is where I want to then also embed AssemblyA.pdb into AssemblyA.exe as embedded resource.
Is that possible somehow? I am aware that this may trigger a double-build.
I ended up writing the following to my project file - works flawlessly. It does a double-build, but it works.
<Target Name="Prebuild">
<CallTarget Targets="Clean" />
<MSBuild Projects="$(SolutionPath)" Targets="Build" Properties="Configuration=Debug;IgnoreRecursion=true" />
</Target>
<Target Name="BeforeBuild">
<ItemGroup>
<_IgnoreRecursion Include="$(IgnoreRecursion)"/>
</ItemGroup>
<CallTarget Targets="Prebuild" Condition="'%(_IgnoreRecursion.Identity)' != 'true'" />
<CreateItem Include="$(TargetDir)\**\*.*">
<Output TaskParameter="Include" ItemName="OutputFiles" />
</CreateItem>
<ItemGroup>
<EmbeddedResource Include="#(OutputFiles)" Condition="('%(OutputFiles.Extension)' == '.dll' Or '%(OutputFiles.Extension)' == '.pdb')">
<LogicalName>%(OutputFiles.DestinationSubDirectory)%(OutputFiles.Filename)%(OutputFiles.Extension)</LogicalName>
</EmbeddedResource>
</ItemGroup>
<Message Importance="high" Text="Embedding: #(OutputFiles->'%(Filename)%(Extension)', ', ')" />
</Target>
If a double compile is not a problem you can create your own target, compile to a temporay folder via msbuild task and then embed the files you need from this temporary folder.
You have to do a rebuild because otherwise it will cache the assemblies.
Your target to compile in the .proj file would look like this:
<Target Name="YourBuild">
<MSBuild Projects="YourProject.csproj" Targets="Build"
Properties="Configuration=Debug;OutputPath=tmp"/>
<MSBuild Projects="YourProject.csproj" Targets="Rebuild"
Properties="Configuration=Debug"/>
</Target>
Files that are included as EmbeddedResoucre in BeforeBuild target in the project:
<Target Name="BeforeBuild">
<ItemGroup>
<YourFiles Include="tmp\*.pdb" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="#(YourFiles ->'%(Relativedir)%(filename)%(extension)')"/>
</ItemGroup>
</Target>
I'm trying to upgrade our TFS server to 2013. We're currently using 2012, but we've also been clinging on to the upgrade template for dear life. With 2013, we'd like to go to the default template and modify it as little as possible.
The problem comes in when you consider that the default template asks you to add each individual .csproj or .sln file that you would like to build. The nice thing about the tfsbuild.proj files is that not only can you build on the server, but you can check out the entire branch and build everything locally, on the command line, by just passing the tfsbuild.proj file to msbuild.exe. Also, developers can own the tfsbuild.proj file without having write access to change the build definition.
What is the replacement for the TFSBuild.proj file in TFS 2013?
My requirements are:
Clean build configuration.
Can easily build everything locally.
What is the solution to this problem in TFS 2013?
Create a wrapper MSBuild .proj that your TFS build definition uses. We use this technique for NuGet package restore, but it can equally be used to chain together multiple solution files.
For local builds you can use msbuild with that .proj wrapper as the target (I just build the .sln file directly as there is only 1).
.proj file (not suggesting that you should use this exact .proj file, just an example)
<PropertyGroup>
<OutDir Condition=" '$(OutDir)'=='' ">$(MSBuildThisFileDirectory)bin\</OutDir>
<Configuration Condition=" '$(Configuration)'=='' ">Release</Configuration>
<SourceHome Condition=" '$(SourceHome)'=='' ">$(MSBuildThisFileDirectory)</SourceHome>
<ToolsHome Condition=" '$(ToolsHome)'=='' ">$(MSBuildThisFileDirectory)tools\</ToolsHome>
</PropertyGroup>
<ItemGroup>
<Solution Include="$(SourceHome)*.sln">
<AdditionalProperties>OutDir=$(OutDir);Configuration=$(Configuration)</AdditionalProperties>
</Solution>
</ItemGroup>
<Target Name="RestorePackages">
<Exec Command=""$(ToolsHome)NuGet\NuGet.exe" restore "%(Solution.Identity)"" />
</Target>
<Target Name="Clean">
<MSBuild Targets="Clean"
Projects="#(Solution)" />
</Target>
<Target Name="Build" DependsOnTargets="RestorePackages">
<MSBuild Targets="Build"
Projects="#(Solution)" />
</Target>
<Target Name="Rebuild" DependsOnTargets="RestorePackages">
<MSBuild Targets="Rebuild"
Projects="#(Solution)" />
</Target>