If you dont know what Pack Uris are consider yourself lucky and move along, there's nothing to see here. Otherwise here's the MSDN documentation for the Pack Uri syntax. It comprehensible but defies mastery, after something like six years I still can't build a Pack Uri off the top of my head.
Below is a helper class and sample code I use when I want to work with Pack Uris. One really nice side benefit of using the helper class is that it constructs the Uris with WPF's PackUriHelper which means the pack:// scheme parser is registered for you and you don't run into the "cannot parse pack://" problem that you sometimes see in unit tests.
namespace ConsoleApplication1
{
using System;
using System.Diagnostics;
using System.IO.Packaging;
using System.Reflection;
using System.Text;
class Program
static void Main(string[] args)
Assembly sysXmlAssembly = typeof(System.Xml.XmlNode).Assembly;
Console.WriteLine(WPFPackUriHelper.CreateLocalAssemblyPackUri(@"Resources\LocalAssemblyLogo.png"));
Console.WriteLine(WPFPackUriHelper.CreateReferencedAssemblyPackUri(sysXmlAssembly.GetName(), @"Resources\ReferencedAssemblyLogo.png"));
Console.WriteLine(WPFPackUriHelper.CreateContentFilePackUri(@"Resources\ContentFileLogo.png"));
Console.WriteLine(WPFPackUriHelper.CreateSiteOfOriginPackUri(@"Resources\SiteOfOriginLogo.png"));
Console.WriteLine("Press any key to end");
Console.ReadKey();
}
public static class WPFPackUriHelper
/// <summary>
/// Constructs a pack Uri for a resource in 'local assembly'.
/// </summary>
/// <param name="path">Path to local assembly resource</param>
/// <returns>Pack Uri for a resource in 'local assembly'</returns>
/// <remarks>
/// Based on rules enumerated at http://msdn.microsoft.com/en-us/library/aa970069(VS.85).aspx#Resource_File_Pack_URIs___Local_Assembly
/// </remarks>
public static Uri CreateLocalAssemblyPackUri(string path)
if (path == null)
throw new ArgumentNullException("path");
return Create(_applicationAuthority, path);
/// Constructs a pack Uri for a resource in a referenced assembly.
/// <param name="name">Name of referenced assembly</param>
/// <param name="path">Path to referenced assembly resource</param>
/// <returns>Pack Uri for a resource in referenced assembly</returns>
/// Based on rules enumerated at http://msdn.microsoft.com/en-us/library/aa970069(VS.85).aspx#Resource_File_Pack_URIs___Referenced_Assembly
public static Uri CreateReferencedAssemblyPackUri(AssemblyName name, string path)
if (name == null)
throw new ArgumentNullException("name");
string assemblyShortName = name.Name;
if (string.IsNullOrWhiteSpace(assemblyShortName))
throw new ArgumentException("Argument must not have null or empty name", "name");
const int averageVersionStringLength = 10; // 4 dot separators + 4 digits + 2 extra padding
const int averagePublicKeyTokenLength = 16; // 8 hex digits (2 characters per digit)
int averageAssemblySpecifierLength = assemblyShortName.Length + averageVersionStringLength + averagePublicKeyTokenLength;
StringBuilder assemblySpecifier = new StringBuilder(averageAssemblySpecifierLength);
assemblySpecifier.Append(assemblyShortName);
Version version = name.Version;
if(version != null)
assemblySpecifier.Append(';');
assemblySpecifier.Append(version.ToString());
byte[] publicKeyToken = name.GetPublicKeyToken();
if (publicKeyToken != null)
assemblySpecifier.Append(ToHexString(publicKeyToken, 0, publicKeyToken.Length));
assemblySpecifier.Append(";component");
Uri packageUri = new Uri(_applicationAuthority, assemblySpecifier.ToString());
return Create(packageUri, path);
/// Constructs a pack Uri for a 'content file' resource.
/// <param name="path">Path to content file resource</param>
/// <returns>Pack Uri for a content file resource</returns>
/// Based on rules enumerated at http://msdn.microsoft.com/en-us/library/aa970069(VS.85).aspx#Content_File_Pack_URIs
public static Uri CreateContentFilePackUri(string path)
/// Constructs a pack Uri for a 'site of origin' resource.
/// <param name="path">Path to site of origin resource</param>
/// <returns>Pack Uri for a site of origin resource</returns>
/// Based on rules enumerated at http://msdn.microsoft.com/en-us/library/aa970069(VS.85).aspx#Site_of_Origin_File_Pack_URIs
public static Uri CreateSiteOfOriginPackUri(string path)
return Create(_siteOfOriginAuthority, path);
private static Uri Create(Uri packageUri, string path)
return PackUriHelper.Create(packageUri, PackUriHelper.CreatePartUri(new Uri(path, UriKind.Relative)));
/// Converts a byte array to a hexidecimal string
/// <param name="bytes">input byte sequence</param>
/// <returns>A hexidecimal string</returns>
/// I can't believe I have to roll out my own converter but
/// the closest equivalent 'BitConvert.ToString(byte [])' pads the bytes with dashes
private static string ToHexString(byte[] bytes, int startIndex, int count)
if (bytes == null)
throw new ArgumentNullException("bytes");
if (startIndex < 0)
throw new ArgumentOutOfRangeException("startIndex");
if (startIndex >= bytes.Length)
if (count < 0)
throw new ArgumentOutOfRangeException("count");
int endIndex = startIndex + count;
if (endIndex > bytes.Length)
StringBuilder result = new StringBuilder(count * 2); // two characters per byte
for (int i = startIndex; i < endIndex; i++)
byte b = bytes[i];
result.Append(ToHexDigit(b >> 4));
result.Append(ToHexDigit(b & 0x0F));
return result.ToString();
private static char ToHexDigit(int value)
Debug.Assert(value >= 0);
Debug.Assert(value < 0x10);
return (value < 0x0A) ? ((char)('0' + value)) : ((char)('a' + (value - 0x0A)));
private static readonly Uri _applicationAuthority = new Uri("application:///.", UriKind.Absolute);
private static readonly Uri _siteOfOriginAuthority = new Uri("siteoforigin:///.", UriKind.Absolute);
This posting is provided "AS IS" with no warranties, and confers no rights.