PRISM + Unity Container - Link sdk and user assemblies

Have anyone already configure the linker to work properly with the Microsoft Unity container?
I have an app that is currently in production but at for now i've only use "SDK assemblies only". So i'm trying to reduce the size of this app and linker is the best option but i'm not getting to make it work.

I've already make a test: created a new Prism.Unity app, with the Prism Template Package and the only change that i made was set link to full mode...the app crashes as well.

The error message:

Unhandled Exception:
08-29 13:52:02.485 E/mono    (12194): System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.TypeInitializationException: The type initializer for 'Microsoft.Practices.Unity.ArrayResolutionStrategy' threw an exception. ---> System.InvalidOperationException: Sequence contains no matching element
08-29 13:52:02.485 E/mono    (12194):   at System.Linq.Enumerable.First[TSource] (System.Collections.Generic.IEnumerable`1[T] source, System.Func`2[T,TResult] predicate) [0x00011] in <b5bd9d990a0b4733885e90ca5ec6c0fb>:0 
08-29 13:52:02.485 E/mono    (12194):   at Microsoft.Practices.Unity.ArrayResolutionStrategy..cctor () [0x00014] in <95410a6f72e5460987abb52dc3238a18>:0 
08-29 13:52:02.485 E/mono    (12194):    --- End of inner exception stack trace ---
08-29 13:52:02.485 E/mono    (12194):   at (wrapper managed-to-native) System.Reflection.MonoCMethod:InternalInvoke (System.Reflection.MonoCMethod,object,object[],System.Exception&)
08-29 13:52:02.485 E/mono    (12194):   at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00002] in <183b200ee49746d48fc781625979428e>:0 
08-29 13:52:02.485 E/mono    (12194):    --- End of inner exception stack trace ---

Best Answer

Answers

  • akamudakamud BRUniversity ✭✭

    You need to preserve some Prism and Unity types.

    Use a custom linker file with at least these rules:

    <?xml version="1.0" encoding="UTF-8" ?>
    <linker>
            <assembly fullname="Microsoft.Practices.Unity">
                    <type fullname="Microsoft.Practices.Unity*" />
            </assembly>
    
            <assembly fullname="Prism.Unity.Forms">
                <type fullname="Prism.Unity.Extensions.DependencyServiceExtension" preserve="fields">
                    <method name=".ctor" />
                </type>
            </assembly>
    </linker>
    
  • NMackayNMackay GBInsider, University mod

    @akamud said:
    You need to preserve some Prism and Unity types.

    Use a custom linker file with at least these rules:

    <?xml version="1.0" encoding="UTF-8" ?>
    <linker>
            <assembly fullname="Microsoft.Practices.Unity">
                    <type fullname="Microsoft.Practices.Unity*" />
            </assembly>
    
            <assembly fullname="Prism.Unity.Forms">
                <type fullname="Prism.Unity.Extensions.DependencyServiceExtension" preserve="fields">
                    <method name=".ctor" />
                </type>
            </assembly>
    </linker>
    

    Ran into the same issue but hadn't investigated any further so thanks for posting this.

  • LyndonHugheyLyndonHughey USUniversity ✭✭✭
    edited December 2017

    Thanks @akamud. This was a huge help. I'm now able to link properly. As a result, my assembly is half the size it was yesterday!

  • BozhiQianBozhiQian AUUniversity ✭✭

    Not sure how to make my linker.xml works.

    These are my steps:

    1. Use the Prism Project Template to create a new Prism Application
    2. Select Unity as your container
    3. On the Android project property window, Select "Android Options", and set Linking dropdown list to "SDK and User Assemblies".
    4. Run debug to deploy to Visual Studio Emulator for Android.

    Before step3, I can run it on Visual Studio Emulator for Android.
    But after step 3, it has issue at running reported from VS2017 output window though building is always successful.

    Resolution of the dependency failed, type = 'Prism.Modularity.IModuleCatalog', name = '(none)'.
    Exception occurred while: while resolving.
    Exception is: ArgumentNullException - Value cannot be null.
    Parameter name: method
    -----------------------------------------------
    At the time of the exception, the container was: 
      Resolving Prism.Modularity.ModuleCatalog,(none) (mapped from Prism.Modularity.IModuleCatalog, (none))
        Resolving Prism.Modularity.ModuleCatalog,(none)
    

    And I tried to add a linker.xml to Android project.

    <?xml version="1.0" encoding="utf-8" ?>
    <linker>
    
      <assembly fullname="Prism.Forms">
        <type fullname="Prism.Modularity.IModuleCatalog" preserve="fields">
          <method name=".ctor" />
        </type>
      </assembly>
    </linker>
    

    But it did not work at all.

    The reason that I need to do step 3 is resolving issue later on once installed "Microsoft.EntityFrameworkCore.Sqlite" nuget package that will result another famous issue "Could not load assembly 'System.Runtime.CompilerServices.Unsafe' during startup registration."

    And because of the step 3 issue, I am not able to do any futher work.
    I tried use Autofac at step 2, but it has the same issue.

    Please give help!!! Thanks.

  • grbarretogrbarreto BRMember ✭✭

    @BozhiQian I have not tried with unity container but the solution here with DryIoc is working.

    I tested using the latest prism template pack.
    Without linker set to full the app size has something like 28MB and after set linker to full the size changed to 9.23MB

  • BozhiQianBozhiQian AUUniversity ✭✭

    Thanks @grbarreto Let me try this.
    But using Dryloc, the VS2017 prism template does not generate ViewModel and so on.

  • Abhijeet_SuryaAbhijeet_Surya USMember ✭✭✭

    @NMackay

    I am getting build error on adding Linker.xml to android project

    Error MSB4018: The "LinkAssemblies" task failed unexpectedly.

  • Abhijeet_SuryaAbhijeet_Surya USMember ✭✭✭
    edited March 2018

    @akamud said:
    Update, I ended up with these rules regarding Prism for my project:

    <?xml version="1.0" encoding="UTF-8" ?>
    <linker>
            <assembly fullname="Microsoft.Practices.Unity">
                <type fullname="Microsoft.Practices.Unity*" />
            </assembly>
    
            <assembly fullname="Prism.Unity.Forms">
                <type fullname="Prism.Unity.Extensions.DependencyServiceExtension" preserve="all">
                    <method name=".ctor" />
                </type>
                <type fullname="Prism.Unity.Navigation.UnityPageNavigationService" preserve="all" />
            </assembly>
    
            <assembly fullname="Prism.Forms">
                <type fullname="Prism.Common.ApplicationProvider" preserve="all" />
                <type fullname="Prism.Services.PageDialogService" preserve="all" />
                <type fullname="Prism.Services.DeviceService" preserve="all" />
            </assembly>
    </linker>
    

    After adding this I am geeting below mention error (I have created sample blank project using prism template)

    /Library/Frameworks/Mono.framework/External/xbuild/Xamarin/Android/Xamarin.Android.Common.targets(5,5): Error MSB4018: The "LinkAssemblies" task failed unexpectedly.
    Mono.Linker.Steps.XmlResolutionException: Failed to process XML description: ---> Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'Microsoft.Practices.Unity, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' ---> Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'Microsoft.Practices.Unity, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'

    @akamud , any suggessions?

  • GuidoNeele.6288GuidoNeele.6288 USMember ✭✭

    @Abhijeet_Surya I see your post was from a month ago but will answer it anyway because I ran into the same issue. You are probably using Prism 7 which doesn't reference Microsoft.Practices.Unity anymore.

  • Abhijeet_SuryaAbhijeet_Surya USMember ✭✭✭

    @GuidoNeele.6288

    Thanks.

    Do you have sample linker to resolve this issue?

  • GuidoNeele.6288GuidoNeele.6288 USMember ✭✭

    This is the one I used

    <?xml version="1.0" encoding="UTF-8" ?>
    <linker>  
    
      <assembly fullname="Unity.Abstractions">
        <type fullname="*" />
      </assembly>
    
      <assembly fullname="Unity.Container">
        <type fullname="*" />
      </assembly>
    
      <assembly fullname="Unity.ServiceLocation">
        <type fullname="*" />
      </assembly>
    
      <assembly fullname="System">
        <type fullname="*" />
      </assembly>
    
      <assembly fullname="mscorlib">
        <type fullname="*" />
      </assembly>
    
      <assembly fullname="Prism">
        <type fullname="*" />
      </assembly>
    
      <assembly fullname="Prism.Unity.Forms">
        <type fullname="*" />
      </assembly>
    
      <assembly fullname="CrisisConnect">
        <type fullname="*" />
      </assembly>
    
      <assembly fullname="Prism.Forms">
        <type fullname="*" />
      </assembly>
    
      <assembly fullname="Newtonsoft.Json">
        <type fullname="*" />
      </assembly>
    </linker>
    
  • PiotrBrzezinskiPiotrBrzezinski PLMember ✭✭

    Hi I created project which size is 43MB so I also need to link Users Assembly.
    But Prism make me headache...

    I set in linkerConfig.xml

    <assembly fullname="Prism.Forms"> <type fullname="*" preserve="all"/> </assembly>

    and still get exception:

    07-14 16:00:03.685: E/AndroidRuntime(10942): Exception is: InvalidOperationException - The type ModuleManager does not have an accessible constructor.

    Doeas somebody fix this?

  • Thanks @GuidoNeele.6288

    I' used your answer and it works!

    So, i'm using Prism 7 and Unity,

    My linker.xml file was:

    <linker>
        <assembly fullname="Prism.Forms">
            <type fullname="Prism.Common.ApplicationProvider" preserve="all" />
            <type fullname="Prism.Services.PageDialogService" preserve="all" />
            <type fullname="Prism.Services.DeviceService" preserve="all" />
            <type fullname="Prism.Ioc*" preserve="all" />
            <type fullname="Prism.Modularity*" preserve="all" />
            <type fullname="Prism.Navigation*" preserve="all" />
            <type fullname="Prism.Behaviors.PageBehaviorFactory" preserve="all">
                <method name=".ctor" />
            </type>
            <type fullname="Prism.Services.DependencyService" preserve="all">
                <method name=".ctor" />
            </type>
        </assembly>
    
        <assembly fullname="Prism">
            <type fullname="Prism.Navigation*" preserve="all" />
            <type fullname="Prism.Logging.EmptyLogger" preserve="all">
                <method name=".ctor" />
            </type>
        </assembly>
    
        <assembly fullname="Unity.Abstractions">
            <type fullname="*" />
        </assembly>
    
        <assembly fullname="Unity.Container">
            <type fullname="*" />
        </assembly>
    
        <assembly fullname="Newtonsoft.Json">
            <type fullname="Newtonsoft.Json.*" preserve="all" />
        </assembly>
    
    </linker>
    
  • NMackayNMackay GBInsider, University mod

    @RobsonAmorim said:
    Thanks @GuidoNeele.6288

    I' used your answer and it works!

    So, i'm using Prism 7 and Unity,

    My linker.xml file was:

    <linker>
        <assembly fullname="Prism.Forms">
            <type fullname="Prism.Common.ApplicationProvider" preserve="all" />
            <type fullname="Prism.Services.PageDialogService" preserve="all" />
            <type fullname="Prism.Services.DeviceService" preserve="all" />
            <type fullname="Prism.Ioc*" preserve="all" />
            <type fullname="Prism.Modularity*" preserve="all" />
            <type fullname="Prism.Navigation*" preserve="all" />
            <type fullname="Prism.Behaviors.PageBehaviorFactory" preserve="all">
                <method name=".ctor" />
            </type>
            <type fullname="Prism.Services.DependencyService" preserve="all">
                <method name=".ctor" />
            </type>
        </assembly>
    
        <assembly fullname="Prism">
            <type fullname="Prism.Navigation*" preserve="all" />
            <type fullname="Prism.Logging.EmptyLogger" preserve="all">
                <method name=".ctor" />
            </type>
        </assembly>
    
        <assembly fullname="Unity.Abstractions">
            <type fullname="*" />
        </assembly>
    
        <assembly fullname="Unity.Container">
            <type fullname="*" />
        </assembly>
    
        <assembly fullname="Newtonsoft.Json">
            <type fullname="Newtonsoft.Json.*" preserve="all" />
        </assembly>
    
    </linker>
    

    This works a treat with Prism 7.2 in iOS & DryIoc, just strip Unity.Abstractions & Unity.Container.

    @RobsonAmorim Thanks for posting.

Sign In or Register to comment.