Generated keys: what qualifies, and what you get
The source generator ships inside both UI packages as an analyzer, together with the MSBuild wiring that feeds it. Nothing has to be configured for it to run.
Which files qualify
A .resx file produces a typed key class when all of these hold:
| Requirement | Why |
|---|---|
It is the neutral file — AppStrings.resx, not AppStrings.de.resx |
The neutral file defines the key set; a satellite translates it |
| Its name has no dot before the extension | A dot is how a culture is named, so My.Strings.resx cannot be told apart from a satellite of My.resx |
A classic *.Designer.cs accessor sits in the same folder |
That file is where the generator reads the namespace and the ResourceManager property it must reference |
The accessor is the one Visual Studio's and Rider's classic resx tooling writes — the
PublicResXFileCodeGenerator or ResXFileCodeGenerator custom tool. The SDK's GenerateResxSource
alternative writes its accessor into obj/, where it is build output rather than a file the
generator can pair a .resx with, so a project using it gets no typed keys.
What becomes a key
Only string entries. An entry carrying a type or mimetype attribute — a binary resource, an
image, a colour, an icon — is skipped, because its value is not a string a lookup could return.
Resource names that are not valid C# identifiers are sanitized into ones that are, and a collision
that sanitizing would create is resolved by appending a number. The class is named after the file,
with Keys appended, and lands in the same namespace as the resource accessor.
// <auto-generated/> - for Resources/AppStrings.resx
namespace YourApp.Resources;
public static partial class AppStringsKeys
{
public static readonly ResourceKey Greeting = new("Greeting", AppStrings.ResourceManager);
public static readonly ResourceKey WindowTitle = new("WindowTitle", AppStrings.ResourceManager);
// …one ResourceKey per string entry, sorted by name.
}
Each ResourceKey carries both the key name and the ResourceManager it belongs to. That is
what makes a typed lookup direct: it never searches, and two files may use the same key name without
colliding.
The class is partial, so you can add members of your own to it in a file of your own.
Diagnostics
| Id | Meaning |
|---|---|
RXLGEN001 |
An eligible .resx file is not well-formed XML. The diagnostic points at the file |
RXLGEN002 |
An eligible .resx file has no recognizable classic accessor in its folder |
RXLGEN002 is the one to expect when a project uses GenerateResxSource, or when the .Designer.cs
file was deleted and the custom tool was never re-run.
The compiler floor
The generator is built against Roslyn 4.8 — the compiler in the .NET 8 SDK. A generator built
against a newer Roslyn simply does not load in an older compiler: the build reports CS9057, skips
generation, and then fails on the missing …Keys types. Building the generator against the floor is
what keeps the packages usable on every SDK from .NET 8 upward, and CI proves it on every run by
consuming the packed packages with nothing but the .NET 8 SDK installed.