New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Referencing an assembly from linker.xml that isn't referenced in code will cause the dll to copy to app but not load into the domain #5589

Closed
PureWeen opened this Issue Feb 12, 2019 · 3 comments

Comments

Projects
None yet
2 participants
@PureWeen
Copy link

PureWeen commented Feb 12, 2019

https://xamarinhq.slack.com/archives/C03CCJNR7/p1549929154073500

Steps to Reproduce

  1. Open AppDelegate.cs file and breakpoint this line Assembly.Load("ExtraLibrary");
  2. Notice that it hits this line because the ExtraLibrary.dll isn't found
  3. now if you continue stepping forward the Assembly.Load("ExtraLibrary"); call will succeed and load the dll

The difference with this project vs the one referenced here
#5588

Is that this project includes a linker.xml file that references the type. So the hope here would be that the dll should load up into the app domain.

Expected Behavior

What I would like to happen is that the dll (because it's referenced by the xml file) will load into the current assembly domains

For example AppDomain.CurrentDomain.GetAssemblies() should return the assembly that way code that needs to scan assemblies for things like DI reliably can.

Actual Behavior

DLL is present in app folder but is not loaded into the Current domain

Environment

Microsoft Visual Studio Enterprise 2019 Int Preview
Version 16.0.0 Preview 3.0 [28608.199.d16.0prev3]
VisualStudio.16.IntPreview/16.0.0-pre.3.0+28608.199.d16.0prev3
Microsoft .NET Framework
Version 4.7.03190

Installed Version: Enterprise

Visual C++ 2019   00435-10000-00000-AA174
Microsoft Visual C++ 2019

Application Insights Tools for Visual Studio Package   9.0.20206.1
Application Insights Tools for Visual Studio

ASP.NET and Web Tools 2019   16.0.12185.18740
ASP.NET and Web Tools 2019

ASP.NET Web Frameworks and Tools 2019   16.0.12185.18740
For additional information, visit https://www.asp.net/

Azure App Service Tools v3.0.0   16.0.12185.18740
Azure App Service Tools v3.0.0

Azure Functions and Web Jobs Tools   16.0.12185.18740
Azure Functions and Web Jobs Tools

C# Tools   3.0.0-beta3-19105-04+f9fc5ea40f861ac30e7ad1a322b7517d4af5d47b
C# components used in the IDE. Depending on your project type and settings, a different version of the compiler may be used.

Common Azure Tools   1.10
Provides common services for use by Azure Mobile Services and Microsoft Azure Tools.

Extensibility Message Bus   1.1.77 (master@24013d5)
Provides common messaging-based MEF services for loosely coupled Visual Studio extension components communication and integration.

Microsoft Azure Tools   2.9
Microsoft Azure Tools for Microsoft Visual Studio 0x10 - v2.9.0.0

Microsoft Continuous Delivery Tools for Visual Studio   0.4
Simplifying the configuration of Azure DevOps pipelines from within the Visual Studio IDE.

Microsoft JVM Debugger   1.0
Provides support for connecting the Visual Studio debugger to JDWP compatible Java Virtual Machines

Microsoft Library Manager   1.0
Install client-side libraries easily to any web project

Microsoft MI-Based Debugger   1.0
Provides support for connecting Visual Studio to MI compatible debuggers

Microsoft Visual C++ Wizards   1.0
Microsoft Visual C++ Wizards

Microsoft Visual Studio Tools for Containers   1.1
Develop, run, validate your ASP.NET Core applications in the target environment. F5 your application directly into a container with debugging, or CTRL + F5 to edit & refresh your app without having to rebuild the container.

Microsoft Visual Studio VC Package   1.0
Microsoft Visual Studio VC Package

Mono Debugging for Visual Studio   16.0.300 (573eda3)
Support for debugging Mono processes with Visual Studio.

NuGet Package Manager   5.0.0
NuGet Package Manager in Visual Studio. For more information about NuGet, visit http://docs.nuget.org/.

Project System Tools   1.0
Tools for working with C#, VisualBasic, and F# projects.

ProjectServicesPackage Extension   1.0
ProjectServicesPackage Visual Studio Extension Detailed Info

ResourcePackage Extension   1.0
ResourcePackage Visual Studio Extension Detailed Info

ResourcePackage Extension   1.0
ResourcePackage Visual Studio Extension Detailed Info

Snapshot Debugging Extension   1.0
Snapshot Debugging Visual Studio Extension Detailed Info

SQL Server Data Tools   16.0.61901.26130
Microsoft SQL Server Data Tools

TypeScript Tools   16.0.10206.2003
TypeScript Tools for Microsoft Visual Studio

Visual Basic Tools   3.0.0-beta3-19105-04+f9fc5ea40f861ac30e7ad1a322b7517d4af5d47b
Visual Basic components used in the IDE. Depending on your project type and settings, a different version of the compiler may be used.

Visual F# Tools 10.4 for F# 4.6   16.0.0.0.  Commit Hash: b5c01b8cc65af6381d2dd558ee63a4aa9e0e98d5.
Microsoft Visual F# Tools 10.4 for F# 4.6

Visual Studio Code Debug Adapter Host Package   1.0
Interop layer for hosting Visual Studio Code debug adapters in Visual Studio

Visual Studio Tools for Containers   1.0
Visual Studio Tools for Containers

VisualStudio.Mac   1.0
Mac Extension for Visual Studio

Xamarin   16.0.0.433 (d16-0@949c8f6c5)
Visual Studio extension to enable development for Xamarin.iOS and Xamarin.Android.

Xamarin Designer   4.17.287 (feb5c9860)
Visual Studio extension to enable Xamarin Designer tools in Visual Studio.

Xamarin Templates   16.0.330 (e66cdf3)
Templates for building iOS, Android, and Windows apps with Xamarin and Xamarin.Forms.

Xamarin.Android SDK   9.1.103.12 (HEAD/7e1c4688)
Xamarin.Android Reference Assemblies and MSBuild support.
    Mono: mono/mono/2018-08@725ba2a2523
    Java.Interop: xamarin/java.interop/d16-0@c987483
    LibZipSharp: grendello/LibZipSharp/master@44de300
    LibZip: nih-at/libzip/rel-1-5-1@b95cf3f
    MXE: xamarin/mxe/xamarin@b9cbb535
    ProGuard: xamarin/proguard/master@905836d
    SQLite: xamarin/sqlite/3.26.0@325e91a
    Xamarin.Android Tools: xamarin/xamarin-android-tools/d16-0@f05c0aa


Xamarin.iOS and Xamarin.Mac SDK   12.6.0.16 (bc9c674)
Xamarin.iOS and Xamarin.Mac Reference Assemblies and MSBuild support.

Example Project (If Possible)

PreserveTestWithLinker.zip

@spouliot

This comment has been minimized.

Copy link
Contributor

spouliot commented Feb 12, 2019

I believe there's some misunderstanding.

  1. Notice that it hits this line because the ExtraLibrary.dll isn't found

No, it's because it's not loaded :)
The question is why should the assembly be loaded into the domain ?

IOW write the same code in a console app, copy the ExtraLibrary.dll inside the same directory, will it load into the app domain ?

Now if you load the assembly then yes, it will be part of the app domain assemblies.

Packaging and runtime are two different things. The linker does not change the application behaviour.

proof

$ pwd
/Users/poupou/Downloads/PreserveTestWithLinker/ExtraLibrary/bin/Debug/netstandard2.0

$ l
total 48
-rwxr-xr-x@ 1 poupou  staff  2294 12 Feb 09:56 ExtraLibrary.deps.json
-rwxr-xr-x@ 1 poupou  staff  4096 12 Feb 09:56 ExtraLibrary.dll
-rwxr-xr-x@ 1 poupou  staff   244 12 Feb 09:56 ExtraLibrary.pdb
-rw-r--r--  1 poupou  staff   900 12 Feb 10:10 test.cs
-rw-r--r--  1 poupou  staff  4608 12 Feb 10:10 test.exe

$ cat test.cs 
using System;
using System.Reflection;

class Program {
	static void Main ()
	{
			Assembly foundAssembly = null;
			Console.WriteLine("without calling LoadLibrary");
			
			foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
			{
				if (assembly.FullName.Contains("ExtraLibrary"))
				{
					foundAssembly = assembly;
				}

				Console.WriteLine(assembly.FullName);
			}

			Console.WriteLine("after calling LoadLibrary");
			if (foundAssembly == null)
			{
				Assembly.Load("ExtraLibrary");
				foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
				{
					if (assembly.FullName.Contains("ExtraLibrary"))
					{
						foundAssembly = assembly;
					}

					Console.WriteLine(assembly.FullName);
				}
			}

			if (foundAssembly == null)
				throw new Exception("assembly not found");

			Console.WriteLine (foundAssembly.CreateInstance("ExtraLibrary.Class1"));

	}
}

$ csc test.cs
Microsoft (R) Visual C# Compiler version 2.8.2.62916 (2ad4aabc)
Copyright (C) Microsoft Corporation. All rights reserved.

$ mono test.exe 
without calling LoadLibrary
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
after calling LoadLibrary
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
ExtraLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
ExtraLibrary.Class1

@spouliot spouliot closed this Feb 12, 2019

@spouliot spouliot added this to the Future milestone Feb 12, 2019

@spouliot

This comment has been minimized.

Copy link
Contributor

spouliot commented Feb 12, 2019

What I would like to happen is that the dll (because it's referenced by the xml file) will load into the current assembly domains

I double checked and your sample works (creating the instance) on device, so the code is AOT'ed as expected.

If XF wants to work that way (which differs from traditional .net) then you can add code to load any *.dll inside the .app - just loop an Assembly.Load over all .dll (most of them are already loaded so oit should be cheap or you can ignore the one already loaded yourself)

However that might cause future problems with the interpreter (as a bunch of other assemblies, possibly conflicting, could be present).

@PureWeen

This comment has been minimized.

Copy link
Author

PureWeen commented Feb 12, 2019

So what I'm trying to do here is understand the consistent story between ios and android plus it's interesting you brought up console apps.

The part where I still see iOS differ (and maybe this is just how iOS has to be) is if you reference a type from the ExtraLibrary literally anywhere outside the ExtraLibrary assembly then iOS loads it into the app domain.

So in the iOS project (or even the cross platform project that's referenced by the iOS project) if you add some class that's never accessed

	public class ClassThatIsNeverCalled
	{
		public void SomeMethod()
		{
			throw new Exception(typeof(ExtraLibrary.Class1).Name);
		}
	}

Then iOS will now front load that ExtraLibrary into the CurrentDomain on startup even if that library is never reached out to.

  • if you do this on a console app the dll won't be loaded given the same scenario
  • if you do this on Android (as of Dev16) it won't be loaded given the same scenario. Android won't load the dll until the runtime accesses something from the library whereas iOS doesn't have this same requirement

The use case I'm working with here is that for iOS (and really only iOS) xplat libraries always have to include a noop call to some type in order for iOS to load that library into the domain and if you specify the file inside the linker then I feel like that should cause the same behavior as a frivolous reference to a type in the library

Here's a sample (run it on dev16) and you'll see that iOS is the only platform where the assembly is loaded up front into the CurrentDomain
PreserveTest.zip

If XF wants to work that way (which differs from traditional .net) then you can add code to load any *.dll inside the .app - just loop an Assembly.Load over all .dll (most of them are already loaded so oit should be cheap or you can ignore the one already loaded yourself)

But I feel like the story here is awkward

  • if the user never references a type in ExtraLibrary this solution won't work because the dll doesn't get packaged into the app
  • This scenario of looping over the Assemblies is only valid if they specify the type in the linker file without every referencing a type from code. Which is sort of edge case and at this point I would just instruct a user to add some random reference to a type in the assembly literally anywhere in there app for a better result

Changing iOS to only load libraries only when first accessed at runtime would probably break too much so that's not what I'm advocating for at this point. But I do feel that if the library is specified in the linker.xml file that it should be front loaded into the domain just like it would if you reference a random type.

And then just an FYI
XF is working on some build targets to make it so users don't have to add anything at all

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment