Search code examples
c#deploymentmsbuildembedded-resource

How to change the generated ManifestResourceName for Embedded Resources


In a C# project, the generated resource name for an Embedded Resource by default undergoes some mangling to make the resulting name a namespaced valid language identifier.

For example Foo/Bar/123.txt becomes {Default Namespace}.Foo.Bar._123.txt and I have to load it with asm.GetManifestResourceStream("Yuck.Foo.Bar._123.txt").

I would much rather have my resources retain their relative path such as Foo/Bar/123.txt to better simulate a virtual file system and so I can load them such as asm.GetManifestResourceStream("Foo/Bar/123.txt").

Now I know that .Net does not place restrictions on resource names, so it seems feasible.

But how do I get the build engine to generate sensible path names for me?


Solution

  • In the .csproj file, the Embedded Resources are defined as <EmbeddedResource> items.

    These have metadata named <LogicalName> which allows overwriting the name of the resource from whatever would otherwise be generated.

    For example:

    <ItemGroup>
      <EmbeddedResource Include="Foo\Bar\123.txt">
        <LogicalName>Foo\Bar\123.txt</LogicalName>
      </EmbeddedResource>
    </ItemGroup>
    

    would generate a resource which could be loaded using asm.GetManifestResourceStream("Foo\Bar\123.txt")

    To do this for all of our embedded resources, we can add a renaming task to the .csproj file which runs before the default names are generated and explicitly assigns names of our choosing:

    <Target Name="ModifyEmbeddedResourceNames" BeforeTargets="CreateManifestResourceNames">
      <ItemGroup>
        <EmbeddedResource>
          <LogicalName>%(EmbeddedResource.Identity)</LogicalName>
        </EmbeddedResource>
      </ItemGroup>
    </Target>
    

    With this we get resources named by their Identity.