Manifest Resource Names and You!
For explicit information on how resource names are chosen, see this dotnet docs issue.
This gist is meant to be a slightly higher level explanation on how resource names are used. Mostly I'm just documenting as much context as possible before I forget.
So we start with some Foo.resx
Foo.resx will get passed to a few tasks in different forms throughout the build.
- GenerateResource (aka resgen)
- CSC (CSharp Compiler, Roslyn)
This task's entire purpose is to set the ManifestResourceName metadata for each Foo.resx (or relevant resource). Note that the tasks
CreateVisualBasicManifestResourceName are wrappers around the
The task is called in Microsoft.CSharp.CurrentVersion.targets. It ONLY runs if ManifestResourceName metadata is NOT set. Should you choose to set that manually,
.resources will be appended to it and that will be the resource name and file name. Resulting in
Whether or not this task runs, the resources are eventually passed to the GenerateResource task.
Takes in .Resx files (XML files) and spits out .resources files (binary files that can be read by the ResourceManager).
ManifestResourceName controls the name that those files get spit out as (which comes from CreateManifestResourceName), UNLESS
LogicalName metadata is set for this resource.
.resources that was output from the GenerateResource task then gets passed over to the
Csc task within the
CoreCompile target (linked above).
The command line args for the
Csc task are massively long, but here's the relevant line (taken from a test project's binlog):
Note: Here we have a resource named
ConsoleApp1.Resource1.resources and a logical name separated by a comma,
ThisIsTheWholeNameSetAsLogicalName. The compiler will ALWAYS prefer the logical name over whatever the manifest resource name was set to. It will then stuff that into the binary. In this case, the resource would be stuffed into the binary as
ThisIsTheWholeNameSetAsLogicalName. Also note that if no LogicalName metadata was set, the embedded resource would be
Again, see this dotnet docs issue for context and a more detailed explanation on how these manifest resource names get chosen.
See this mediocre diagram below for a visualization of what happens (pictures help me understand this stuff easier).