72

In my program, how can I read the properties set in AssemblyInfo.cs:

[assembly: AssemblyTitle("My Product")]
[assembly: AssemblyDescription("...")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Radeldudel inc.")]
[assembly: AssemblyProduct("My Product")]
[assembly: AssemblyCopyright("Copyright @ me 2008")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

I'd like to display some of these values to the user of my program, so I'd like to know how to load them from the main program and from komponent assemblies I'm using.

starblue
  • 55,348
  • 14
  • 97
  • 151
Sam
  • 28,421
  • 49
  • 167
  • 247

8 Answers8

71

This is reasonably easy. You have to use reflection. You need an instance of Assembly that represents the assembly with the attributes you want to read. An easy way of getting this is to do:

typeof(MyTypeInAssembly).Assembly

Then you can do this, for example:

object[] attributes = assembly.GetCustomAttributes(typeof(AssemblyProductAttribute), false);

AssemblyProductAttribute attribute = null;
if (attributes.Length > 0)
{
   attribute = attributes[0] as AssemblyProductAttribute;
}

Referencing attribute.Product will now give you the value you passed to the attribute in your AssemblyInfo.cs. Of course, if the attribute you look for can occur more than once, you may get multiple instances in the array returned by GetCustomAttributes, but this is not usually an issue for assembly level attributes like the ones you hope to retrieve.

Jeff Yates
  • 61,417
  • 20
  • 137
  • 189
  • 5
    You can also use Assembly.GetExecutingAssembly().GetCustomAttributes() to get the attributes of the currently executing assembly. – jop Oct 09 '08 at 14:30
  • 1
    Note that if you're reading attributes for an assembly that isn't loaded, the process of loading cannot be undone unless a separate AppDomain is used and then unloaded. – Drew Noakes Oct 22 '08 at 11:13
  • 4
    GetExecutingAssembly doesn't always give what you want (for example, it can return the debugger if the debugger started your application). – Jeff Yates Dec 30 '09 at 14:04
  • 1
    Isnt it: Assembly.GetAssembly(typeof(MyTypeInAssembly)) ? (possibly changed over the versions?) – bytedev Dec 15 '16 at 15:37
  • @nashwan Good catch. There was no change; I just wrote `GetAssembly()` instead of `Assembly`. – Jeff Yates Dec 23 '16 at 16:16
15

I've created this extension method that uses Linq:

public static T GetAssemblyAttribute<T>(this System.Reflection.Assembly ass) where T :  Attribute
{
    object[] attributes = ass.GetCustomAttributes(typeof(T), false);
    if (attributes == null || attributes.Length == 0)
        return null;
    return attributes.OfType<T>().SingleOrDefault();
}

and then you can conveniently use it like that:

var attr = targetAssembly.GetAssemblyAttribute<AssemblyDescriptionAttribute>();
if(attr != null)
     Console.WriteLine("{0} Assembly Description:{1}", Environment.NewLine, attr.Description);
dmihailescu
  • 1,625
  • 17
  • 15
  • An excellent utility method. A quick hint for those interested in getting the version of an assembly. Use: assembly.GetAssemblyAttribute() (details: http://stackoverflow.com/questions/1144525/getcustomattribute-returns-null-for-assemblyversionattribute) – XDS Oct 27 '14 at 16:36
  • For those finding this later, this extension method has been part of [.NET since 4.5](https://learn.microsoft.com/en-us/dotnet/api/system.reflection.customattributeextensions.getcustomattribute?view=net-6.0#system-reflection-customattributeextensions-getcustomattribute-1(system-reflection-assembly)) – canton7 Jan 12 '22 at 16:46
10

I personally really like the implementation of lance Larsen and his static AssemblyInfo class.

One basically pastes the class in his assembly (I usually use the already existing AssemblyInfo.cs file as it fits naming convention)

The code to paste is:

internal static class AssemblyInfo
{
    public static string Company { get { return GetExecutingAssemblyAttribute<AssemblyCompanyAttribute>(a => a.Company); } }
    public static string Product { get { return GetExecutingAssemblyAttribute<AssemblyProductAttribute>(a => a.Product); } }
    public static string Copyright { get { return GetExecutingAssemblyAttribute<AssemblyCopyrightAttribute>(a => a.Copyright); } }
    public static string Trademark { get { return GetExecutingAssemblyAttribute<AssemblyTrademarkAttribute>(a => a.Trademark); } }
    public static string Title { get { return GetExecutingAssemblyAttribute<AssemblyTitleAttribute>(a => a.Title); } }
    public static string Description { get { return GetExecutingAssemblyAttribute<AssemblyDescriptionAttribute>(a => a.Description); } }
    public static string Configuration { get { return GetExecutingAssemblyAttribute<AssemblyConfigurationAttribute>(a => a.Configuration); } }
    public static string FileVersion { get { return GetExecutingAssemblyAttribute<AssemblyFileVersionAttribute>(a => a.Version); } }

    public static Version Version { get { return Assembly.GetExecutingAssembly().GetName().Version; } }
    public static string VersionFull { get { return Version.ToString(); } }
    public static string VersionMajor { get { return Version.Major.ToString(); } }
    public static string VersionMinor { get { return Version.Minor.ToString(); } }
    public static string VersionBuild { get { return Version.Build.ToString(); } }
    public static string VersionRevision { get { return Version.Revision.ToString(); } }

    private static string GetExecutingAssemblyAttribute<T>(Func<T, string> value) where T : Attribute
    {
        T attribute = (T)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(T));
        return value.Invoke(attribute);
    }
}

You add a using System; to the top of the file and you're good to go.

For my applications i use this class to set/get/work with my local users settings using:

internal class ApplicationData
{

    DirectoryInfo roamingDataFolder;
    DirectoryInfo localDataFolder;
    DirectoryInfo appDataFolder;

    public ApplicationData()
    {
        appDataFolder = new DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), AssemblyInfo.Product,"Data"));
        roamingDataFolder = new DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),AssemblyInfo.Product));
        localDataFolder   = new DirectoryInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), AssemblyInfo.Product));

        if (!roamingDataFolder.Exists)            
            roamingDataFolder.Create();

        if (!localDataFolder.Exists)
            localDataFolder.Create();
        if (!appDataFolder.Exists)
            appDataFolder.Create();

    }

    /// <summary>
    /// Gets the roaming application folder location.
    /// </summary>
    /// <value>The roaming data directory.</value>
    public DirectoryInfo RoamingDataFolder => roamingDataFolder;


    /// <summary>
    /// Gets the local application folder location.
    /// </summary>
    /// <value>The local data directory.</value>
    public DirectoryInfo LocalDataFolder => localDataFolder;

    /// <summary>
    /// Gets the local data folder location.
    /// </summary>
    /// <value>The local data directory.</value>
    public DirectoryInfo AppDataFolder => appDataFolder;
}

Have a look at Larsens website (MVP), he has cool stuff to draw Inspiration from.

DeadlyChambers
  • 5,217
  • 4
  • 44
  • 61
Walter Verhoeven
  • 3,867
  • 27
  • 36
10

Ok, perhaps a bit out of date now for the original question but I will present this for future reference anyway.

If you want to do it from inside the assembly itself then use the following :

using System.Runtime.InteropServices;
using System.Reflection;

object[] customAttributes = this.GetType().Assembly.GetCustomAttributes(false);

You can then iterate through all of the custom attributes to find the one(s) you require e.g.

foreach (object attribute in customAttributes)
{
  string assemblyGuid = string.Empty;    

  if (attribute.GetType() == typeof(GuidAttribute))
  {
    assemblyGuid = ((GuidAttribute) attribute).Value;
    break;
  }
}
ccellar
  • 10,326
  • 2
  • 38
  • 56
  • I'd like to use the Copyright. It is not in the list of attributes parallel to GuidAttribute at http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.aspx – AnneTheAgile May 21 '13 at 16:33
  • (sorry, cannot edit my other comment) This is great, I see System.Reflection.Assembly* has all the usual Attributes and many I had not known about. http://msdn.microsoft.com/en-us/library/system.attribute.aspx To use the Copyright, this worked; aCopyright = ((AssemblyCopyrightAttribute) attribute).Copyright.ToString(); – AnneTheAgile May 21 '13 at 17:04
8

Okay, I tried to go through many resources to find a method to extract .dll attributes for an Assembly.LoadFrom(path). But unfortunately, I couldn't find any good resources. And this question was the top most result for searching on c# get assembly attributes (For me at least) So I thought of sharing my work.

I wrote the following simple Console Program to retrieve general assembly attributes after many hours of struggle. Here I have provided the code so anyone can use it for further reference work.

I use CustomAttributes property for this. Feel free to comment on this approach

Code :

using System;
using System.Reflection;

namespace MetaGetter
{
    class Program
    {
        static void Main(string[] args)
        {
            Assembly assembly = Assembly.LoadFrom("Path to assembly");

            foreach (CustomAttributeData attributedata in assembly.CustomAttributes)
            {
                Console.WriteLine(" Name : {0}",attributedata.AttributeType.Name);

                foreach (CustomAttributeTypedArgument argumentset in attributedata.ConstructorArguments)
                {
                    Console.WriteLine("   >> Value : {0} \n" ,argumentset.Value);
                }
            }
       
            Console.ReadKey();
        }
    }
}

Sample Output :

Name : AssemblyTitleAttribute
   >> Value : "My Product"
Kavindu Dodanduwa
  • 12,193
  • 3
  • 33
  • 46
  • 1
    I would point out that the [`CustomAttributes` property](https://msdn.microsoft.com/en-us/library/system.reflection.assembly.customattributes%28v=vs.110%29.aspx) is only available from .NET 4.5 and above. In .NET 4.0 and above, the [`GetCustomAttributesData()` method](https://msdn.microsoft.com/en-us/library/system.reflection.assembly.getcustomattributesdata%28v=vs.100%29.aspx) is available as an alternative. – Wai Ha Lee Oct 13 '15 at 11:26
3

This is a great way to retrieve specific attributes in a single line of code. No special class required.

string company = ((AssemblyCompanyAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(AssemblyCompanyAttribute), false)).Company;
Randall Deetz
  • 512
  • 4
  • 25
  • Code-only answers frequently get flagged as 'low quality posts'! So, maybe you could add a few words of explanation? – Adrian Mole Oct 02 '19 at 04:59
  • 1
    @Adrian: Pretty self-explanatory. If I only need a single attribute, this is the way to go. Thanks for the feedback. – Randall Deetz Oct 03 '19 at 04:22
2

I use this:

public static string Title
{
    get
    {
        return GetCustomAttribute<AssemblyTitleAttribute>(a => a.Title);
    }
}

for reference:

using System;
using System.Reflection;
using System.Runtime.CompilerServices;



namespace Extensions
{


    public static class AssemblyInfo
    {


        private static Assembly m_assembly;

        static AssemblyInfo()
        {
            m_assembly = Assembly.GetEntryAssembly();
        }


        public static void Configure(Assembly ass)
        {
            m_assembly = ass;
        }


        public static T GetCustomAttribute<T>() where T : Attribute
        {
            object[] customAttributes = m_assembly.GetCustomAttributes(typeof(T), false);
            if (customAttributes.Length != 0)
            {
                return (T)((object)customAttributes[0]);
            }
            return default(T);
        }

        public static string GetCustomAttribute<T>(Func<T, string> getProperty) where T : Attribute
        {
            T customAttribute = GetCustomAttribute<T>();
            if (customAttribute != null)
            {
                return getProperty(customAttribute);
            }
            return null;
        }

        public static int GetCustomAttribute<T>(Func<T, int> getProperty) where T : Attribute
        {
            T customAttribute = GetCustomAttribute<T>();
            if (customAttribute != null)
            {
                return getProperty(customAttribute);
            }
            return 0;
        }



        public static Version Version
        {
            get
            {
                return m_assembly.GetName().Version;
            }
        }


        public static string Title
        {
            get
            {
                return GetCustomAttribute<AssemblyTitleAttribute>(
                    delegate(AssemblyTitleAttribute a)
                    {
                        return a.Title;
                    }
                );
            }
        }

        public static string Description
        {
            get
            {
                return GetCustomAttribute<AssemblyDescriptionAttribute>(
                    delegate(AssemblyDescriptionAttribute a)
                    {
                        return a.Description;
                    }
                );
            }
        }


        public static string Product
        {
            get
            {
                return GetCustomAttribute<AssemblyProductAttribute>(
                    delegate(AssemblyProductAttribute a)
                    {
                        return a.Product;
                    }
                );
            }
        }


        public static string Copyright
        {
            get
            {
                return GetCustomAttribute<AssemblyCopyrightAttribute>(
                    delegate(AssemblyCopyrightAttribute a)
                    {
                        return a.Copyright;
                    }
                );
            }
        }



        public static string Company
        {
            get
            {
                return GetCustomAttribute<AssemblyCompanyAttribute>(
                    delegate(AssemblyCompanyAttribute a)
                    {
                        return a.Company;
                    }
                );
            }
        }


        public static string InformationalVersion
        {
            get
            {
                return GetCustomAttribute<AssemblyInformationalVersionAttribute>(
                    delegate(AssemblyInformationalVersionAttribute a)
                    {
                        return a.InformationalVersion;
                    }
                );
            }
        }



        public static int ProductId
        {
            get
            {
                return GetCustomAttribute<AssemblyProductIdAttribute>(
                    delegate(AssemblyProductIdAttribute a)
                    {
                        return a.ProductId;
                    }
                );
            }
        }


        public static string Location
        {
            get
            {
                return m_assembly.Location;
            }
        }

    }

}
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
  • public static int ProductId { get { return GetCustomAttribute( delegate(AssemblyProductIdAttribute a) { return a.ProductId; } ); } } Here, `AssemblyProductIdAttribute' Error -> The type or namespace name 'AssemblyProductIdAttribute' could not be found (are you missing a using directive or an assembly reference?) – Pritam May 01 '17 at 06:02
  • Pritam: You're missing the namespace System.Reflection (using System.Reflection;), or you're on a odd framework edition/version. https://msdn.microsoft.com/en-us/library/system.reflection.assemblyproductattribute(v=vs.110).aspx – Stefan Steiger May 02 '17 at 07:08
  • __using System.Reflection__ is included in code, I can easily use other functions. None of them give any error. Also, Framework is also correct. – Pritam May 02 '17 at 09:07
  • @Pritam: Are you on .NET Core ? Because this should be from 1.1 to 4.* including in Silverlight. Yes, just tried - that attribute is not available in .NET Core. – Stefan Steiger May 02 '17 at 11:42
  • 1
    Also, for .NET Core, it's: public static T GetCustomAttribute() where T : Attribute { IEnumerable customAttributes = m_assembly.GetCustomAttributes(); foreach (Attribute thisAttribute in customAttributes) { return (T)((object)thisAttribute); } return default(T); } – Stefan Steiger May 02 '17 at 11:49
2

If you know the attribute you are looking for is unique, it is much easier to use this often overlooked static helper method of the Attribute class:

var attribute = Attribute.GetCustomAttribute(assembly, typeof(AssemblyTitleAttribute))

This is easier because you don't need to mess around with arrays, or worry about that pesky inherit parameter. You just get the single attribute value directly, or null if none exists.

glopes
  • 4,038
  • 3
  • 26
  • 29