Reputation: 11334
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
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:
Load the project as an Xml document of some sort.
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.
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.
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