Description
Resource Naming Conventions Have Changed
For those that would like a slightly higher level explanation and maybe even a mediocre diagram of what's going on here, see this gist I created.
Version introduced
3.0, via applying DependentUpon convention, but more specifically applying that convention to localized resources. Here is the related MSBuild issue that tracked this.
Old behavior
When the DependentUpon
metadata was set, the manifest name would be FullTypeName.resources
where FullTypeName is Namespace.Classname
. When the DependentUpon
metadata was NOT set, the manifest names default to: FullTypeName.FolderPathRelativeToRoot.Culture.resources
.
New behavior
When a resx is associated with a type like in the winforms case, the generally presumed convention is that the resource is called FullTypeName.resources
(the culture may or may not be present, FullTypeName.Culture.resources
for example).
From this presumed convention, the rules around how RootNamespace and folders impact the name chosen mirror how VS picks a namespace and name for a new class: RootNamespace.FoldersSeparatedByDots.FileName.(resx|resources|cs)
So if you leave all the defaults when you add files and resources in VS, then when you have Type.cs next to Type.resx, you will get FullNameOfType.resources. However, when you stray from the defaults, there’s more to it.
The points below are the rules with which manifest resource names are generated:
1. If the metadata LogicalName %(EmbeddedResource.LogicalName)
is set, then use it as is.
Examples:
<EmbeddedResource Include="X.resx" LogicalName="SomeName.resources" />
<EmbeddedResource Include="X.fr-FR.resx" LogicalName="SomeName.resources" />
Then the resource is SomeName.resources
, irrespective of the .resx
file name, culture, or any other metadata.
2. else if the metadata ManifestResourceName %(EmbeddedResource.ManifestResourceName)
is set then add the .resources
extension and use it.
Examples:
<EmbeddedResource Include="X.resx" ManifestResourceName="SomeName" />
Then the resource name is SomeName.resources
<EmbeddedResource Include="X.fr-FR.resx" ManifestResourceName="SomeName.fr-FR" />
Then the resource name is SomeName.fr-FR.resources
3. else if %(EmbeddedResource.DependentUpon)
is set to a source file, then parse the source file and add culture and .resources
extension to the full type name of the first class in the file. This allows types to be renamed and have the corresponding resource change names accordingly.
Given Q.cs:
namespace SomeNamespace { class SomeType {} }}
Examples:
<EmbeddedResource Include="X.resx" DependentUpon="Q.cs">
Then the resource name is SomeNamespace.SomeType.resources
<EmbeddedResource Include="X.fr-FR.resx" DependentUpon="Q.cs">
Then the resource name is SomeNamespace.SomeType.fr-FR.resources
4. else if EmbeddedResourceUseDependentUponConvention
is set to true
(which is true by default for projects targeting .net core 3+), then choose DependentUpon as follows and perform rule 3 above.
If there is a source file in the same folder that has the same name as the resx when not including culture or file extensions, choose DependentUpon from the resx to the source file.
Example:
Src/
Q.cs: namespace SomeNamespace { class SomeType {} }}
Q.resx --> resource name is SomeNamespace.SomeType.resources
Q.fr-Fr.resx --> resource name is SomeNamespace.SomeType.fr-FR.resources
5. else let RelativePath = %(EmbeddedResource.Link) if set, else %(EmbeddedResource.Identity). (This is the path in solution explorer from project root to file.) Then use $(RootNamespace).(RelativePathWithDotsForSlashes).Culture?.resources
Reason for change
We had various issues(1, 2, 3) revolving around the desire to get users to migrate to .NET Core and how MSBuild handles embedded resources being a blocker for that.
Recommended action
If you're unsatisfied with the manifest names that are currently being generated, simply add this line to your project file:
<EmbeddedResourceUseDependentUponConvention>false</EmbeddedResourceUseDependentUponConvention>
Setting this tag to false is how you opt out of this convention entirely. Do note that rules 1 and 2 above still apply.
Otherwise, modify your resource file metadata to satisfy one of the above rules.
Category
- ASP.NET Core
- C#
- MSBuild
- Windows Forms
- Windows Presentation Foundation (WPF)
Issue metadata
- Issue type: breaking-change