PhD
PhD

Reputation: 11334

How to programmatically make an autogenerated file an embedded resource in visual studio?

I have a convoluted workflow like this: A build of one of the projects in Visual Studio (2013) leads to generation of XML files. These files are used by another project, as part of the framework.

However, for the XML files to be of any use, they're to be marked as embedded resource - currently done via the VS UI/form via the file's properties. This is good for manually added files.

But how do I programmatically make an autogenerated XML file an embedded resource, so that the next project can just pick it up (in a sense) and have the files be embedded in the corresponding DLL?

My current guess is to programmatically edit the .csproj file and add lines similar to the one below:

<EmbeddedResource Include="Path\To\File\MyEmbeddedResource.meta.xml" />

Is that it?

Upvotes: 2

Views: 1567

Answers (1)

Corey
Corey

Reputation: 16574

You can achieve this using a linked item and - if they are both part of the same solution - an appropriate set of build dependencies.

First, build the project so that the XML file you want to add as a resource is created.

Next, in the project you want to embed the XML into, right click on the project in the Solution Explorer, choose 'Add Existing' and browse for the XML file. Before hitting the 'Add' button in the browser, click on the drop-down button to the right of it and select 'Add As Link'. This will ensure that the file will always be the current one.

Select the added file link and change the build type to 'Embedded Resource'.

Assuming that your XML comes from a project in the same solution (ignore this bit if not), then in the solution properties under Project Dependencies you can set the destination project (where the resource will go) to depend on the source project that builds the XML file.

Or, if you prefer, you can add the link yourself:

<EmbeddedResource Include="Path\To\File\MyEmbeddedResource.meta.xml">
    <Link>MyEmbeddedResource.meta.xml</Link>
</EmbeddedResource>

EDIT: after discussions...

As mentioned in the comments below, if you want to do this by direct manipulation of a project file you will need to do the following:

  1. Load the project as an Xml document of some sort.

  2. Locate the ItemGroup node that contains the project's file list, which will generally be the only one in the project that contains at least one Compile nodes.

  3. For each file, insert a new EmbedResource node with an optional Link node. The Link node is not required but this is what you get when you manually add a linked file.

  4. Save the file.

Seems fairly simple. My Xml is a bit rusty, but this code produces the exact output I was after:

// required 'using' directives: System.IO, System.Xml.Linq

public static void EmbedResourceFiles(string projectFilename, IEnumerable<string> fileList, bool makeLinks = true)
{
    // This is the namespace used by the .csproj Xml file
    XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003";
    // 1: Open the document
    XDocument project = XDocument.Load(projectFilename);

    // 2: Locate target ItemGroup
    var itemGroup = project.Descendants(ns + "Compile").FirstOrDefault()?.Parent;
    if (itemGroup == null)
        throw new Exception("Failed to locate correct ItemGroup node in project file");

    // 3: Insert EmbedResource nodes
    foreach (var file in fileList)
    {
        var node = new XElement(ns + "EmbeddedResource", new XAttribute("Include", file));
        if (makeLinks)
            node.Add(new XElement(ns + "Link", Path.GetFileName(file)));
        itemGroup.Add(node);
    }

    // 4: Save it, keeping a backup just in case.
    File.Copy(projectFilename, projectFilename + ".bak", true);
    project.Save(projectFilename);
}

Gather the file list however you want and pass the list to the method above. If you want to suppress creation of <Link> nodes, give it a 'false' in the third parameter. I did a few tests and it doesn't seem to make any difference either way.

Hopefully this resolves your question.

Upvotes: 3

Related Questions