How to add a glob for resx files for new SDK csproj file

Viewed 2972

If I add a new resx file to my properties folder in my new dotnetstandard 2.0 SDK project from VS2017 I see

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <EmbeddedResource Remove="Properties\foo.resx" />
  </ItemGroup>

  <ItemGroup>
    <Compile Update="Properties\MyWords.Designer.cs">
      <DesignTime>True</DesignTime>
      <AutoGen>True</AutoGen>
      <DependentUpon>MyWords.resx</DependentUpon>
    </Compile>
  </ItemGroup>

  <ItemGroup>
    <EmbeddedResource Update="Properties\MyWords.resx">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>MyWords.Designer.cs</LastGenOutput>
    </EmbeddedResource>
  </ItemGroup>


</Project>

However I'd prefer to have this handled the same way normal cs files are handled. The project is empty and the filesystem is searched. What is the globby way to achieve the above so that when I add new files they don't end up explicity declared.

My first attempt is

  <ItemGroup>
    <Compile Update="Properties\**\*.designer.cs">
      <DesignTime>True</DesignTime>
      <AutoGen>True</AutoGen>
      <DependentUpon>Properties\%(Filename).resx</DependentUpon>
    </Compile>
  </ItemGroup>

  <ItemGroup>
    <EmbeddedResource Update="Properties\**\*.resx">
      <Generator>ResXFileCodeGenerator</Generator>

    </EmbeddedResource>
  </ItemGroup>

but this won't work because

Properties\%(Filename).resx

expands to

Properties\Foo.designer.resx

instead of

Properties\Foo.resx
2 Answers

Kudos to @stijn for the direction, we took this solution a step further as it was missing the EmbeddedResource step we use during our publish to avoid disk IOPS at runtime.

Here is a similar strategy that also works with embedded resources:

RESX + Embedded Resource (MSBUILD 15 Glob-style)

  <ItemGroup>
    <Compile Include="**\*.Designer.cs">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>$([System.String]::Copy('%(FileName)').Replace('.Designer', '.resx'))</DependentUpon>
    </Compile>
    <EmbeddedResource Include="**\*.resx">
      <Generator>PublicResXFileCodeGenerator</Generator>
      <LastGenOutput>$([System.String]::Copy('%(FileName)')).Designer.cs</LastGenOutput>
    </EmbeddedResource>
  </ItemGroup>

Notes: The MSBUILD Item Metadata reference is a great resource - e.g. it tells you that %FileName excludes the extension which tripped me up initially. Also this related SO post affirms the necessity of using String.Copy.

You can use property functions on metadata so erasing the .Designer part with String.Replace should be ok:

<Compile Update="Properties\**\*.designer.cs">
  <DesignTime>True</DesignTime>
  <AutoGen>True</AutoGen>
  <DependentUpon>Properties\$([System.String]::Copy('%(FileName)').Replace('.Designer', '')).resx</DependentUpon>
</Compile>
Related