Changes made in build event are not persisting on clickonce publish - c#

I am having issues with changes made by a post build event not persisting when published.
I currently have my project set to append some extra information to the end of a few otherwise static files in the post build event. When I view the resulting files locally (<some path>\bin\x86\Debug\) I can verify that the changes have been made.
When I go to view the same files as published by clickonce (in the <some click once url>\Application Files\<some version> directory) the files appear without any changes having been made to them.
In addition to a post build event, I have also tried also tried a BeforePublish target and still receive the same result:
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.Targets" />
<Target Name="BeforePublish">
<!-- build event here -->
</Target>
Can anyone explain why I am experiencing this behavior and suggest a solution?

you need to modify files in obj folder - that's where they are copied into publish folder from. In my app I have the following logic to sign all files for the app:
<Target Name="SignOutput" AfterTargets="CoreCompile" Condition="'$(ConfigurationName)'=='Release'">
<PropertyGroup>
<TimestampServerUrl>http://timestamp.verisign.com/scripts/timestamp.dll</TimestampServerUrl>
<ApplicationDescription>MY APP</ApplicationDescription>
<SigningCertificateCriteria></SigningCertificateCriteria>
</PropertyGroup>
<ItemGroup>
<SignableFiles Include="$(ProjectDir)obj\$(ConfigurationName)\$(TargetName)$(TargetExt)" />
</ItemGroup>
<Exec Condition=" '$(ConfigurationName)'=='Release'" Command=""c:\Program Files (x86)\Windows Kits\8.0\bin\x64\signtool.exe" sign $(SigningCertificateCriteria) /d "$(ApplicationDescription)" /t "$(TimestampServerUrl)" "%(SignableFiles.Identity)"" />
</Target>
note the
Include="$(ProjectDir)obj\$(ConfigurationName)\$(TargetName)$(TargetExt)"
line.

Related

After Publish Copy event in VS2019, same functionality as post build event

I'm trying to copy a folder of template files (about 9 thousand files and ~1gb) that are used by my
.net web application to the publish output directory when publishing through VS2019. I have a Post Build script in there to copy them to output when it builds(Works when building locally), but this step seems to get skipped when the files are copied for publishing.
Any ideas how I can add these files so that they get published with rest of application? its a large amount of files so when I tried adding them into VS and change "Copy to output always" VS crashes.
Microsoft has some documentation here about modifying the publish profile to pickup and deploy extra files. Essentially add this to your .pubxml file for the specific publish profile and extra files will be copied.
<Target Name="CustomCollectFiles">
<ItemGroup>
<_CustomFiles Include="..\ExtraFiles\**\*" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForMsdeployDependsOn);
</CopyAllFilesToSingleFolderForMsdeployDependsOn>
</PropertyGroup>
https://learn.microsoft.com/en-us/aspnet/web-forms/overview/deployment/visual-studio-web-deployment/deploying-extra-files

How to publish additional files into bin folder

My .net web app project also includes some unmanaged dlls as additional files.
These are a couple of levels deep in subfolders.
When I publish this project I need these files to be copied to the bin folder alongside all the other binaries.
No matter what settings I try, the best I can get is for them to be published into their existing folder structure which is not where I need them to be.
I've created a PostBuild event to copy the files and this works when building locally but not when publishing to a server. I've not been able to get PostPublish events to work in the same way.
Is there another way to achieve this?
Note this is similar but not the same as a previous question:
Publish unmanaged DLL from referenced project
I have a similar setup. 2 projects in my solution, one .NET Core and the other C++. When I am going to publish the dotnetcoreapp2.2 I want to include the precompiled C++ DLL from the other project.
#JuanR's answer is not working for me, though it is already pretty close to my version. It looks like the <ItemGroup> needs to be in the <Target> tag.
<Target Name="PrepublishScript" BeforeTargets="PrepareForPublish">
<ItemGroup>
<DataModelFiles Include="$(ProjectDir)..\MyCppProject\bin\Release\MyCppProject.dll" />
</ItemGroup>
<Copy SourceFiles="#(DataModelFiles)" DestinationFolder="$(PublishDir)" SkipUnchangedFiles="false" />
</Target>
Try using an after-publish task.
You can create an item group for copy:
<ItemGroup>
<binFilesToCopy Include="$(OutDir)\somepath\to\yourexternalDLLFolder\*" />
<!-- Add more folders/files you want to copy here -->
</ItemGroup>
Then add a target for after publishing:
<Target Name="AfterPublish">
<Copy SourceFiles ="#(binFilesToCopy)" DestinationFolder ="$(OutDir)\bin" />
</Target>
I did this mostly from memory so double-check for syntax, but get you the idea.
In the properties of the file you can set Copy to output directoryto Copy always or you can edit the solution file, expand the xml tag of the file needed and add <CopyToOutputDirectory>Always</CopyToOutputDirectory> as sub-tag.

Build configuration for dynamically referenced projects

I have an ASP.NET project that is included in multiple solutions. In each solution I'd like a different unreferenced project to be included in the ASP.NET project's build output. The solutions look like this:
Foo.sln
WebApp.csproj
Foo.csproj
Bar.sln
WebApp.csproj
Bar.csproj
Ideally, this would work even when debugging with F5. I tried doing this with build configurations, but deviating from the typical 'Debug' and 'Release' seems brittle when working within Visual Studio. Is there a typical way of doing this?
Disclaimer: I don't think this is a very good idea to do but it seems like it can be done.
To test this solution I created two projects. ConsoleApplication1 and ClassLibrary1. ConsoleApplication1 does not have a reference (that is visible in Visual Studio) to ClassLibary1 but when building ConsoleApplication1 from Visual Studio it will build then copy the ClassLibary1.dll to the bin folder of ConsoleApplication1.
To import the target file you will go ahead and add this line to the project that you want to build the unreferenced project. This path will be relative to the current project so in my case the target file was at the root of my solution. Make sure you add this after the line <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> because unreferenced.target relies on targets that are setup in Microsoft.CSharp.targets.
<Import Project="..\unreferenced.target" />
Then you will go ahead and create a file name unreferenced.target and add the contents below to the file.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Start another msbuild task to build your unreferenced project -->
<Target Name="BuildBeforeResolveReferences" BeforeTargets="BeforeResolveReferences">
<MSBuild
BuildInParallel="False"
Projects="$(SolutionDir)ClassLibrary1\ClassLibrary1.csproj"
RunEachTargetSeparately="True"
StopOnFirstFailure="False"
UnloadProjectsOnCompletion="False">
</MSBuild>
</Target>
<Target Name="CopyUnreferencedProjectOutput" AfterTargets="Build">
<!-- This item group is here because we do not want it evaluated by msbuild until the ClassLibrary1.csproj has been compiled and its output is in its output directory -->
<ItemGroup>
<!-- Gets a list of all files at the OutputPath that end in .dll if you need the pdbs remove the .dll -->
<!-- To maintain folder structure in the bin folder use <SourceFiles Include="..\ClassLibary1\#(OutputPath)**\*.dll" /> the double ** is a recursive wild card and will look through all directorys -->
<SourceFiles Include="$(MSBuildProjectDirectory)\..\ClassLibrary1\$(OutputPath)*.dll" />
</ItemGroup>
<!-- To make sure the copy maintains folder structure switch it to this copy -->
<!-- <Copy SourceFiles="#(SourceFiles)" DestinationFiles="#(SourceFiles -> '$(MSBuildProjectDirectory)$(OutputPath)%(RecursiveDir)%(Filename)%(Extension)')" /> -->
<Copy SourceFiles="#(SourceFiles)" DestinationFolder="$(MSBuildProjectDirectory)\$(OutputPath)" />
</Target>
<!-- Cleans up all the files when clean is called -->
<Target Name="CleanUnreferenceProjectOutput" BeforeTargets="Clean">
<ItemGroup>
<!-- Removed the .dll from the end of this to clean up the pdbs as well -->
<SourceFiles Include="$(SolutionDir)\ClassLibrary1\$(OutputPath)*" />
<SourceFiles Include="$(SolutionDir)\ConsoleApplication1\$(OutputPath)*.dll" />
</ItemGroup>
<Delete Files="#(SourceFiles)" />
</Target>
</Project>
I think this is the best that can be done. You could extend this to have a list of projects that are not referenced but you want to build but for this example I just left it at one.
EDIT 2: Before getting to the current solution I did extensive research into injecting the reference into the ProjectReference itemgroup before assemblies were resolved. It can be done but you have to set the property BuildInVisualStudio to false because otherwise when the msbuild conditions are evaluted in the ResolveProjectReferences target in Microsoft.Common.Current.targets you will select a MSBuild task that only runs the GetManifest target. I was able to get the solution to build but given my lack of knowledge on what setting BuildInVisualStudio to false entails I opted for the solution above. Also I added a task for cleaning up the files that were moved to the bin folders because clean will only cleanup what {ProjectName}{ProjectExtension}FileListAbsoluteText.txt in the obj folder of your project.
EDIT: After doing some more research into the solution below it will only work from the command line. I am currently looking into why this is occuring.
I don't know if there is a typical way of doing what you are asking for (from IDE), but you have an options to accomplish this manually by editing the *.*proj files.
Each project will emit output (*.dll, *.exe, app.config, etc), and it will be copied to the folder specified in the $(OutputPath) property (internally it will use OutDir property). If you will build a solution, you will have the $(SolutionDir) property, as well as $(SolutionName). So, you can define new msbuild project, which will be referenced by the other ones, and you can set the property $(OutputPath) so that every output will go into one folder (let call it Common.props):
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SolutionDir Condition=" '$(SolutionDir)' == '' ">$(MSBuildThisFileDirectory)<SolutionDir>
<SolutionName Condition=" '$(SolutionName)' == '' " >DefaultSlnName</SolutionName>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<OutputPath>$(SolutionDir)$(SolutionName)\bin\$(Configuration)</OutputPath>
</PropertyGroup>
</Project>
After that, you should import that project by your other projects - *.*proj (you should specify correct path to the project):
<Import Project="..\Common.props" Condition="Exists('..\Common.props')" />
Using common $(OutputPath) property will place all of your binaries to the one folder - this should help to resolve your task.

ABCpdf nuget package XULRunner folder is corrupt?

I'm trying to update my (previously working) pdf-creating web application to use the ABCpdf.NET and ABCpdf.NET Gecko Runtime nuget packages.
I've installed both packages (both are version 8.1.1.6) however when I run my application, I get the following WebSupergoo.ABCpdf8.Internal.PDFException:
Failed to add HTML: Gecko engine hit an error it was unable to recover
from. Possible causes: XULRunner folder is corrupt or is from another
version of ABCpdf.
After installing the ABCpdf.NET Gecko Runtime package, I got a dialog telling me that I would need to manually copy the XULRunner folder into my output directory. In order to achieve this, I added the following to my applications .csproj file:
<Target Name="AfterBuild">
<CallTarget Targets="CopyAbcpdfToDeployFolder" />
</Target>
<Target Name="CopyAbcpdfToDeployFolder">
<ItemGroup>
<SourceDir Include="$(ProjectDir)XULRunner\**\*.*" />
</ItemGroup>
<Copy SourceFiles="#(SourceDir)" DestinationFolder="$(WebProjectOutputDir)\$(OutputPath)%(SourceDir.RecursiveDir)\XULRunner" />
</Target>
(This seems to be working correctly - the XULRunner folder and its contents are present in my bin folder after a build)
The line of code that is failing is as follows:
theDoc.AddImageUrl(url);
Can anyone help me get this working?
As it turns out, my changes to the .csproj file we not copying all files into the correct subfolders. In order to copy the folder structure and files recursively, the XML should have looked like this:
<Target Name="AfterBuild">
<CallTarget Targets="CopyXULRunnerToDeployFolder" />
</Target>
<Target Name="CopyXULRunnerToDeployFolder">
<ItemGroup>
<MyFiles Include="XULRunner\**\*.*" />
</ItemGroup>
<Microsoft.Build.Tasks.Copy SourceFiles="#(MyFiles)" DestinationFiles="#(MyFiles->'$(OutputPath)\XULRunner\%(RecursiveDir)%(Filename)%(Extension)')"/>
</Target>
I was able to accomplish the same outcome with the following MSBuild xml:
<ItemGroup>
<Content Include="XULRunner\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
I fell upon this setup after dealing with issues concerning the building of a package via MSDeploy not including the XULRunner files.
Not sure if there's anything patently wrong with this, but so far it works for me on a multiple staged deployment setup.

external file for build tasks

I am creating a .net web application and have some build tasks eg msbuild copy task. I add this by editing the project file for the application and adding the task.
While this works ok, is there any way I can use an external xml file to the project file and have my build tasks in this with the main project file referencing it? I would much prefer this as I wouldn't then have to edit the main project file and there is separation between the project file and the build tasks.
You can simply reference any external project or target file by adding an import to your main project file:
...
<!-- this is the default import for (c#) web project files -->
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" />
<!-- import your custom project/target file here -->
<Import Project="MyCustom.targets" Condition="Exists('MyCustom.targets')" />
...
Adding the Condition will allow to build your main project even if your custom project/target file is missing because the build is run in a different environment.
I'm using this approach to run FxCop and StyleCop targets on my local machine but the same main project file can be built without any changes in my staging environment.
Update
Your comment suggests that you actually are looking rather for a solution that should work the other way round: You want to execute some steps before and after building your project without modifying the project configuration itself.
In that case the best way is to create your custom project to call the build of your web project. This could look something like this:
<Project DefaultTargets="MyTargetAfterBuild">
<!-- some Project attributes omitted for readability -->
<Target Name="MyTargetBeforeBuild" ContinueOnError="false">
<Exec Command="svn export" />
</Target>
<Target Name="Build" DependsOnTargets="MyTargetBeforeBuild">
<MSBuild Projects="MyWebProject.csproj" Targets="Build" Properties="Configuration=Release" >
</MSBuild>
</Target>
<Target Name="MyTargetAfterBuild" DependsOnTargets="Build">
<Exec Command="powershell.exe .\MyCustomScript.ps1" />
</Target>
</Project>
You might be interested in this answer on a similar scenario with a more detailed example.
You can call msbuild.exe, targetting your separate build file, in a pre-build or post-build event.

Categories

Resources