3

I have a project which embeds some files into it, two of which ends with .SMS.something. When the project is compiled, a satellite assembly for the "SMS" culture is generated even though I have not specified anywhere that I want to use satellite assemblies, and is it even a culture?

I have searched all over the place for an explanation, but I am at a loss. The only things I found were people trying to embed their resource assemblies for actual cultures into their executable, but this is not my case. I just want to have all my embedded resources, which are only in one language, to be in the same assembly.

How can I prevent this automatic generation of satellite assemblies, or specify that SMS is not a culture?

Sense545
  • 494
  • 4
  • 14
  • The build system doesn't get an explicit clue from the project that a .resx file needs to be turned into a satellite assembly. Except one, the filename format. You are tripping up that logic by using periods in the filename. Pick a name, any name, just not one that *resembles* a localizable .resx file. – Hans Passant Dec 03 '14 at 13:16
  • The file name does not end with .resx, and must contain periods. I'm currently making some progress by trying to override some stuff in the build process. Will post an answer if I find a working solution. – Sense545 Dec 03 '14 at 13:45

1 Answers1

5

I managed to solve this in a very hacky put perfectly working way by looking in the Microsoft.Common.targets and Microsoft.CSharp.targets and figuring out what tasks actually sorted the resources and gave them names.

So I override the CreateCSharpManifestResourceName task with one that set the ManifestResourceName and LogicalName to be something along the lines of what i want:

<!-- Overriding this task in order to set ManifestResourceName and LogicalName -->
<UsingTask TaskName="CreateCSharpManifestResourceName" TaskFactory="CodeTaskFactory"
           AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
  <ParameterGroup>
    <ResourceFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]"
                   Required="true" />
    <RootNamespace ParameterType="System.String"
                   Required="true" />
    <PrependCultureAsDirectory
                   ParameterType="System.Boolean" />
    <ResourceFilesWithManifestResourceNames
                   ParameterType="Microsoft.Build.Framework.ITaskItem[]"
                   Output="true" />
  </ParameterGroup>
  <Task>
    <Code Type="Fragment" Language="cs">
      foreach (ITaskItem item in ResourceFiles) {
        var link = item.GetMetadata("Link").Replace("\\", "/");
        link = "/" + link.TrimStart('/');
        item.SetMetadata("ManifestResourceName", link);
        item.SetMetadata("LogicalName", link);
      }
      ResourceFilesWithManifestResourceNames = ResourceFiles;
    </Code>
  </Task>
</UsingTask>

As an added bonus, the files i embed get their actual path (only with \ replaced with /) as their resource name, and thus can be easily looked up using Assembly.GetManifestResourceStream(x) where x would be e.g. /path.to/my.SMS.file.

And then I override the AssignCulture task with one that just returns that none of the files had any culture, and adds <WithCulture>false</WithCulture> to them (which fits perfectly in my case):

<!-- Overriding this task to set WithCulture and sort them as not having culture -->
<UsingTask TaskName="AssignCulture" TaskFactory="CodeTaskFactory"
           AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
  <ParameterGroup>
    <Files ParameterType="Microsoft.Build.Framework.ITaskItem[]"
           Required="true" />
    <AssignedFilesWithCulture
           ParameterType="Microsoft.Build.Framework.ITaskItem[]"
           Output="true" />
    <AssignedFilesWithNoCulture
           ParameterType="Microsoft.Build.Framework.ITaskItem[]"
           Output="true" />
    </ParameterGroup>
    <Task>
        <Code Type="Fragment" Language="cs">
            ITaskItem[] withCulture = new ITaskItem[Files.Length];
            ITaskItem[] withoutCulture = new ITaskItem[Files.Length];
            for (var i = 0; i &lt; Files.Length; i++) {
                ITaskItem item = Files[i];
                var wc = item.GetMetadata("WithCulture");
                if (wc == "") { item.SetMetadata("WithCulture", "False"); }
                if (wc.ToLowerInvariant() == "true") {
                    withCulture[i] = item;
                } else {
                    withoutCulture[i] = item;
                }
                var type = item.GetMetadata("Type");
                if (type == "") { item.SetMetadata("Type", "Non-Resx"); }
            }
            AssignedFilesWithCulture = withCulture;
            AssignedFilesWithNoCulture = withoutCulture;
        </Code>
    </Task>
</UsingTask>
Sense545
  • 494
  • 4
  • 14