Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Getting publishing information for a ClickOnce deployment

5.00/5 (2 votes)
27 Mar 2012CPOL2 min read 20.8K  
This tip describes a way to get publishing information for a ClickOnce deployed application

Introduction

Sometimes it's good to know basic information concerning a ClickOnce deployment such as publish version, where the application was installed from, name of the manifest and so on.

This tip helps to resolve this information. It's usable only for applications that have ApplicationIdentity set (such as ClickOnce deployed applications).

The code

First, the full code:

C#
/// <summary>
/// Helper class to extract identity information based on domain identity
/// </summary>
public static class PublishInfo {

  /// <summary>
  /// Types of identities
  /// </summary>
  public enum IdentityType {
     /// <summary>
     /// Deployment identity
     /// </summary>
     Deployment = 1,
     /// <summary>
     /// Application identity
     /// </summary>
     Application = 2
  }

  // Regular expressions
  private static System.Text.RegularExpressions.Regex _versionRegex = 
    new System.Text.RegularExpressions.Regex(@"Version=(?<Major>\d*)." + 
    @"(?<Minor>\d*).(?<Build>\d*).(?<Revision>\d*)", 
    System.Text.RegularExpressions.RegexOptions.Compiled);
  private static System.Text.RegularExpressions.Regex _cultureRegex = 
    new System.Text.RegularExpressions.Regex(@", Culture=(?<Culture>[^,]*),", 
    System.Text.RegularExpressions.RegexOptions.Compiled);
  private static System.Text.RegularExpressions.Regex _publicKeyTokenRegex = 
    new System.Text.RegularExpressions.Regex(@", PublicKeyToken=(?<PublicKeyToken>[^,]*),", 
    System.Text.RegularExpressions.RegexOptions.Compiled);
  private static System.Text.RegularExpressions.Regex _processorArchitectureRegex = 
    new System.Text.RegularExpressions.Regex(@", processorArchitecture=(?<ProcessorArchitecture>[^,]*)", 
    System.Text.RegularExpressions.RegexOptions.Compiled);

  /// <summary>
  /// Main uri
  /// </summary>
  public static System.Uri Uri { get; private set; }

  /// <summary>
  /// Deployment identity
  /// </summary>
  public static Identity DeploymentIdentity { get; private set; }

  /// <summary>
  /// Application identity
  /// </summary>
  public static Identity ApplicationIdentity { get; private set; }

  /// <summary>
  /// Class that holds the identity information
  /// </summary>
  public class Identity {

     /// <summary>
     /// Type of the identity
     /// </summary>
     public PublishInfo.IdentityType IdentityType { get; private set; }

     /// <summary>
     /// Version information
     /// </summary>
     public System.Version Version { get; private set; }

     /// <summary>
     /// Name of the application
     /// </summary>
     public string ApplicationName { get; private set; }

     /// <summary>
     /// Public key token
     /// </summary>
     public string PublicKeyToken { get; private set; }

     /// <summary>
     /// Processor architecture
     /// </summary>
     public System.Reflection.ProcessorArchitecture ProcessorArchitecture { get; private set; }

     /// <summary>
     /// Default constructor
     /// </summary>
     private Identity() { }

     /// <summary>
     /// Constructor
     /// </summary>
     /// <param name="identity">Identity string to parse</param>
     /// <param name="identityType">Type of the identity</param>
     internal Identity(string identity, PublishInfo.IdentityType identityType) {
        System.Text.RegularExpressions.Match regexMatch;
        System.Reflection.ProcessorArchitecture architecture;

        this.IdentityType = identityType;

        try {
           // Parse application name
           this.ApplicationName = identity.Substring(0, identity.IndexOf(','));

           // Parse version
           regexMatch = _versionRegex.Match(identity);
           this.Version = new System.Version(int.Parse(regexMatch.Groups["Major"].ToString()),
                                            int.Parse(regexMatch.Groups["Minor"].ToString()),
                                            int.Parse(regexMatch.Groups["Build"].ToString()),
                                            int.Parse(regexMatch.Groups["Revision"].ToString()));

           // Parse public key token
           regexMatch = _publicKeyTokenRegex.Match(identity);
           this.PublicKeyToken = regexMatch.Groups["PublicKeyToken"].ToString();

           // Parse processor architecture
           regexMatch = _processorArchitectureRegex.Match(identity);
           if (!System.Enum.TryParse<System.Reflection.ProcessorArchitecture>(
                   regexMatch.Groups["ProcessorArchitecture"].ToString(), true, out architecture)) {
              architecture = System.Reflection.ProcessorArchitecture.None;
           }
           this.ProcessorArchitecture = architecture;
        } catch { }
     }
  }

  /// <summary>
  /// Constructor for the PublishInfo class
  /// </summary>
  static PublishInfo() {
     string identities;
     string[] identity;

     try {
        // Get the full name of the identity
        identities = System.AppDomain.CurrentDomain.ApplicationIdentity.FullName;

        // Parse uri
        PublishInfo.Uri = new System.Uri(identities.Substring(0, identities.IndexOf('#')));
        identities = identities.Substring(identities.IndexOf('#') + 1);

        //Split the separate identities
        if (identities.IndexOf("\\") > -1) {
           identity = identities.Split('\\');
        } else {
           identity = identities.Split('/');
        }

        //Create the identity information
        PublishInfo.DeploymentIdentity = new Identity(identity[0], IdentityType.Deployment);
        PublishInfo.ApplicationIdentity = new Identity(identity[1], IdentityType.Application);
     } catch { }
  }
}

Main parts explained

The ApplicationIdentity of CurrentDomain returns a string representation for the application. This string contains three informative parts:

  1. Application URL
  2. # as a separator
  3. Deployment identity
  4. \ as a separator (1)
  5. Application identity

The PublishInfo constructor first separates the application URL and stores it statically in this class. After this the remainder of the string is splitted using the separator.

1 Even though the MSDN documentation states that \ is used as a separator, when I tested this / was the actual separator used. For this reason both variations are implemented in the code.

The Identity class holds the information for individual identity, application or deployment. In the constructor of this class the key information is parsed from the identity string and placed on proper properties such as Version.

The properties of the Identity class are:

  • IdentityType: Which type of identity is this: Application or Deployment
  • ApplicationName: either the application name or the deployment manifest name depending on the identity type
  • Version: Version for the identity described using System.Version class
  • PublicKeyToken: Public key token of the identity
  • ProcessorArchitecture: Processor architecture of the identity, described using System.Reflection.ProcessorArchitecture enumeration

Using the class

As an example of the usage of the class I wrote the property values of both identities to output window of Visual Studio using Debug class:

C#
System.Diagnostics.Debug.WriteLine("Uri: " + PublishInfo.Uri.ToString());
System.Diagnostics.Debug.WriteLine("");
System.Diagnostics.Debug.WriteLine("DeploymentIdentity");
System.Diagnostics.Debug.WriteLine("------------------");
System.Diagnostics.Debug.WriteLine("ApplicationName: " + PublishInfo.DeploymentIdentity.ApplicationName);
System.Diagnostics.Debug.WriteLine("Version: " + PublishInfo.DeploymentIdentity.Version.ToString());
System.Diagnostics.Debug.WriteLine("PublicKeyToken: " + PublishInfo.DeploymentIdentity.PublicKeyToken);
System.Diagnostics.Debug.WriteLine("ProcessorArchitecture: " + 
       PublishInfo.DeploymentIdentity.ProcessorArchitecture.ToString());
System.Diagnostics.Debug.WriteLine("");
System.Diagnostics.Debug.WriteLine("ApplicationIdentity");
System.Diagnostics.Debug.WriteLine("-------------------");
System.Diagnostics.Debug.WriteLine("ApplicationName: " + PublishInfo.ApplicationIdentity.ApplicationName);
System.Diagnostics.Debug.WriteLine("Version: " + PublishInfo.ApplicationIdentity.Version.ToString());
System.Diagnostics.Debug.WriteLine("PublicKeyToken: " + PublishInfo.ApplicationIdentity.PublicKeyToken);
System.Diagnostics.Debug.WriteLine("ProcessorArchitecture: " + 
       PublishInfo.ApplicationIdentity.ProcessorArchitecture.ToString());

The results were like

Uri: file:///C:/Temp/publish/Tester.application

DeploymentIdentity
------------------
ApplicationName: Tester.application
Version: 1.0.0.9
PublicKeyToken: 79481f74d589e5cd
ProcessorArchitecture: X86

ApplicationIdentity
-------------------
ApplicationName: Tester.exe
Version: 1.0.0.9
PublicKeyToken: 79481f74d589e5cd
ProcessorArchitecture: X86 

Note that if you're running the program from Visual Studio, you'll get different results, such as

Uri: http://tempuri.org/Tester.application

DeploymentIdentity
------------------
ApplicationName: Tester.application
Version: 1.0.0.9
PublicKeyToken: 0000000000000000
ProcessorArchitecture: X86

ApplicationIdentity
-------------------
ApplicationName: DomainIdentity.exe
Version: 1.0.0.9
PublicKeyToken: 0000000000000000
ProcessorArchitecture: X86 

Also note that if the application hasn't been deployed yet, ApplicationIdentity is null so both identities in the static helper class are null.

History

  • March 27, 2012: Tip created.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)