ashes999
ashes999

Reputation: 10163

MissingManifestResourceException for EmbeddedResouce in Silverlight

I write Silverlight games using XNA-based Silverlight engines. I have a previous game where I have files (MP3s and text files) with Build Action set to Embedded Resource, and no *.resx file to be seen in my solution.

The game runs fine; you can see the production version here.

On the other hand, my current project doesn't allow this. When I try to make files Embedded Resources, I get a MissingManifestResourceException thrown in my constructor of the main UserControl instance that starts my app. The error message is:

Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "DeenGames.Colosseum.Content.Audio.2.mp3.resources" was correctly embedded or linked into assembly "DeenGames.Colosseum" at compile time, or that all the satellite assemblies required are loadable and fully signed.

I'm very, very, very perplexed. Setting any item's Build Action to Embedded Resource, whether MP3, text, or image, causes this exception.

How the heck do I fix (or debug) this? I'm 99% sure I do not need a .resx file, because my previous projects don't have one.

There's this lovely MSDN page which assures the world that:

In particular, Silverlight embedded resources must always use the Resource build action, and not the Embedded Resource build action, which uses a format that Silverlight cannot recognize.

But there's a well-known solution using Assembly.GetExecutingAssembly().GetManifestResourceNames(). In my case, it doesn't show me the resource if it's just a Resource; if it's an Embedded Resource, I can see the file name with dot-delimited namespace (as expected).

Download and see for yourself a very simple working example here. It has two embedded files (.2dg and .map) and compiles/runs without any exceptions OR resx file.

You can also download a broken example here. Replace FlatRedBall.dll with RadiantWrench.dll and watch the working example break. (Use ScreenController.ShowScreen and remove all FRB-referenced code.)

Upvotes: 1

Views: 1078

Answers (1)

Todd Main
Todd Main

Reputation: 29155

Embedded Resource is a WinForms technology that is depreciated in the Silverlight runtime. Instead, a build action of Resource or Content should be used instead.

When you set an item to Embedded Resource, Silverlight expects this to be a .resx file because this is what happens inside the .csproj or .vbproj file when you create a .resx and add resources to it (the file is marked as Embedded Resource for MSBuild and its resources are simply a None inside of an <ItemGroup/> that are discovered by the ResXGenerator at runtime based off the relative URI folder of "Resources"). If it isn't, it removes it or sets it as Content. You can examine Microsoft.Silverlight.Common.targets (usually in your C:\Program Files (x86)\MSBuild\Microsoft\Silverlight\v4.0 folder) to see how it changes items marked as Embedded Resource - setting to content, setting to none or setting to a .resx file.

If you're looking to just query what resources you have in the project, you could try this somewhat cumbersome approach: Enumerating embedded resources


UPDATE: In looking at your project, this is not really using an Embedded Resource the way WinForms uses this Build Action type or even .resx, per say. It uses a function from the ToolsSilverlight.dll called EmbeddedResourceFileReader.ReadFile. The code for that is:

    private static string ReadFile(string fileName, Assembly currentAssembly)
    {
        string text = EmbeddedResourceHelper.CheckAndSanitizePath(fileName);
        string result = "";
        using (Stream manifestResourceStream = currentAssembly.GetManifestResourceStream(text))
        {
            if (manifestResourceStream == null)
            {
                throw new ArgumentException("Couldn't open " + fileName + ". Make sure the file exists in that directory, and has Build Action set to Embedded Resource.");
            }
            using (StreamReader streamReader = new StreamReader(manifestResourceStream))
            {
                result = streamReader.ReadToEnd();
            }
        }
        return result;
    }

Your .csproject file lists your files as:

<ItemGroup>
    <EmbeddedResource Include="Content\Qadar.2dg" />
    <EmbeddedResource Include="Content\Maps\main.map" />
    <None Include="Properties\AppManifest.xml" />
</ItemGroup>

All this does is embed, as mentioned with the Microsoft.Silverlight.Common.targets above, your files as common Resources (at a top level, not with the list of other actual resouces) and finds a way to read them. You can decompile your DLL with ILSpy to exam that these are indeed now common Resources under the Resources folder.

So how can you do this in your new project? Replicate the exact method you did in your first one - add ToolsSilverlight.dll, list your items as Embedded Resource, and call them using EmbeddedResourceFileReader.ReadFile. You may also want to ensure your .csproj file <ItemGroup/> structure is similar to original one. Not sure if <None Include="Properties\AppManifest.xml"/> is needed by EmbeddedResourceFileReader, but it may be.

Upvotes: 0

Related Questions