Assembly.Load - is it possible?

StuartLodgeStuartLodge Stuart LodgeUSBeta ✭✭✭
edited March 2013 in iOS

This is a follow-up to last September's post http://stackoverflow.com/questions/12401588/can-you-use-assembly-load-in-monotouch


In MvvmCross I load plugins - which are basically just a formal way of doing IoC

These plugins are compiled and linked statically in the app - they are not downloaded at runtime.

Ideally I'd like to get references to the code inside these plugins using Assembly.Load - but I just can't get it to work.

I've tried:

  • Cirrious.MvvmCross.Plugins.Location.Touch (this version works on WP, WPF and RT)
  • Cirrious.MvvmCross.Plugins.Location.Touch.dll (this version works on Droid)
  • Cirrious.MvvmCross.Plugins.Location.Touch, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

But I always get FileNotFoundException back.


If I reference a type in the DLL first (in normal code) so that the assembly is already loaded then the Assembly.Load statement succeeds - but otherwise no luck.


Am I just doomed to failure on this? Or is there some magic combination of assemblyname, filename and/or project setting that can make it work?

Stuart

Posts

  • HuGuangYuHuGuangYu Hu Guang Yu CNMember, Beta

    I think the Xamarin Team just disabled this kind of work in Monotouch compiler to follow Apple's rule.

  • StuartLodgeStuartLodge Stuart Lodge USBeta ✭✭✭

    Thanks @Simon

    But just to be clear, this isn't about dynamically loading new modules - this is about loading assemblies that ship within the package - which should work according to @poupou in that StackOverflow answer (Unless I'm wrong, I think @poupou is a Xamarin coding genius - sometimes also known as @spouliot ?)

  • HuGuangYuHuGuangYu Hu Guang Yu CNMember, Beta

    I think it's possible for monodroid, but not monotouch.

  • NicWiseNicWise Nic Wise NZMember, Insider ✭✭✭

    @stuartlodge

    I think you have to link it at compile/build/AOT time. You can't load an assembly by name, because everything is loaded - or if not, it can't BE loaded. I'd expect Assembly.Load to fail all the time - I'm not sure why it works even sometimes!

    MonoDroid can do it 'cos you are running a full mono framework with JITer, I think. Monotouch is NOT - there is no JIT, if it's not compiled into your app, it doesn't exist. I suspect the "use it first" thing registers that your assembly is in memory now (Even tho, technically, it was before) so Assembly.Load matches something it has registered, and doesn't check the disk. Same as if you did Assembly.Load twice in a normal framework - the second time would be "oh, I have it already, here you go"

    And yes @poupou is Sebastian, who, along with @rolf, is one of the main X.iOS developers (not sure if there is more - others do bits, eg @jstedfast - but I think those 2 are the 2 core guys. But then add in @kumpera, Marek Safar, Zoltan, Mark.... who tend to do the more low level "we put this in register X so we don't get a cache miss", GC, etc type stuff)

    I'm also sure I've missed more than one someone. If so, SORRY!

    @jonp and @eno are the same for X.Android.

  • StuartLodgeStuartLodge Stuart Lodge USBeta ✭✭✭

    Thanks @nicwise who is also @fastchicken - top work in making sure everyone gets this flagged in their inbox ;)

    I'm with you on 'I'm not sure why it works even sometimes!' - that's why I gave up on it back last September... However, recent comments from @dsplaisted have given me new ideas and hope... so I thought I'd check...

    Stuart

  • NicWiseNicWise Nic Wise NZMember, Insider ✭✭✭

    @stuartlodge FLAG EVERYONE IN THEIR INBOXES!

  • SebastienPouliotSebastienPouliot Sebastien Pouliot CAMember, Xamarin Team Xamurai

    @StuartLodge This has not changed recently. IOW you cannot load new (as in not AOT compiled) assemblies.

    Now Assembly.Load* methods (there's many and they all differs a bit) don't really load assemblies if they were already loaded (e.g. by the runtime).

    That's why it will works (Load will return non-null) if you had used a type from that assembly earlier. The runtime load the assembly structures and that will make the Assembly available when Load* is called. E.g.

    string filename = Path.GetFileName (GetType ().Assembly.Location);
    Assembly assembly = Assembly.LoadFile (filename);
    

    There must be a type reference between you main .exe and the .dll you want, right ? otherwise the assembly loader would not AOT (and copy) those assemblies inside the final application. Is there anything you known from the assemblies that could be used to jumpstart the runtime into loading them ? (before you call Assembly.Load)

    p.s. @poupou (forum, stackoverflow) is the same as @spouliot (twitter) and sebastien@x.com - OTOH I have no papers naming me a genius (maybe I should print this one ;-)

  • StuartLodgeStuartLodge Stuart Lodge USBeta ✭✭✭

    Thanks PouPou

    you cannot load new (as in not AOT compiled) assemblies.

    If I reference an assembly but never use it - and I have Linker set to SDK only - then does it not get AOT compiled?

    Is there anything you known from the assemblies that could be used to jumpstart the runtime into loading them ?

    Kind of - there is a known registration interface (which is what I get just after the assembly.load is called) - but other than that it only contain objects that get referenced by interface.

    This is for plugins - interface-driven components - where the basic idea is that there's a central PCL assembly which contains the interface and then separate assemblies containing the platform specific implementations (the 'real code').

    -

    I've no worries if this doesn't work - my workaround is to jumpstart them just like you suggest - I use a registration pattern - like:

        protected override void AddPluginsLoaders(MvxLoaderPluginRegistry registry)
        {
            registry.AddConventionalPlugin<Cirrious.MvvmCross.Plugins.Visibility.Touch.Plugin>();
            registry.AddConventionalPlugin<Cirrious.MvvmCross.Plugins.File.Touch.Plugin>();
            registry.AddConventionalPlugin<Cirrious.MvvmCross.Plugins.DownloadCache.Touch.Plugin>();
            base.AddPluginsLoaders(registry);
        }
    

    However, since I was changing this area in WP and WinRT, I thought I'd check up on this old xamios question too.

    @dsplaisted and I are talking (arguing nicely) about this area at the moment - we're trying to work out if there is a way that all PCLs+extension methods could be built in a similar way - if they can, then tools like a multi-platform-nuget could be built around them.

    Thanks for the info

    Stuart (wondering about making an app that provides proof-of-genius-certification)

  • SebastienPouliotSebastienPouliot Sebastien Pouliot CAMember, Xamarin Team Xamurai

    If I reference an assembly but never use it - and I have Linker set to SDK only - then does it not get AOT compiled?

    No, that's how the .NET compilers works, i.e. it's unrelated to the linker, AOT compiler or even Xamarin.iOS itself.

    E.g. the C# compiler will only include assembly references if they are used. IOW you can add -r: for every FX assemblies but if you only use mscorlib.dll then your .exe will only reference this single assembly.

    After compilation XS/MD will give to mtouch an initial list of assemblies (you can see it in the Build Log).

    mtouch will recursively analyze the .exe (and other supplied .dll) to find every assemblies that can be needed (that's even before the linker gets called).

    Later the linker might find out some assemblies are not needed (i.e. the code that referencing them was removed) and remove them from the final application.

    What's left will be AOT'ed and copied (stripped first for release builds) inside your application.

    In doubt you can check inside your .app directory so see which .dll made it out to the end :-)

  • StuartLodgeStuartLodge Stuart Lodge USBeta ✭✭✭
    edited March 2013

    While I'm distracting you anyway... and so I don't ask this again in another 6 months :)

    No, that's how the .NET compilers works, i.e. it's unrelated to the linker, AOT compiler or even Xamarin.iOS itself.

    What do you mean by '.NET compilers' here?

    As far I understand it from practical hacking... especially while investigating this question

    • if I reference a project inside one of the Studio Twins, but don't use any types from within the source project
    • then the .Net compiler will compile that referenced project
    • and the MSBuild/XBuild Twins will copy that assembly to the output folder
    • but when the .Net compiler compiles the referencing project then the output IL doesn't have any reference information in the '.assembly extern' section.

    But then I'm not sure which bit of the toolchain happens next?

    Obviously the 'packagers' for WinRT, WP, and XamDroid all choose to package the semi-referenced Assembly (Assembly.Load works in all those platforms). Also, PCL-Daniel seems really convinced that whatever MS's magic AoT cloud compiler is for WP will process these assemblies.

    ... but it seems XamTouch is different? And I guessed that's because the AOT compiler is only being run against the reference list (and ancestor reference list) from the 'main' compiled IL assembly?

    Is that roughly right?

    Stuart

  • SebastienPouliotSebastienPouliot Sebastien Pouliot CAMember, Xamarin Team Xamurai

    What do you mean by '.NET compilers' here?

    I mean .NET compilers (not IDE) and assembly references (not project references). E.g.

        $ cat hello.cs
        using System;
    
       class Program {
        static void Main ()
        {
            Console.WriteLine ("Hello");
        }
       }
       $ mcs hello.cs -r:System.dll
       $ monodis hello.exe
       .assembly extern mscorlib
       {
         .ver 4:0:0:0
         .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
       }
       .assembly 'hello'
       {
       ...
    

    So asking a compiler to add a reference (e.g. to System.dll) won't automatically include it in the final binary (e.g. only mscorlib is referenced by hello.exe) unless it's required.

  • StuartLodgeStuartLodge Stuart Lodge USBeta ✭✭✭

    Thanks

    I still think this is a packaging/AOT difference rather than a compiler one - as the other 'packagers' and AOT compilers (e.g. WinPhone in the Marketplace) all claim to support these additional files.

    But doesn't matter... I'll keep using the code based registration for Touch and Mac - and will use the file based loading on the others.

    Thanks again :)

    Stuart

  • KirkKlobeKirkKlobe Kirk Klobe USMember, Beta

    We are also resorting to this code-based registration technique. There really should be a feature added to overcome this limitation. Perhaps an mtouch flag to force inclusion of an assembly?

Sign In or Register to comment.