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.
That Foo.resx
will get passed to a few tasks in different forms throughout the build.
- CreateManifestResourceName
- GenerateResource (aka resgen)
- CSC (CSharp Compiler, Roslyn)
- Source Code
- Where it's called in Microsoft.CSharp.CurrentVersion.targets
This task's entire purpose is to set the ManifestResourceName metadata for each Foo.resx (or relevant resource). Note that the tasks CreateCSharpManifestResourceName
and CreateVisualBasicManifestResourceName
are wrappers around the CreateManifestResourceName
task.
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 <your_manifestresourcename_value>.resources
Whether or not this task runs, the resources are eventually passed to the GenerateResource task.
- Source Code
- Where it's called in Microsoft.Common.CurrentVersion.targets
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.
- Source Code
- Where it's called in Microsoft.CSharp.Core.targets
The .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):
/resource:obj\Debug\netcoreapp3.1\ConsoleApp1.Resource1.resources,ThisIsTheWholeNameSetAsLogicalName
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 ConsoleApp1.Resource1.resources
.
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).