46

Is there a way in C# to get the Assembly of the calling method? (Not the current method.)

i.e. I want the executing assembly, one above in the call stack.

1
  • 3
    Edited tags; [assembly] is used for assembly-language questions. Commented Mar 29, 2011 at 21:04

6 Answers 6

64

Try this

Assembly.GetCallingAssembly();
Sign up to request clarification or add additional context in comments.

5 Comments

I want the assembly of the calling method, not the current method.
err - this will give you the assembly of the calling method, not the current method. GetExecutingAssembly gives you the assembly of the current method. Stecya is correct.
Inlining can make this unreliable - see Remarks section in msdn.microsoft.com/en-us/library/…
Then don't let it be inlined :) [MethodImplAttribute(MethodImplOptions.NoInlining)]
Be also aware of tail calls. A tail call would be for example return Assembly.GetCallingAssembly(); - which might be optimized by the compiler as well and hence return unexpected results. A tail call optimization cannot be prevented by an attribute, only by avoiding to call a function right "inline" with the return statement.
15

How about this:

StackTrace stackTrace = new StackTrace();           // get call stack

var assembly = stackTrace.GetFrame(0).GetMethod().DeclaringType.Assembly;

With help from http://www.csharp-examples.net/reflection-callstack/

4 Comments

This will break when the JIT inlines methods.
When does the JIT inline methods?
It's a JIT optimization, so it decides according to its internal implementation. Inlining can be prevented though with an attribute: stackoverflow.com/questions/5169219/…
There are ways to force a JIT compiler to avoid optimizing specific inline methods to avoid method optimization, by adding the following attribute above your method [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
7

This is what I use:

        var stackFrames = new StackTrace().GetFrames();
        if(stackFrames==null) return null;
        var executingAssembly = Assembly.GetExecutingAssembly();
        foreach (var frame in stackFrames)
        {
            var assembly = frame.GetMethod().DeclaringType.Assembly;
            if (assembly != executingAssembly)
            {
                return assembly;
            }
        }
        return null;

Comments

6

No it's not possible to reliably understand who is calling you. Some people will undoubtedly suggest a stack walk but that is unreliable due to JIT inlining. There is just no way to reliably get the method / assembly which is calling your method.

2 Comments

What about Assembly.GetCallingAssembly(), as Stecya pointed out to me earlier?
There are ways to force the JIT compiler to avoid optimizing specific inline methods to avoid method stack optimization, by adding the following attribute above your method [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
1

Wrote this to get the AssemblyInfo.cs attributes for the calling assembly -- so uses the "GetAssembly(int stackTraceLevel)" method that does what is needed...

All this is also up on my blog at http://lancelarsen.com/reading-values-from-assemblyinfo-cs/

Enjoy

/// <summary>
/// Gets the values from the AssemblyInfo.cs file for the previous assembly
/// </summary>
/// <example>
/// AssemblyInfoCalling assembly = new AssemblyInfoCalling();
/// string company1 = assembly.Company;
/// string product1 = assembly.Product;
/// string copyright1 = assembly.Copyright;
/// string trademark1 = assembly.Trademark;
/// string title1 = assembly.Title;
/// string description1 = assembly.Description;
/// string configuration1 = assembly.Configuration;
/// string fileversion1 = assembly.FileVersion;
/// Version version1 = assembly.Version;
/// string versionFull1 = assembly.VersionFull;
/// string versionMajor1 = assembly.VersionMajor;
/// string versionMinor1 = assembly.VersionMinor;
/// string versionBuild1 = assembly.VersionBuild;
/// string versionRevision1 = assembly.VersionRevision;
/// </example>
public class AssemblyInfoCalling
{
    /// <summary>
    /// Initializes a new instance of the <see cref="AssemblyInfoCalling"/> class.
    /// </summary>
    /// <param name="traceLevel">The trace level needed to get correct assembly 
    /// - will need to adjust based on where you put these classes in your project(s).</param>
    public AssemblyInfoCalling(int traceLevel = 4)
    {
        //----------------------------------------------------------------------
        // Default to "3" as the number of levels back in the stack trace to get the 
        //  correct assembly for "calling" assembly
        //----------------------------------------------------------------------
        StackTraceLevel = traceLevel;
    }

    //----------------------------------------------------------------------
    // Standard assembly attributes
    //----------------------------------------------------------------------
    public string Company { get { return GetCallingAssemblyAttribute<AssemblyCompanyAttribute>(a => a.Company); } }
    public string Product { get { return GetCallingAssemblyAttribute<AssemblyProductAttribute>(a => a.Product); } }
    public string Copyright { get { return GetCallingAssemblyAttribute<AssemblyCopyrightAttribute>(a => a.Copyright); } }
    public string Trademark { get { return GetCallingAssemblyAttribute<AssemblyTrademarkAttribute>(a => a.Trademark); } }
    public string Title { get { return GetCallingAssemblyAttribute<AssemblyTitleAttribute>(a => a.Title); } }
    public string Description { get { return GetCallingAssemblyAttribute<AssemblyDescriptionAttribute>(a => a.Description); } }
    public string Configuration { get { return GetCallingAssemblyAttribute<AssemblyDescriptionAttribute>(a => a.Description); } }
    public string FileVersion { get { return GetCallingAssemblyAttribute<AssemblyFileVersionAttribute>(a => a.Version); } }

    //----------------------------------------------------------------------
    // Version attributes
    //----------------------------------------------------------------------
    public static Version Version
    {
        get
        {
            //----------------------------------------------------------------------
            // Get the assembly, return empty if null
            //----------------------------------------------------------------------
            Assembly assembly = GetAssembly(StackTraceLevel);
            return assembly == null ? new Version() : assembly.GetName().Version;
        }
    }
    public string VersionFull { get { return Version.ToString(); } }
    public string VersionMajor { get { return Version.Major.ToString(); } }
    public string VersionMinor { get { return Version.Minor.ToString(); } }
    public string VersionBuild { get { return Version.Build.ToString(); } }
    public string VersionRevision { get { return Version.Revision.ToString(); } }

    //----------------------------------------------------------------------
    // Set how deep in the stack trace we're looking - allows for customized changes
    //----------------------------------------------------------------------
    public static int StackTraceLevel { get; set; }

    //----------------------------------------------------------------------
    // Custom Attributes
    //----------------------------------------------------------------------
    public string Location 
    { 
        get
        {
            try
            {
                return GetCallingAssemblyAttribute<AssemblyLocationAttribute>(a => a.Value);
            }
            catch (NullReferenceException)
            {
                return string.Empty;
            }

        } 
    }

    /// <summary>
    /// Gets the calling assembly attribute.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value">The value.</param>
    /// <example>return GetCallingAssemblyAttribute&lt;AssemblyCompanyAttribute&gt;(a => a.Company);</example>
    /// <returns></returns>
    private string GetCallingAssemblyAttribute<T>(Func<T, string> value) where T : Attribute
    {
        //----------------------------------------------------------------------
        // Get the assembly, return empty if null
        //----------------------------------------------------------------------
        Assembly assembly = GetAssembly(StackTraceLevel);
        if (assembly == null) return string.Empty;

        //----------------------------------------------------------------------
        // Get the attribute value
        //----------------------------------------------------------------------
        T attribute = (T) Attribute.GetCustomAttribute(assembly, typeof (T));
        return value.Invoke(attribute);
    }

    /// <summary>
    /// Go through the stack and gets the assembly
    /// </summary>
    /// <param name="stackTraceLevel">The stack trace level.</param>
    /// <returns></returns>
    private static Assembly GetAssembly(int stackTraceLevel)
    {
        //----------------------------------------------------------------------
        // Get the stack frame, returning null if none
        //----------------------------------------------------------------------
        StackTrace stackTrace = new StackTrace();
        StackFrame[] stackFrames = stackTrace.GetFrames();
        if (stackFrames == null) return null;

        //----------------------------------------------------------------------
        // Get the declaring type from the associated stack frame, returning null if nonw
        //----------------------------------------------------------------------
        var declaringType = stackFrames[stackTraceLevel].GetMethod().DeclaringType;
        if (declaringType == null) return null;

        //----------------------------------------------------------------------
        // Return the assembly
        //----------------------------------------------------------------------
        var assembly = declaringType.Assembly;
        return assembly;
    }
}

Comments

1

Came across this looking for something similar. In my case, it was Assembly.GetEntryAssembly().

Use Case

Program A runs CodeDomProvider.CompileAssemblyFromSource to embed resources and compile Program B. DLL in Program B then reads resources, but doesn't know the Assembly (which the above solves).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.