Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong target order when using both MvcBuildViews=true and DeployOnBuild=true MSBuild properties? #82

Open
julealgon opened this issue Oct 7, 2024 · 5 comments

Comments

@julealgon
Copy link

I'm playing around with switching our deployment process from a "raw" file copy of build outputs, to a more proper "publish"-based approach, where we first publish to a folder and then copy those contents instead. One of the things I want to tap into with this change is the native XML transform step, which we currently cannot use as it only runs on publish.

However, I noticed that when I try to publish in Release mode, the contents of the bin/obj/Package folder (the standard place where publish outputs are placed) is empty.

I'm running the following simple commandline:

msbuild /p:Configuration=Release /p:DeployOnBuild=true

I noticed that if I executed the exact same command, but using Debug configuration, the files were output just fine.

After analyzing the logs, I noticed that the publish results were being cleaned by the aspnet compilation target, which appears to be running after the publishing step. This of course is triggered by the MvcBuildViews flag, which is true by default only in Release mode.

At first glance, this makes little sense to me: shouldn't aspnet compilation be happening before packaging, so that the extra compiled bits are included in the publish package?

Here is a slightly redacted version of the MSBuild logs from one of our affected projects, starting after the CoreCompile target:

CoreCompile:
Skipping target "CoreCompile" because all output files are up-to-date with respect to the input files.
_CopyAppConfigFile:
Skipping target "_CopyAppConfigFile" because all output files are up-to-date with respect to the input files.
CopyFilesToOutputDirectory:
  ...
SetRoslynCompilerFiles:
  Using Roslyn from 'C:\Users\JulianoLealGoncalves\.nuget\packages\microsoft.codedom.providers.dotnetcompilerplatform\4
  .1.0\tools\roslyn-4.1.0' folder
ValidateGlobalPackageSetting:
  $(PackageAsSingleFile) is True
  $(PackageFileName) is ... Validating...
CollectFilesFromIntermediateAssembly:
  Gather all files from Project items @(IntermediateAssembly). Adding:
  ...
CollectFilesFromContent:
  Gather all files from Project items @(Content). Adding:
  Web.config;Global.asax;Default.aspx;Ping.aspx;V2\Default.aspx
CollectFilesFromIntermediateSatelliteAssembliesWithTargetPath:
  Gather all files from Project output (IntermediateSatelliteAssembliesWithTargetPath). Adding:
CollectFilesFromReference:
  Gather all files from Project items @(ReferenceCopyLocalPaths,ReferenceComWrappersToCopyLocal,ResolvedIsolatedComModu
  les,_DeploymentLooseManifestFile,NativeReferenceFile).
CollectFilesFromAllExtraReferenceFiles:
  Gather all files from Project items @(AllExtraReferenceFiles). Adding:
CollectFilesFrom_binDeployableAssemblies:
  Gather all files from Project items @(_binDeployableAssemblies). Adding:
PipelineCollectFilesPhase:
  Publish Pipeline Collect Files Phase
PreTransformWebConfig:
  Found The following for Config tranformation:
  Web.config
  ...
TransformWebConfigCore:
Skipping target "TransformWebConfigCore" because all output files are up-to-date with respect to the input files.
PostTransformWebConfig:
  Transformed Web.config using ... into obj\Release\Tran
  sformWebConfig\transformed\Web.config.
PipelineTransformPhase:
  Publish Pipeline Transform Phase
PreAutoParameterizationWebConfigConnectionStrings:
  Skip copying obj\Release\TransformWebConfig\transformed\Web.config to obj\Release\CSAutoParameterize\original\Web.con
  fig, File obj\Release\CSAutoParameterize\original\Web.config is up to date
AutoParameterizationWebConfigConnectionStringsCore:
Skipping target "AutoParameterizationWebConfigConnectionStringsCore" because all output files are up-to-date with respe
ct to the input files.
PostAutoParameterizationWebConfigConnectionStrings:
  Auto ConnectionString Transformed obj\Release\TransformWebConfig\transformed\Web.config into obj\Release\CSAutoParame
  terize\transformed\Web.config.
PipelineMsdeploySpecificTransformPhase:
  Publish Pipeline Deploy phase Stage PipelineMsdeploySpecificTransformPhase
CopyAllFilesToSingleFolderForMsdeploy:
  ...
PipelineCopyAllFilesToOneFolderForMsdeploy:
  Publish Pipeline Deploy phase Stage PipelineCopyAllFilesToOneFolderForMsdeploy
Package:
  Invoking Web Deploy to generate the package with the following settings:
  $(LocalIisVersion) is 10
  $(DestinationIisVersion) is 10
  $(UseIis) is False
  $(IncludeIisSettings) is False
  $(_DeploymentUseIis) is False
  $(DestinationUseIis) is False
GetMSDeployInstalledVersionPath:
  $(_DefaultMSDeployMaxVersion) is 3
  $(_MSDeployVersionsToTry) is 9.0
  $(MSDeployPath) is C:\Program Files\IIS\Microsoft Web Deploy V3\
GenerateMsdeployManifestFiles:
  Generate source manifest file for Web Deploy package/publish ...
PackageUsingManifest:
  Packaging into ...
  Starting Web deployment task from source: manifest(...) to Destination: package(...).
  Successfully executed Web deployment task.
  ...
GenerateSampleDeployScript:
  ...
PipelineDeployPhase:
  Publish Pipeline Deploy Phase
CleanupForBuildMvcViews:
  Deleting file "obj\Release\TransformWebConfig\transformed\Web.config".
  Deleting file "obj\Release\TransformWebConfig\original\Web.config".
  Deleting file "obj\Release\TransformWebConfig\assist\Web.config".
  Deleting file "obj\Release\CSAutoParameterize\transformed\Web.config".
  Deleting file "obj\Release\CSAutoParameterize\original\Web.config".
  Deleting file "obj\Release\Package\PackageTmp\V2\Default.aspx".
  Deleting file "obj\Release\Package\PackageTmp\bin\roslyn\csc.exe".
  ...
MvcBuildViews:
Done Building Project ... (default targets).

The package contents are generated in the PackageUsingManifest target, but right after that, CleanupForBuildMvcViews is executed and deletes all the files it generates.

I found a similar problem described here:

But in that case, the person had the MvcBuildViews target declared in their own project, which is not the case with this SDK, where that target (AFAIK) is part of the SDK itself.

Am I missing something obvious here, or is there an issue in the SDK that should be fixed so that MvcBuildViews (aspnet compiler dynamic compilation) takes place before the standard publishing targets do?

Is this SDK supposed to work with the DeployOnBuild MSBuild flag? Or should I actually be looking into a different deployment approach altogether?

@CZEMacLeod
Copy link
Owner

Hmm - I've not encountered this myself.
There are some examples of how to publish manually or with CI/CD in #21 (comment)

You might be able to fix the ordering you are talking about with

<PropertyGroup>
  <PipelineCollectFilesPhaseDependsOn>
    $(PipelineCollectFilesPhaseDependsOn);
    MvcBuildViews;
  </PipelineCollectFilesPhaseDependsOn>
</PropertyGroup>

If this fixes things, then I would think that a PR to add this to the SDK would be in order.

You might also try

msbuild /p:Configuration=Release /p:DeployOnBuild=true /p:PrecompileBeforePublish=true /p:MvcBuildViews=false

@julealgon
Copy link
Author

I realized after looking a bit further into this that we don't really need to have the MvcBuildViews flag at the point of publish, as we are already building the project in a previous step with that flag enabled (by default).

So I worked around this by adding <MvcBuildViews>false</MvcBuildViews> to my publish profile.

You might also try

msbuild /p:Configuration=Release /p:DeployOnBuild=true /p:PrecompileBeforePublish=true /p:MvcBuildViews=false

As I understand it, PrecompileBeforePublish is a different behavior, that optimizes for first access on the server. We are not (yet) using this flag on our deployment, but I'll definitely look into it.

For now, the only reason we've been using the standard MvcBuildViews was for PR validation purposes (so it would fail if any additional error was detected on views after dynamic compilation).

@leusbj
Copy link
Contributor

leusbj commented Oct 9, 2024

@julealgon

You do understand correctly about the PrecompileBeforePublish and related properties will perform an AspNet Compilation immediately before and include that output into the publish artifacts. Once you are using the precompile option having the MvcBuildViews disabled is even preferred because running both would just run the AspNet Compiler twice.

If you decide that while you are investigating the PrecompileBeforePublish you would like to retain the ability to fail the build process on any AspNet Runtime Compilation errors, you can alter your publish profile to set the "destination" of the publish output to anywhere outside the project directory (the name of this property changes between Folder and WebDeploy profiles so I'm not including it).

@EmperorArthur
Copy link

@leusbj

Once you are using the precompile option having the MvcBuildViews disabled is even preferred because running both would just run the AspNet Compiler twice.

Probably worth it to add that to the "docs/SDK.md" and the getting started documentation. I just found this project and am loving it. But our CI/CD system would probably have hit this and it would take us a bit to wonder why compilation was taking so long.

@CZEMacLeod
Copy link
Owner

@EmperorArthur Happy to take PRs to the docs to clarify anything. There are a lot of 'special cases' for this, as everybody has their own CI/CD scripts and ways of doing things.
I've tried to keep everything as close to the base as possible, while automating stuff like the packages for compilers etc. but it is difficult to not be overly prescriptive and allowing people to override behaviors to make it easy to migrate to in an existing project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants