Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assembly.GetCallingAssembly isn't supported on WinRT, but is for portable class libraries?

I'm needing to get some meta-data about the assembly which calls my component. As such, using Assembly.GetCallingAssembly() seems to be a natural fit. However, I've found it works everywhere except for in Windows Store. Where it's supported:

  • Phone 7.0+
  • .Net 1.0+
  • Portable Class Libraries

However, where it's not supported is directly within a Windows Store application. I can make a portable class library and then call it from there inside of a Windows Store application, but I can't just put it directly in the Windows Store app/class library.

Is there a workaround for this or some other way to get the type of metadata provided by Assembly?

like image 903
Earlz Avatar asked Jan 23 '13 16:01

Earlz


2 Answers

Assembly.GetCallingAssembly is not exposed in WinRT - supposedly because its semantics are unreliable in the face of inlining etc (source), but it also doesn't fit too much with the restricted reflection permitted in Windows Store apps. You can get something like Assembly.GetCurrentAssembly(), eg like this:

typeof(MainPage).GetTypeInfo().Assembly

But that's not the same at all. With the restricted reflection model, obtaining a stack trace at runtime as is possible in .NET will not be possible either.

As to the portable class library, I was about to say that Assembly.GetCurrentAssembly() is supported in portable class libraries in general, but just not in WinRT - which would make sense if it's simply not in that platform. But actually, it seems that it is present in all profiles including WinRT except WinRT+.NET4.5 - it seems there must be some sort of oversight here with this inconsistency. So the method is present in WinRT (and moreover there's no sort of redirection going on), but not visible in the metadata available at compile time.

Therefore you can call the method with reflection:

var assembly = (Assembly) typeof(Assembly).GetTypeInfo()
    .GetDeclaredMethod("GetCallingAssembly")
    .Invoke(null, new object[0]);

I presume the non-visibility of this method in Windows Store apps is a "we wish this would go away".

(This answer only concerns "can I" not "should I").

like image 165
Nicholas W Avatar answered Sep 19 '22 14:09

Nicholas W


The method was cut simply because it is too unreliable in a WinRT app. A strong design goal for WinRT was to make interop between different language runtime environments simple and trouble-free. Which works well, you can easily create a WinRT component in a language like C# and have it used by an app that was written in an unmanaged language like C++ or Javascript.

This is possible as well in a desktop .NET app but it is much more complicated, having to fall back to a [ComVisible] assembly or creating a mixed-mode assembly in the C++/CLI language. Using Assembly.GetCallingAssembly() in such a case will fail as well, it is however entirely expected to fail by the programmer since he's well aware of doing something special.

That gets a lot more murky in a WinRT component. Especially since it doesn't necessary fail if the call was actually made from another .NET assembly. But no hope when it came from unmanaged code.

This random kind of failure is just utter misery without a decent workaround. Accordingly the method was cut. Using PCL is a possible workaround, but Microsoft has sternly warned in the past that such kind of hackorama is highly unrecommended. With non-zero odds that it will be caught by the store validation procedure and result in a rejection.

like image 36
Hans Passant Avatar answered Sep 20 '22 14:09

Hans Passant