Thinking of Using GetCallingAssembly? Be careful

Veliana Thong 25 Apr 2017

When trying to run a RESTful WCF service in UAT environment, we had a runtime error saying that an embedded resource could not be loaded. We didn’t have this problem locally and also not in DEV environment. We spent hours trying to replicate the problem locally. Running it in Debug mode worked fine, the exception seemed to only happen in Release mode. What made it worse was when we built a Release version and tried to debug that version, it worked fine. This must be a configuration issue, something must have changed recently that broke the UAT publish. Long story short, we managed to narrow it down to the combination of the enabling of the ‘Optimize code’ check box in Visual Studio (which was not there in the previous UAT publish) and the use of GetCallingAssembly() in the assembly that has the embedded resource.

So what does ‘Optimize code’ do and why doesn’t it work well with GetCallingAssembly()?

When code optimization is enabled, the JIT compiler moves codes around, for example it dynamically inlines some functions to eliminate the overhead of function calls speed. This means in runtime the optimization might change the code created by the JIT compiler, consequently returning a different assembly than what we had in mind when we decided to use GetCallingAssembly(). This is explained in an old MSDN documentation’s remarks:

If the method that calls the GetCallingAssembly() method is expanded inline by the compiler (that is, if the compiler inserts the function body into the emitted Microsoft intermediate language (MSIL), rather than emitting a function call), then the assembly returned by the GetCallingAssembly() method is the assembly containing the inline code. This might be different from the assembly that contains the original method. To ensure that a method that calls the GetCallingAssembly() method is not inlined by the compiler, you can apply the MethodImplAttribute attribute with MethodImplOptions.NoInlining.

Code inlining

What is code inlining? According to wikipedia:

In computing, inline expansion, or inlining, is a manual or compiler optimization that replaces a function call site with the body of the called function

Let’s illustrate this with some codes. The illustration is taken from MSDN documentation.

namespace Assembly1
{
    public Assembly Method1()
    {
        return Assembly.GetCallingAssembly();
    }
}

namespace Assembly2
{
    public Assembly Method2()
    {
        return Method1();
    }
}

namespace Assembly3
{
    public Assembly Method3()
    {
        return Method2();
    }
}

When Method1() is not inlined, GetCallingAssembly() returns Assembly2.
When Method2() is not inlined, GetCallingAssembly() returns Assembly2.

When Method1() is inlined:

namespace Assembly3
{
    public Assembly Method3()
    {
        return Method2();
    }
}

namespace Assembly2
{
    public Assembly Method2()
    {
        return Assembly.GetCallingAssembly(); // Method1() is inlined
    }
}

GetCallingAssembly() returns Assembly3.

When Method2() is inlined:

namespace Assembly3
{
    public Assembly Method3()
    {
        return Method1();  // Method2() is inlined
    }
}

namespace Assembly1
{
    public Assembly Method1()
    {
        return Assembly.GetCallingAssembly();
    }
}

GetCallingAssembly() returns Assembly3.

Conclusion

Next time you’re thinking about using GetCallingAssembly(), think again. Think of how it’s going to be used outside of your project. Is anyone going to enable code optimization? Because if this is the case, GetCallingAssembly() might return unexpected assembly. There are two ways to go about this:

  1. Make sure to apply MethodImplAttribute attribute with MethodImplOptions.NoInlining
  2. Use GetExecutingAssembly() instead because it’s not prone to JIT inlining

Further readings