Team LiB
Previous Section Next Section

Embedding Content and Resources in Assemblies

The previous section discussed embedded and linked files. When you create an assembly, the manifest informs the Common Language Runtime of all dependent files. If you want to make sure that a specific icon, image, text file, or whatever file you need, is considered a necessary part of your application, you can make it a part of your assembly.

There are two ways to make a file part of your assembly. You can either embed the file directly into the assembly, or you can make the assembly refer to the file via the manifest. When using Visual Studio .NET, it is actually quite easy to create embedded resources, so that's what will be covered in this next section.

Keep in mind that you can store absolutely anything as an embedded resource. Neither Visual Studio .NET nor the Common Language Runtime cares what information you're storing. Whenever you get a resource out of a loaded assembly, you get it as a stream (part of System.IO). This stream can contain any kind of data, including binary data for images, text data for XML, culture-specific string tables, and much more.

For this example, assume that you've decided that you want to add some kind of read-only set of data to your assembly. Perhaps you want to store a table of ZIP Code and county lookups, state names, or any other kind of large set of read-only data that you want to distribute with your application but you don't want to expose in some accessible format, such as Access or Excel.

Add a new item to the AssemblyIntro project, select XML File, and call it EmbeddedData.xml. Set its contents to the following:

<?xml version="1.0" encoding="utf-8" ?> 
    <DataNode id="21">
      <DataValue>This is a data value</DataValue>
    <DataNode id="35">
      <DataValue>This is another data value</DataValue>

In that file's properties panel, set the build action to Embedded Resource. This instructs Visual Studio .NET to compile the file directly into the assembly. This is extremely important because if the file is not marked as an embedded resource, it will not be linked and will not appear in the compiled assembly.

To get at the embedded data, you need to make use of some more reflection. Listing 12.3 shows the new AssemblyTool class and a new method, GeTDataNodeValue, to retrieve data nodes from the preceding XML.

Listing 12.3. The New AssemblyTool Class, Modified for Embedded Resources
using System;
using System.IO;
using System.Xml;
using System.Reflection;
using System.Text;

namespace SAMS.CSharpUnleashed.Chapter12.AssemblyIntro
  /// <summary>
  /// This is the AssemblyTool sample class
  /// </summary>
  public class AssemblyTool
    private static XmlDocument doc = null;

    public AssemblyTool()


    public static string GetAssemblyInfo()
      // gets the Assembly in which this code is executing, not
      // necessarily the Assembly of the main executable (EX
      Assembly thisAssembly = Assembly.GetExecutingAssembly();
      AssemblyName thisName = thisAssembly.GetName();
      StringBuilder sb = new StringBuilder();
      sb.AppendFormat("Assembly Name: {0}\n", thisAssembly.FullName);
      sb.AppendFormat("Assembly Version: {0}\n", thisName.Version.ToString());
      sb.AppendFormat("Assembly Culture: {0}\n", thisName.CultureInfo.ToString());
      return sb.ToString();

    private static void LoadEmbeddedDoc()
      Assembly thisAssembly = Assembly.GetExecutingAssembly();
      Stream s = thisAssembly.GetManifestResourceStream(
      doc = new XmlDocument();
      doc.Load( s );

    public static string GetDataNodeValue( int nodeId )
      if (doc == null)

      XmlNode node = doc.SelectSingleNode(
      string.Format("//DataNode[@id='{0}']", nodeId ) );
      if (node != null)
        return node.InnerText;
        return "No node found";


The first new method, LoadEmbeddedDoc, uses GetManifestResourceStream to obtain a stream for the embedded XML document. Remember this method because you'll use it nearly every time you try to grab embedded data from an assembly. The second method, GeTDataNodeValue, first checks to see whether XmlDocument is null.


Reflection operations are typically very costly in terms of time and processor consumption. If at all possible, store the results of reflection operations to avoid repetitive and redundant calls. In this case, the XML document is cached so that throughout the lifetime of the application process, the reflection operation is performed only once.

If the document is null, the LoadEmbeddedDoc method is invoked. Then some XPath is used to find the appropriate DataNode element and return its value.

Add the following few lines of test code to the main class to exercise the new code sections:

Console.WriteLine( AssemblyTool.GetDataNodeValue(21) );
Console.WriteLine( AssemblyTool.GetDataNodeValue(35) );
Console.WriteLine( AssemblyTool.GetDataNodeValue(50) );

Build the application again and run it, and you should see the following three new lines of text:

This is a data value
This is another data value
No node found

You might be wondering how this might actually be useful for you. If you are thinking about monolithic applications or large installs on DVD-ROMs, it might not seem all that useful. However, the situation changes if you think modular. In a situation in which your application relies on data embedded in an assembly and your application is configured for dynamic updates from the Internet, you can easily imagine a scenario where you could simply make changes to the embedded XML (or text files, or images, or language-specific strings, and so on) and they would propagate to your application (be it web-based or Windows-based) seamlessly. XML resources can also expose to other applications complex data structures to allow for in-depth processing, such as exposing an identity to an application that supports plug-ins (creating plug-ins will be covered at the end of this chapter).

    Team LiB
    Previous Section Next Section