msbuild not collecting static web assets from dependencies in restricted environment - asp.net-core

I have a Blazor webassembly project which requires some web assets from its dependencies (most of such projects require some).
When I build the project on my machine, everything works fine.
However, when I try to run the very same build in a containerized environment, the application still builds without any errors or warnings, but static web assets are not included in the publishable output.
Withing the containerized environment I have exactly the same toolchain and deps installed (dotnet core 6.0.102). Env vars are different (restricted subset).
I have checked the usual culprits (strace, etc). I can see the relevant asset files and associated prop files being read by msbuild successfully. Yet, when I inspect "Initial items" section in the msbuild log, StaticWebAsset subsection is missing outright, even if I invoke the ResolveStaticWebAssetsConfiguration target directly.
Yet, on my normal workstation everything "just works".
Does somebody know what can cause msbuild to ignore all the static web asset property files post successful reading of those (as confirmed by strace)?

Related

MSBuild GenerateResource task produces resource file names with incomplete namespace, causing our app to crash at runtime

We build mobile apps using Xamarin Forms, with macOS building the iOS apps. We ran into an issue today that has left me scratching my head.
A normal build with embedded resource files looks like this:
CoreResGen:
/Library/Frameworks/Mono.framework/Versions/5.16.0/lib/mono/4.5/resgen.exe /useSourcePath
[....all of our references....]
/compile
Resources/HtmlStyleRes.resx,obj/BuildAgentRelease_iOS/ForumApp.Common.Resources.HtmlStyleRes.resources
Resources/TextRes.resx,obj/BuildAgentRelease_iOS/ForumApp.Common.Resources.TextRes.resources
Resources/TextRes.nb.resx,obj/BuildAgentRelease_iOS/ForumApp.Common.Resources.TextRes.nb.resources
So no surprises there; the .resx files are compiled into binary .resources files with the assembly namespace + folder name + resx filename.
However, we made a change to our directory structure on the build server, and this changed the output from CoreResGen:
CoreResGen:
/Library/Frameworks/Mono.framework/Versions/5.16.0/lib/mono/4.5/resgen.exe /useSourcePath
[....all of our references....]
/compile
Resources/HtmlStyleRes.resx,obj/BuildAgentRelease_iOS/ForumApp.Common.HtmlStyleRes.resources
Resources/TextRes.resx,obj/BuildAgentRelease_iOS/ForumApp.Common.TextRes.resources
Resources/TextRes.nb.resx,obj/BuildAgentRelease_iOS/ForumApp.Common.TextRes.nb.resources
Notice how the "Resources" folder was dropped from the .resources filename. When compiled into an app, this causes our app to crash at runtime, since the resource file namespace is now different.
We build our apps using self-hosted Azure agents. All apps are built from the same repository, and as part of an effort to streamline the build servers, we implemented a pipeline task to utilize a common repository folder for all builds. The Azure agent would normally build out of _work/build-id/s, and our pipeline task will symlink this directory to _work/g/repo-id so that multiple builds can share the same repository.
When we build with the repo in _work/build-id/s, everything is fine. When we build with the symlinked repo, the file namespace error occurs.
As far as we can tell, this happens on macOS, but not on Windows.
We have a possibly related issue that happens on macOS, but not on Windows. The following outputs are from macOS using mono:
Path.GetDirectoryName(#"Resources\TextRes.resx") => ""
Path.GetDirectoryName(#"Resources/TextRes.resx") => "Resources"
Path.GetDirectoryName is used in CreateCSharpManifestResourceName to create the output file name from Resources\TextRes.resx, but there appear to be guards replacing \ with / and I can't see why symlinking the source folder would trigger it.
Has anyone experienced this? Am I missing something obvious?

What is the purpose of msbuild's GenerateRuntimeConfigurationFiles?

I upgraded a netcore1.1 project to the new VS2017/csproj.
In my test projects only, it added:
<PropertyGroup>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
</PropertyGroup>
I did some digging to discover that it generates these files in the bin directory:
ProjectName.Tests.runtimeconfig.json
ProjectName.Tests.runtimeconfig.dev.json
What is this setting and these files, and why do I need them?
Why were they only generated for my test projects?
These are specific to .NET Core projects and specify
Which runtime and version to use. Typically Microsoft.NETCore.App. The "host framework resolver" looks for a matching folder inside the shared folder (e.g. C:\Program Files\dotnet\shared\Microsoft.NETCore.App\1.1.2). This is important since multiple runtimes can be installed side-by-side and the host needs to know which one to use when you run dotnet myapp.dll.
Additional options for the runtime. The most prominent is probably the garbage collection setting that switches between "desktop" and "server" mode. When you set <ServerGarbageCollection>true</ServerGarbageCollection> int he csproj file, this will cause a value in the runtimeconfig.json to be set. (This property is defaulted to true for web projects)
Additional options for the host. additionalProbingPath for example is set to your local NuGet cache which contains the restored packages. You may have noticed that referencing a NuGet package does not cause its dll files to be copied to the output directory (by default). The host uses the additional probing path to look for packages / dlls referenced to in this location (actually it is a two-step lookup: deps.json tells the host which packages to use and this property tells where to look for this package). Since this is only used for development and shouldn't end up in the published output (since this would mean relying on a NuGet cache on the target), this settings is put into a runtimeconfig.dev.json.
"Classic" .NET Framework projects also had a concept of letting the application set some runtime settings. This was accomplished by having an .exe.config file (which would be built from an App.config file in a project if present). You can think of runtimeconfig.json as "the new .exe.config" but the only have a few overlapping concerns.

'runtimes' Folder after Publishing a .Net Core App to Azure Publish Via VS Online

What is the purpose of the 'runtimes' folder that gets published along with all my project files? I have a VS Online account, and have the build/deploy process configured through there. The 'runtimes' folder is certainly not a folder that exists in source control or my project folder.
'runtimes' folder contents:
example contents:
Thanks,
Drew
Like #Gregory_Ott I was facing a similar issue where my deployment was an FDD deployment and the 'runtimes' folder was still being created. All I did was, mentioned the runtime and set the self-contained property to false.
In the following example I have used dotnet to publish:
dotnet publish -c Release -o ..\publish --runtime win-x64 --self-contained false
The following link should help you with the deployment:
https://learn.microsoft.com/en-us/dotnet/core/deploying/deploy-with-cli
These exist because you are building your application as a self contained application as opposed to one that is dependent upon the framework being installed on the machine executing it. Documentation can be found at https://learn.microsoft.com/en-us/dotnet/articles/core/deploying/ describing the various options that can be used to control this output.
If portable target runtime is selected, runtime folder is created.
FWIW, I was facing this situation with a .NET 5 application. An empty "runtimes" project was there in the output directory. After wasting a few minutes I realized that the folder was a left-over from a previous build. I deleted bin/obj folders completely and published again and the "runtimes" folder is no longer there in the output. I didn't have to change anything in the project file or build options. Hope it saves someone else a few minutes too.
Could this explain the existence of a runtimes folder in an FDD deployment:
A framework-dependent deployment with third-party dependencies is only
as portable as its third-party dependencies. For example, if a
third-party library only supports macOS, the app isn't portable to
Windows systems. This happens if the third-party dependency itself
depends on native code. A good example of this is Kestrel server,
which requires a native dependency on libuv. When an FDD is created
for an application with this kind of third-party dependency, the
published output contains a folder for each Runtime Identifier (RID)
that the native dependency supports (and that exists in its NuGet
package).
Source: https://learn.microsoft.com/en-us/dotnet/core/deploying/deploy-with-vs?tabs=vs156#framework-dependent-deployment
Setting your RuntimeIdentifier might be the solution. In my case, working with an Azure Function, it cut about 500 megs and reduced my archive down to 174 megs. This is important because on Consumption plans you get very limited storage.
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>preview</LangVersion>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<OutputType>Exe</OutputType>
<!--
Prevents the runtimes folder from being created in publish, which contained 500 megs of runtime files we don't need.
-->
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>
In the publish profile in Visual Studio, if Target runtime is set to 'Portable' then all possible runtimes are generated. This is the default, so the output can be reduced by a more selective choice if applicable:

TFS Build dropping extra files including csproj in target folder

I have an automated build process set up to run from a build definition in TFS, which publishes a web application and generates/executes a database project script successfully via publish profiles that are passed as msbuild arguments in the build process definition. Everything is now running as expected except that several unnecessary files are being deployed to the target folder, including the .csproj file, all of the config transforms, and the properties folder which contains all of my publish profiles.
This is strange because 1. It's definitely not including ALL files/folders and mostly appears to be including ones used by the publish profile like transforms, while applying the transform correctly and excluding any explicitly excluded file (as defined in the pubxml), and 2. The process works perfectly if I do it by publishing from the project in Visual Studio 2013. I have the profile configured to only include files needed by the application, and I've confirmed in the csproj file that this property is there.
I tried excluding the properties folder from deployment in the pubxml file, but this causes the build to crash because it can't find the assembly file. What I've gathered is that the process is keeping all files it needs to complete the build, and dropping all of those files in my destination folder. FWIW, I'm using the "file system" method and I'm not sure yet if web deploy will make a difference. I haven't been able yet to connect to the target server with web deploy, but that's a separate problem to solve. Is there something in the build that I can configure so that my destination folder has only the files it needs to run the application, and not the files needed to BUILD the application?
FYI I also have not been using a drop folder, I'm not sure if that makes a difference or not but that might be the only thing I haven't tested as it doesn't seem necessary since I'm using a publishprofile and don't want to use the default tfs build configuration.
I found a solution that works well enough, after reading this: http://www.asp.net/web-forms/tutorials/deployment/advanced-enterprise-web-deployment/excluding-files-and-folders-from-deployment
This was a little uglier solution than I wanted, since it requires hard-coding the names of excluded files, but it does the trick and only requires identifying the files and folders in one location instead of altering a publish profile for each target environment. I created a wpp.targets file and used the ExcludeFromPackageFolders and ExcludeFromPackageFiles elements to identify the extra files. Ironically, if I don't also name the wpp.targets file in the exclude element, THAT file is included in my package. It's possible MSDeploy doesn't have the same issues with TFS as filesystem, but after spending half a day trying to work through a different set of issues and permissions workarounds, we decided that file system is a cleaner publishing method.

Build in TFS with multiple project is not taking the correct transformation web config

I have a solution in VS2010 and it has three project, two of these projects have web config file, the projects have web config transformation for each environment (dev, test and prod).
At the process for TFS build option, I have the at the MSBuild Arguments : /p:DeployOnBuild=True
Everything looks good, the drop folder, the zip files and all structure for the final deployment. The issue I am facing the web config for test and prod is not created correctly after the final deployment, I could see at the drop folders the file projectName.SetParameters.xml, it contains the values for development when the build has been QUEUE for Test and Prod. One of the project has the correct web config (test and prod) but the other project has always the dev webconfig.
Is it a bug in the MS Build? What am I missing in the build parameters?
When I create a build deployment package the web config transformation creates the correct web config file, no issues with this process, but I do not want to use build deployment package to deploy my solution.
Any help will be appreciated.
Thank you.
In your Build Definition you probably defined the Configurations to use. Part of that also defines something like Any CPU or x86. As it turns out the solution the Platform "Any CPU" has a space where in the project files the Platform Any CPU does not have a space.
I found the best way to get around this was to leave the Platform blank and only put in the configuration name. VS will pop up a warning letting you know that there is data missing, you can just hit "Yes" to save it anyways. Alternatively you can just type in your configurations like the following |Release,|Debug.
The pattern is [PlatformName]|[ConfigurationName],[PlatformName]|[ConfigurationName],...