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

System.IO.Packaging not resolved correctly #1154

Closed
alexdrl opened this Issue Jan 3, 2018 · 18 comments

Comments

Projects
None yet
7 participants
@alexdrl

alexdrl commented Jan 3, 2018

Steps to Reproduce

We're having an issue with a Xamarin project, which as we added System.IO.Packaging 4.4.1 nuget package dependency, the reference is resolved as the ref/netstandard1.3 DLL, a reference assembly. It seems that because of that, the Xamarin app fails to start because this DLL does not get packaged, and so the app fails to start with this common xamarin error https://forums.xamarin.com/discussion/63584/android-could-not-load-assembly-xxx-during-startup-registration

There seems to be an issue open related to that dotnet/corefx#23830

Expected Behavior

The application starts correctly.

Actual Behavior

The application fails to start with the "Could not load assembly 'xxx' during startup registration" error.

Version Information

VS 15.5.2
Xamarin 4.8
Xamarin.Android 8.1

VS bug #580833

@weshaggard

This comment has been minimized.

weshaggard commented Jan 3, 2018

@marek-safar @akoeplinger does System.IO.Packaging exist in the Xamarin platform?

@marek-safar

This comment has been minimized.

Contributor

marek-safar commented Jan 3, 2018

@weshaggard no, we thought as this is fully managed assembly and we never supported it we could just get it from nuget as netstandard1.x

@weshaggard

This comment has been minimized.

weshaggard commented Jan 3, 2018

@marek-safar you're right this package doesn't have the Xamarian placeholders in it so it should be using the netstandard implementation.

@alexdrl can you give more information on the error you are hitting? Such as which assembly cannot be loaded? Can you also verify what assembly is getting deployed with your application? I would expect the lib\netstandard1.3 or lib\netstandard2.0 library to be deployed.

@jonpryor

This comment has been minimized.

Contributor

jonpryor commented Jan 3, 2018

This feels like a variation on Bug #57342 and other bugs that I vaguely recall seeing but can't readily find.

@dellis1972: Do you remember anything more recent/specific?

@alexdrl: Could you please provide the diagnostic build output of the packaging process for your app?

msbuild /v:diag /t:SignAndroidPackage App.csproj > b.txt

Then upload b.txt "somewhere" (gist.github.com works).

@jonpryor

This comment has been minimized.

Contributor

jonpryor commented Jan 3, 2018

@alexdrl

This comment has been minimized.

@alexdrl

This comment has been minimized.

alexdrl commented Jan 4, 2018

@weshaggard This is the debug log that is displaying running the android app https://gist.github.com/alexdrl/39fb731fadd62d84fcd8ed2952e707e0

@marek-safar

This comment has been minimized.

Contributor

marek-safar commented Jan 4, 2018

@alexdrl please attach full re-build log with verbosity level set to Diagnostic

@alexdrl

This comment has been minimized.

alexdrl commented Jan 4, 2018

@marek-safar I uploaded the file to this temporary repo as this is huge for the gist to manage, it is located here https://github.com/alexdrl/msbuildlog/blob/master/cleanlog.zip

@dellis1972

This comment has been minimized.

Contributor

dellis1972 commented Jan 4, 2018

@jonpryor looks like the fix we put in for ignoring reference assemblies is working . I see this following in the log file from above.

warning : Ignoring D:\W\Packages\system.io.packaging\4.0.0\ref\netstandard1.3 as it is a Reference Assembly [D:\W\AR\RPQPrototype\HealthAndWelfare\UI\Mobile\XF\Main\Droid\XF.Main.Droid.csproj]

So I guess we are correctly ignoring the reference assembly, but for some reason the actual assembly we need is not included in the list of resolved assemblies.

@jonpryor

This comment has been minimized.

Contributor

jonpryor commented Jan 4, 2018

I'm not certain that we are ignoring the reference assembly:

  BuildApk Task (TaskId:1229)
    ApkInputPath: obj\Debug\android\bin\packaged_resources (TaskId:1229)
      ...
      obj\Debug\android\assets\System.IO.Packaging.dll (TaskId:1229)

So we're finding a System.IO.Packaging.dll assembly, and copying into obj\Debug\android\assets. Where's it coming from? This is where MSBuild diagnostic output is wonderful, compared to xbuild...

Task "BuildApk" (TaskId:1229)
  Task Parameter:AndroidNdkDirectory=C:\ProgramData\Microsoft\AndroidNDK64\android-ndk-r13b\ (TaskId:1229)
  Task Parameter:ApkInputPath=obj\Debug\android\bin\packaged_resources (TaskId:1229)
  Task Parameter:ApkOutputPath=obj\Debug\android\bin\RPQPrototype.Android.apk (TaskId:1229)
  Task Parameter:EmbedAssemblies=False (TaskId:1229)
  Task Parameter:
      ResolvedUserAssemblies=
      ...
  Task Parameter:
      EmbeddedNativeLibraryAssemblies=
      ...
          D:\W\Packages\system.io.packaging\4.0.0\ref\netstandard1.3\System.IO.Packaging.dll
                  CopyLocal=false
                  FusionName=System.IO.Packaging, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
                  ImageRuntime=v4.0.30319
                  NuGetIsFrameworkReference=false
                  NuGetPackageId=System.IO.Packaging
                  NuGetPackageVersion=4.0.0
                  NuGetSourceType=Package
                  OriginalItemSpec=D:\W\Packages\system.io.packaging\4.0.0\ref\netstandard1.3\System.IO.Packaging.dll
                  Private=false
                  ReferenceAssembly=D:\W\Packages\system.io.packaging\4.0.0\ref\netstandard1.3\System.IO.Packaging.dll
                  ReferenceSourceTarget=ResolveAssemblyReference
                  ResolvedFrom={RawFileName}
                  Version=

That does not look right; @(ReferencePath) and/or @(ReferenceDependencyPaths) is hitting the reference assembly, not the actual assembly.

Regardless, that doesn't answer where obj\Debug\android\assets\System.IO.Packaging.dll is coming from. Searching further backward...

Task "LinkAssemblies" (TaskId:1189)
  Task Parameter:UseSharedRuntime=true (TaskId:1189)
  Task Parameter:MainAssembly=obj\Debug\android\assets\ADDInformatica.RPQPrototype.HealthAndWelfare.UI.Mobile.XF.Main.Droid.dll (TaskId:1189)
  Task Parameter:OutputDirectory=obj\Debug\linkdst\ (TaskId:1189)
  Task Parameter:OptionalDestinationDirectory=obj\Debug\android\assets\ (TaskId:1189)
  Task Parameter:LinkMode=None (TaskId:1189)
  Task Parameter:LinkDescriptions=LinkDescription.xml (TaskId:1189)
  Task Parameter:LinkOnlyNewerThan=obj\Debug\link.flag (TaskId:1189)
  Task Parameter:
      ResolvedAssemblies=
          ...
          D:\W\Packages\system.io.packaging\4.0.0\ref\netstandard1.3\System.IO.Packaging.dll

The <LinkAssemblies/> task (optionally) links the assemblies -- LinkMode=None here, so no linking is performed -- and copies the assemblies into obj\Debug\android\assets.

We thus infer that @(ResolvedAssemblies) erroneously contains the reference assembly.

We may be emitting the warning about ignoring a reference assembly, but notice that we're ignoring netstandard1.3, not System.IO.Packaging.dll. It's System.IO.Packaging.dll which is causing problems.

@(ResolvedAssemblies) is set by the <ResolveAssemblies/> task, and we see that @(FIlteredAssemblies) contains the reference assembly:

Task "ResolveAssemblies" (TaskId:1169)
  Task Parameter:
      Assemblies=
          ...
          D:\W\Packages\system.io.packaging\4.0.0\ref\netstandard1.3\System.IO.Packaging.dll

Unfortunately, it appears that our creation of @(FilteredAssemblies) removes the item metadata, so we don't see any metadata within the above fragment.

@(FilteredAssemblies) in turn comes from @(ReferenceCopyLocalPaths) and @(ReferencePath). Unfortunately, I can't quickly find where System.IO.Packaging.dll is coming from to be located within either @(ReferenceCopyLocalPaths) or @(ReferencePath).

@dellis1972

This comment has been minimized.

Contributor

dellis1972 commented Jan 23, 2018

Some more informations. It looks like the required target ResolvePackageDependenciesForBuild is not built. This is probably because it is part of the Microsoft.NET.Sdk.targets. Since android (and iOS) projects do not use the new project format I suspect that those targets are not being imported. They are then never run, so we end up with the wrong references.

@radical might be able to confirm this. I'm trying to see what we need to do to add this to android.

@ConX-Ryan

This comment has been minimized.

ConX-Ryan commented Feb 12, 2018

what is the estimated working timeline on fixing this and the downstream issues? 1196

Xamarin Forms with .NETStandard 2.0 is DOA at the moment

@dellis1972

This comment has been minimized.

Contributor

dellis1972 commented Feb 12, 2018

@ConX-Ryan from my understanding this is a problem in the MSbuild NetStandard targets so this will probably be tracked on Microsoft/msbuild#2776. @radical can you confirm that is the case?

@johnwmcintosh

This comment has been minimized.

johnwmcintosh commented Feb 26, 2018

I'm having this problem with EF Core 2.0.1 as described here https://stackoverflow.com/questions/48956433/ef-core-2-0-1-unsafe-in-xamarin-android

@JonDouglas asked I post a "reaction" here. Not sure what that means so I'm just using a comment.

jonpryor added a commit that referenced this issue Feb 27, 2018

[Xamarin.Android.Build.Tasks] Improve .NET Standard Support (#1185)
Context: #1154

This PR brings in changes from xamarin/xamarin-macios#2643 and
xamarin/xamarin-macios#2731 to improve our .NET Standard support.
While this does not fix the packaging problem in #1154 it will give
us parity with the iOS code base.

jonpryor added a commit that referenced this issue Feb 27, 2018

[Xamarin.Android.Build.Tasks] Improve .NET Standard Support (#1185)
Context: #1154

This PR brings in changes from xamarin/xamarin-macios#2643 and
xamarin/xamarin-macios#2731 to improve our .NET Standard support.
While this does not fix the packaging problem in #1154 it will give
us parity with the iOS code base.

dellis1972 added a commit to dellis1972/java.interop that referenced this issue Mar 5, 2018

[Java.Interop.Tools.Cecil] Change DirectoryAssemblyResolver to allow …
…forced loading.

Context xamarin/xamarin-android#1154

One of the problems we currently face is that our build system
resolves `ref` netstandard libraries. With the current cache
system, onces an assembly has been loaded into the Cecil cache
it only ever uses that assembly. We might need to replace the
current cached version with a new one if we detect a `ref` and
need to reload the `lib`.

dellis1972 added a commit to dellis1972/xamarin-android that referenced this issue Mar 5, 2018

[Xamarin.Android.Build.Tasks] Better support for netstandard libraries.
Fixes xamarin#1154, xamarin#1162

Netstandard packages sometimes ship with both reference and
implementation assemblies. The Nuget build task `ResolveNuGetPackageAssets`
only resolves the `ref` version of the assemblies. There does
not seem to be away way to FORCE Nuget to resolve the lib one.
How .net Core manages to do this is still a mistery. That said
the Nuget `ResolveNuGetPackageAssets` does give us a hint as to
how to use the `project.assets.json` file to figure out what
`lib` version of the package we should be including.

This commit reworks `ResolveAssemblies` to attempt to map the
`ref` to a `lib` if we find a Referenece Assembly. Historically
we just issue a warning (which will probably be ignored), but
now we will use the `project.assets.json` file to find the
implementation version of the `ref` assembly.

We need to be using `NewtonSoft.Json` since it provides a decent
API for querying json. We make use of the Nuget build properties
`$(ProjectLockFile)` for the location of the `project.assets.json`
, `$(NuGetPackageRoot)` for the root folder of the Nuget packages
and `$(NuGetTargetMoniker)` and `$(_NuGetTargetFallbackMoniker)`
for resolving which `TargetFrameworks` we are looking for. All of these
properties should be set by Nuget. If they are not we should fallback
to the default behaviour and just issue the warning.

	{
  		"version": 3,
  		"targets": {
    			"MonoAndroid,Version=v8.1": {
				"System.IO.Packaging/4.4.0": {
					"type": "package",
					"compile": {
						"ref/netstandard1.3/System.IO.Packaging.dll": {}
					},
					"runtime": {
						"lib/netstandard1.3/System.IO.Packaging.dll": {}
					}
				},
			}
		}
	}

The code above is a cut down sample of the `project.assets.json`. So our
code will first resolve the `targets`. We use `$(NuGetTargetMoniker)` to
do this. For an android project this should have a value of
`MonoAndroid,Version=v8.1`. Note we do NOT need to worry about the version
here. When Nuget restores the packages it creates the file so it will
use the correct version.
Next we try to find the `System.IO.Packaging/4.4.0`. My first throught
was to use the version of the reference assembly we just loaded. But
in this package even though the nuget version was `4.4.0` the assembly
versioin was `4.0.2` .. so not helpful. So we need to just search for the
items starting with `System.IO.Packaging`. Next is to look for the `runtime`
item and then finally the value of that. Once we have resolved the path
we need to then combine that with the `$(NuGetPackageRoot)` to get the
full path to the new library. If at any point during all of this code
we don't get what we expect (i.e a null) we should abort and just issue
the warning.

The only real concern with this is if the format of the `project.assets.json`
file changes. It is not ment to be edited by a human so there is the
possibiltity that the Nuget team will decide to either change the schema or
even migrate to a new file format.
@jonpryor

This comment has been minimized.

Contributor

jonpryor commented Mar 5, 2018

@dellis1972: This is thought provoking: xamarin/xamarin-macios#3199 (comment)

With a .NET Core project, for example, there are two steps: build and publish. The build target compiles against the ref assembly. The publish target will result in the lib assembly being copied to the publish directory so it can be used at runtime.

Should we follow suite, such that our "Build" step can use reference assemblies, while the "Publish" step acquires and uses the actual assemblies?

Can we follow suite? Is such a change supportable by our build process?

@dellis1972

This comment has been minimized.

Contributor

dellis1972 commented Mar 5, 2018

ResolveAssemblies is what we use to pull together the list of assemblies we need to package. See #1356

jonpryor added a commit to xamarin/java.interop that referenced this issue Mar 5, 2018

[Java.Interop.Tools.Cecil] Change DirectoryAssemblyResolver to allow …
…forced loading. (#270)

Context: xamarin/xamarin-android#1154
Context: xamarin/xamarin-android#1356

One of the problems we currently face is that our build system
resolves `ref` netstandard libraries. With the current cache
system, onces an assembly has been loaded into the Cecil cache
it only ever uses that assembly. We might need to replace the
current cached version with a new one if we detect a `ref` and
need to reload the `lib`.

dellis1972 added a commit to dellis1972/xamarin-android that referenced this issue Mar 6, 2018

[Xamarin.Android.Build.Tasks] Better support for netstandard libraries.
Fixes xamarin#1154, xamarin#1162

Netstandard packages sometimes ship with both reference and
implementation assemblies. The Nuget build task `ResolveNuGetPackageAssets`
only resolves the `ref` version of the assemblies. There does
not seem to be away way to FORCE Nuget to resolve the lib one.
How .net Core manages to do this is still a mistery. That said
the Nuget `ResolveNuGetPackageAssets` does give us a hint as to
how to use the `project.assets.json` file to figure out what
`lib` version of the package we should be including.

This commit reworks `ResolveAssemblies` to attempt to map the
`ref` to a `lib` if we find a Referenece Assembly. Historically
we just issue a warning (which will probably be ignored), but
now we will use the `project.assets.json` file to find the
implementation version of the `ref` assembly.

We need to be using `NewtonSoft.Json` since it provides a decent
API for querying json. We make use of the Nuget build properties
`$(ProjectLockFile)` for the location of the `project.assets.json`
, `$(NuGetPackageRoot)` for the root folder of the Nuget packages
and `$(NuGetTargetMoniker)` and `$(_NuGetTargetFallbackMoniker)`
for resolving which `TargetFrameworks` we are looking for. All of these
properties should be set by Nuget. If they are not we should fallback
to the default behaviour and just issue the warning.

	{
  		"version": 3,
  		"targets": {
    			"MonoAndroid,Version=v8.1": {
				"System.IO.Packaging/4.4.0": {
					"type": "package",
					"compile": {
						"ref/netstandard1.3/System.IO.Packaging.dll": {}
					},
					"runtime": {
						"lib/netstandard1.3/System.IO.Packaging.dll": {}
					}
				},
			}
		}
	}

The code above is a cut down sample of the `project.assets.json`. So our
code will first resolve the `targets`. We use `$(NuGetTargetMoniker)` to
do this. For an android project this should have a value of
`MonoAndroid,Version=v8.1`. Note we do NOT need to worry about the version
here. When Nuget restores the packages it creates the file so it will
use the correct version.
Next we try to find the `System.IO.Packaging/4.4.0`. My first throught
was to use the version of the reference assembly we just loaded. But
in this package even though the nuget version was `4.4.0` the assembly
versioin was `4.0.2` .. so not helpful. So we need to just search for the
items starting with `System.IO.Packaging`. Next is to look for the `runtime`
item and then finally the value of that. Once we have resolved the path
we need to then combine that with the `$(NuGetPackageRoot)` to get the
full path to the new library. If at any point during all of this code
we don't get what we expect (i.e a null) we should abort and just issue
the warning.

The only real concern with this is if the format of the `project.assets.json`
file changes. It is not ment to be edited by a human so there is the
possibiltity that the Nuget team will decide to either change the schema or
even migrate to a new file format.

dellis1972 added a commit to dellis1972/xamarin-android that referenced this issue Mar 9, 2018

[Xamarin.Android.Build.Tasks] Better support for netstandard libraries.
Fixes xamarin#1154, xamarin#1162

Netstandard packages sometimes ship with both reference and
implementation assemblies. The Nuget build task `ResolveNuGetPackageAssets`
only resolves the `ref` version of the assemblies. There does
not seem to be away way to FORCE Nuget to resolve the lib one.
How .net Core manages to do this is still a mistery. That said
the Nuget `ResolveNuGetPackageAssets` does give us a hint as to
how to use the `project.assets.json` file to figure out what
`lib` version of the package we should be including.

This commit reworks `ResolveAssemblies` to attempt to map the
`ref` to a `lib` if we find a Referenece Assembly. Historically
we just issue a warning (which will probably be ignored), but
now we will use the `project.assets.json` file to find the
implementation version of the `ref` assembly.

We need to be using `NewtonSoft.Json` since it provides a decent
API for querying json. We make use of the Nuget build properties
`$(ProjectLockFile)` for the location of the `project.assets.json`
, `$(NuGetPackageRoot)` for the root folder of the Nuget packages
and `$(NuGetTargetMoniker)` and `$(_NuGetTargetFallbackMoniker)`
for resolving which `TargetFrameworks` we are looking for. All of these
properties should be set by Nuget. If they are not we should fallback
to the default behaviour and just issue the warning.

	{
  		"version": 3,
  		"targets": {
    			"MonoAndroid,Version=v8.1": {
				"System.IO.Packaging/4.4.0": {
					"type": "package",
					"compile": {
						"ref/netstandard1.3/System.IO.Packaging.dll": {}
					},
					"runtime": {
						"lib/netstandard1.3/System.IO.Packaging.dll": {}
					}
				},
			}
		}
	}

The code above is a cut down sample of the `project.assets.json`. So our
code will first resolve the `targets`. We use `$(NuGetTargetMoniker)` to
do this. For an android project this should have a value of
`MonoAndroid,Version=v8.1`. Note we do NOT need to worry about the version
here. When Nuget restores the packages it creates the file so it will
use the correct version.
Next we try to find the `System.IO.Packaging/4.4.0`. My first throught
was to use the version of the reference assembly we just loaded. But
in this package even though the nuget version was `4.4.0` the assembly
versioin was `4.0.2` .. so not helpful. So we need to just search for the
items starting with `System.IO.Packaging`. Next is to look for the `runtime`
item and then finally the value of that. Once we have resolved the path
we need to then combine that with the `$(NuGetPackageRoot)` to get the
full path to the new library. If at any point during all of this code
we don't get what we expect (i.e a null) we should abort and just issue
the warning.

The only real concern with this is if the format of the `project.assets.json`
file changes. It is not ment to be edited by a human so there is the
possibiltity that the Nuget team will decide to either change the schema or
even migrate to a new file format.

dellis1972 added a commit to dellis1972/xamarin-android that referenced this issue Mar 9, 2018

[Xamarin.Android.Build.Tasks] Better support for netstandard libraries.
Fixes xamarin#1154, xamarin#1162

Netstandard packages sometimes ship with both reference and
implementation assemblies. The Nuget build task `ResolveNuGetPackageAssets`
only resolves the `ref` version of the assemblies. There does
not seem to be away way to FORCE Nuget to resolve the lib one.
How .net Core manages to do this is still a mistery. That said
the Nuget `ResolveNuGetPackageAssets` does give us a hint as to
how to use the `project.assets.json` file to figure out what
`lib` version of the package we should be including.

This commit reworks `ResolveAssemblies` to attempt to map the
`ref` to a `lib` if we find a Referenece Assembly. Historically
we just issue a warning (which will probably be ignored), but
now we will use the `project.assets.json` file to find the
implementation version of the `ref` assembly.

We need to be using `Nuget.ProjectModel` since it an API for
querying the `project.assets.json`. We make use of the Nuget build properties
`$(ProjectLockFile)` for the location of the `project.assets.json`
, `$(NuGetPackageRoot)` for the root folder of the Nuget packages
and `$(NuGetTargetMoniker)` for resolving which `TargetFrameworks`
we are looking for. All of these properties should be set by Nuget.
If they are not we should fallback to the default behaviour and just issue the warning.

	{
  		"version": 3,
  		"targets": {
    			"MonoAndroid,Version=v8.1": {
				"System.IO.Packaging/4.4.0": {
					"type": "package",
					"compile": {
						"ref/netstandard1.3/System.IO.Packaging.dll": {}
					},
					"runtime": {
						"lib/netstandard1.3/System.IO.Packaging.dll": {}
					}
				},
			}
		}
	}

The code above is a cut down sample of the `project.assets.json`. So our
code will first resolve the `targets`. We use `$(NuGetTargetMoniker)` to
do this. For an android project this should have a value of
`MonoAndroid,Version=v8.1`. Note we do NOT need to worry about the version
here. When Nuget restores the packages it creates the file so it will
use the correct version.
Next we try to find the `System.IO.Packaging`. We need to look at the
`lockFile.Libraries` to get information about the install path in the
Nuget folder, and then `target.Libraries` to pick out the  `runtime`
item.
Once we have resolved the path we need to then combine that with the
`$(NuGetPackageRoot)` to get the full path to the new library. If at any
point during all of this code we don't get what we expect (i.e a null) we
should abort and just issue the warning.

The only real concern with this is if the format of the `project.assets.json`
file changes. It is not ment to be edited by a human so there is the
possibiltity that the Nuget team will decide to either change the schema or
even migrate to a new file format. Hopefully we can just update the `Nuget`
nuggets if that happens.

@jonpryor jonpryor added the vs-sync label Mar 12, 2018

dellis1972 added a commit to dellis1972/xamarin-android that referenced this issue Mar 13, 2018

[Xamarin.Android.Build.Tasks] Better support for netstandard libraries.
Fixes xamarin#1154, xamarin#1162

Netstandard packages sometimes ship with both reference and
implementation assemblies. The Nuget build task `ResolveNuGetPackageAssets`
only resolves the `ref` version of the assemblies. There does
not seem to be away way to FORCE Nuget to resolve the lib one.
How .net Core manages to do this is still a mistery. That said
the Nuget `ResolveNuGetPackageAssets` does give us a hint as to
how to use the `project.assets.json` file to figure out what
`lib` version of the package we should be including.

This commit reworks `ResolveAssemblies` to attempt to map the
`ref` to a `lib` if we find a Referenece Assembly. Historically
we just issue a warning (which will probably be ignored), but
now we will use the `project.assets.json` file to find the
implementation version of the `ref` assembly.

We need to be using `Nuget.ProjectModel` since it an API for
querying the `project.assets.json`. We make use of the Nuget build properties
`$(ProjectLockFile)` for the location of the `project.assets.json`
, `$(NuGetPackageRoot)` for the root folder of the Nuget packages
and `$(NuGetTargetMoniker)` for resolving which `TargetFrameworks`
we are looking for. All of these properties should be set by Nuget.
If they are not we should fallback to the default behaviour and just issue the warning.

	{
  		"version": 3,
  		"targets": {
    			"MonoAndroid,Version=v8.1": {
				"System.IO.Packaging/4.4.0": {
					"type": "package",
					"compile": {
						"ref/netstandard1.3/System.IO.Packaging.dll": {}
					},
					"runtime": {
						"lib/netstandard1.3/System.IO.Packaging.dll": {}
					}
				},
			}
		}
	}

The code above is a cut down sample of the `project.assets.json`. So our
code will first resolve the `targets`. We use `$(NuGetTargetMoniker)` to
do this. For an android project this should have a value of
`MonoAndroid,Version=v8.1`. Note we do NOT need to worry about the version
here. When Nuget restores the packages it creates the file so it will
use the correct version.
Next we try to find the `System.IO.Packaging`. We need to look at the
`lockFile.Libraries` to get information about the install path in the
Nuget folder, and then `target.Libraries` to pick out the  `runtime`
item.
Once we have resolved the path we need to then combine that with the
`$(NuGetPackageRoot)` to get the full path to the new library. If at any
point during all of this code we don't get what we expect (i.e a null) we
should abort and just issue the warning.

The only real concern with this is if the format of the `project.assets.json`
file changes. It is not ment to be edited by a human so there is the
possibiltity that the Nuget team will decide to either change the schema or
even migrate to a new file format. Hopefully we can just update the `Nuget`
nuggets if that happens.

dellis1972 added a commit to dellis1972/xamarin-android that referenced this issue Mar 15, 2018

[Xamarin.Android.Build.Tasks] Better support for netstandard libraries.
Fixes xamarin#1154, xamarin#1162

Netstandard packages sometimes ship with both reference and
implementation assemblies. The Nuget build task `ResolveNuGetPackageAssets`
only resolves the `ref` version of the assemblies. There does
not seem to be away way to FORCE Nuget to resolve the lib one.
How .net Core manages to do this is still a mistery. That said
the Nuget `ResolveNuGetPackageAssets` does give us a hint as to
how to use the `project.assets.json` file to figure out what
`lib` version of the package we should be including.

This commit reworks `ResolveAssemblies` to attempt to map the
`ref` to a `lib` if we find a Referenece Assembly. Historically
we just issue a warning (which will probably be ignored), but
now we will use the `project.assets.json` file to find the
implementation version of the `ref` assembly.

We need to be using `Nuget.ProjectModel` since it an API for
querying the `project.assets.json`. We make use of the Nuget build properties
`$(ProjectLockFile)` for the location of the `project.assets.json`
, `$(NuGetPackageRoot)` for the root folder of the Nuget packages
and `$(NuGetTargetMoniker)` for resolving which `TargetFrameworks`
we are looking for. All of these properties should be set by Nuget.
If they are not we should fallback to the default behaviour and just issue the warning.

	{
  		"version": 3,
  		"targets": {
    			"MonoAndroid,Version=v8.1": {
				"System.IO.Packaging/4.4.0": {
					"type": "package",
					"compile": {
						"ref/netstandard1.3/System.IO.Packaging.dll": {}
					},
					"runtime": {
						"lib/netstandard1.3/System.IO.Packaging.dll": {}
					}
				},
			}
		}
	}

The code above is a cut down sample of the `project.assets.json`. So our
code will first resolve the `targets`. We use `$(NuGetTargetMoniker)` to
do this. For an android project this should have a value of
`MonoAndroid,Version=v8.1`. Note we do NOT need to worry about the version
here. When Nuget restores the packages it creates the file so it will
use the correct version.
Next we try to find the `System.IO.Packaging`. We need to look at the
`lockFile.Libraries` to get information about the install path in the
Nuget folder, and then `target.Libraries` to pick out the  `runtime`
item.
Once we have resolved the path we need to then combine that with the
`$(NuGetPackageRoot)` to get the full path to the new library. If at any
point during all of this code we don't get what we expect (i.e a null) we
should abort and just issue the warning.

The only real concern with this is if the format of the `project.assets.json`
file changes. It is not ment to be edited by a human so there is the
possibiltity that the Nuget team will decide to either change the schema or
even migrate to a new file format. Hopefully we can just update the `Nuget`
nuggets if that happens.

dellis1972 added a commit to dellis1972/xamarin-android that referenced this issue Mar 20, 2018

[Xamarin.Android.Build.Tasks] Better support for netstandard libraries.
Fixes xamarin#1154, xamarin#1162

Netstandard packages sometimes ship with both reference and
implementation assemblies. The Nuget build task `ResolveNuGetPackageAssets`
only resolves the `ref` version of the assemblies. There does
not seem to be away way to FORCE Nuget to resolve the lib one.
How .net Core manages to do this is still a mistery. That said
the Nuget `ResolveNuGetPackageAssets` does give us a hint as to
how to use the `project.assets.json` file to figure out what
`lib` version of the package we should be including.

This commit reworks `ResolveAssemblies` to attempt to map the
`ref` to a `lib` if we find a Referenece Assembly. Historically
we just issue a warning (which will probably be ignored), but
now we will use the `project.assets.json` file to find the
implementation version of the `ref` assembly.

We need to be using `Nuget.ProjectModel` since it an API for
querying the `project.assets.json`. We make use of the Nuget build properties
`$(ProjectLockFile)` for the location of the `project.assets.json`
, `$(NuGetPackageRoot)` for the root folder of the Nuget packages
and `$(NuGetTargetMoniker)` for resolving which `TargetFrameworks`
we are looking for. All of these properties should be set by Nuget.
If they are not we should fallback to the default behaviour and just issue the warning.

	{
  		"version": 3,
  		"targets": {
    			"MonoAndroid,Version=v8.1": {
				"System.IO.Packaging/4.4.0": {
					"type": "package",
					"compile": {
						"ref/netstandard1.3/System.IO.Packaging.dll": {}
					},
					"runtime": {
						"lib/netstandard1.3/System.IO.Packaging.dll": {}
					}
				},
			}
		}
	}

The code above is a cut down sample of the `project.assets.json`. So our
code will first resolve the `targets`. We use `$(NuGetTargetMoniker)` to
do this. For an android project this should have a value of
`MonoAndroid,Version=v8.1`. Note we do NOT need to worry about the version
here. When Nuget restores the packages it creates the file so it will
use the correct version.
Next we try to find the `System.IO.Packaging`. We need to look at the
`lockFile.Libraries` to get information about the install path in the
Nuget folder, and then `target.Libraries` to pick out the  `runtime`
item.
Once we have resolved the path we need to then combine that with the
`$(NuGetPackageRoot)` to get the full path to the new library. If at any
point during all of this code we don't get what we expect (i.e a null) we
should abort and just issue the warning.

The only real concern with this is if the format of the `project.assets.json`
file changes. It is not ment to be edited by a human so there is the
possibiltity that the Nuget team will decide to either change the schema or
even migrate to a new file format. Hopefully we can just update the `Nuget`
nuggets if that happens.

jonpryor added a commit that referenced this issue Mar 21, 2018

dellis1972 added a commit to dellis1972/xamarin-android that referenced this issue Mar 21, 2018

[Xamarin.Android.Build.Tasks] Better support for netstandard libraries.
Fixes xamarin#1154, xamarin#1162

Netstandard packages sometimes ship with both reference and
implementation assemblies. The Nuget build task `ResolveNuGetPackageAssets`
only resolves the `ref` version of the assemblies. There does
not seem to be away way to FORCE Nuget to resolve the lib one.
How .net Core manages to do this is still a mistery. That said
the Nuget `ResolveNuGetPackageAssets` does give us a hint as to
how to use the `project.assets.json` file to figure out what
`lib` version of the package we should be including.

This commit reworks `ResolveAssemblies` to attempt to map the
`ref` to a `lib` if we find a Referenece Assembly. Historically
we just issue a warning (which will probably be ignored), but
now we will use the `project.assets.json` file to find the
implementation version of the `ref` assembly.

We need to be using `Nuget.ProjectModel` since it an API for
querying the `project.assets.json`. We make use of the Nuget build properties
`$(ProjectLockFile)` for the location of the `project.assets.json`
, `$(NuGetPackageRoot)` for the root folder of the Nuget packages
and `$(NuGetTargetMoniker)` for resolving which `TargetFrameworks`
we are looking for. All of these properties should be set by Nuget.
If they are not we should fallback to the default behaviour and just issue the warning.

	{
  		"version": 3,
  		"targets": {
    			"MonoAndroid,Version=v8.1": {
				"System.IO.Packaging/4.4.0": {
					"type": "package",
					"compile": {
						"ref/netstandard1.3/System.IO.Packaging.dll": {}
					},
					"runtime": {
						"lib/netstandard1.3/System.IO.Packaging.dll": {}
					}
				},
			}
		}
	}

The code above is a cut down sample of the `project.assets.json`. So our
code will first resolve the `targets`. We use `$(NuGetTargetMoniker)` to
do this. For an android project this should have a value of
`MonoAndroid,Version=v8.1`. Note we do NOT need to worry about the version
here. When Nuget restores the packages it creates the file so it will
use the correct version.
Next we try to find the `System.IO.Packaging`. We need to look at the
`lockFile.Libraries` to get information about the install path in the
Nuget folder, and then `target.Libraries` to pick out the  `runtime`
item.
Once we have resolved the path we need to then combine that with the
`$(NuGetPackageRoot)` to get the full path to the new library. If at any
point during all of this code we don't get what we expect (i.e a null) we
should abort and just issue the warning.

The only real concern with this is if the format of the `project.assets.json`
file changes. It is not ment to be edited by a human so there is the
possibiltity that the Nuget team will decide to either change the schema or
even migrate to a new file format. Hopefully we can just update the `Nuget`
nuggets if that happens.

jonpryor added a commit that referenced this issue Mar 21, 2018

[Xamarin.Android.Build.Tasks] Better support for netstandard librarie…
…s. (#1356)

Fixes: #1154
Fixes: #1162

NetStandard packages sometimes ship with both reference and
implementation assemblies. The NuGet build task
`<ResolveNuGetPackageAssets/>` only resolves the `ref` version of the
assemblies. There does not seem to be away way to *force* NuGet to
resolve the lib one.

This commit reworks the `<ResolveAssemblies/>` task to attempt to map
the `ref` to a `lib` if we find a Referenece Assembly. Historically
we just issue a warning (which will probably be ignored), but
now we will use the `project.assets.json` file to find the
implementation version of the `ref` assembly, by using the
`NuGet.ProjectModel` package to find the library which is associated
with a reference assembly.

We thus "ignore" reference assemblies, using the "referenced"/"real"
assemblies instead, to ensure that our existing build process
continues to generate usable packages.

*Note*: An alternative approach would be to "embrace" reference
assemblies, allowing them to be used in the build. This doesn't
currently work with our build system, as we assume assemblies will
contain native libraries, Android resources, and other artifacts
which must be extracted at build time, and reference assemblies will
not contain these artifacts.

We would like to explore the "embrace" strategy, but this will
require far more effort to support.

jonpryor added a commit that referenced this issue Mar 21, 2018

[Xamarin.Android.Build.Tasks] Better support for netstandard librarie…
…s. (#1356)

Fixes: #1154
Fixes: #1162

NetStandard packages sometimes ship with both reference and
implementation assemblies. The NuGet build task
`<ResolveNuGetPackageAssets/>` only resolves the `ref` version of the
assemblies. There does not seem to be away way to *force* NuGet to
resolve the lib one.

This commit reworks the `<ResolveAssemblies/>` task to attempt to map
the `ref` to a `lib` if we find a Referenece Assembly. Historically
we just issue a warning (which will probably be ignored), but
now we will use the `project.assets.json` file to find the
implementation version of the `ref` assembly, by using the
`NuGet.ProjectModel` package to find the library which is associated
with a reference assembly.

We thus "ignore" reference assemblies, using the "referenced"/"real"
assemblies instead, to ensure that our existing build process
continues to generate usable packages.

*Note*: An alternative approach would be to "embrace" reference
assemblies, allowing them to be used in the build. This doesn't
currently work with our build system, as we assume assemblies will
contain native libraries, Android resources, and other artifacts
which must be extracted at build time, and reference assemblies will
not contain these artifacts.

We would like to explore the "embrace" strategy, but this will
require far more effort to support.

jonpryor added a commit to xamarin/java.interop that referenced this issue Mar 22, 2018

[Java.Interop.Tools.Cecil] Change DirectoryAssemblyResolver to allow …
…forced loading. (#270)

Context: xamarin/xamarin-android#1154
Context: xamarin/xamarin-android#1356

One of the problems we currently face is that our build system
resolves `ref` netstandard libraries. With the current cache
system, onces an assembly has been loaded into the Cecil cache
it only ever uses that assembly. We might need to replace the
current cached version with a new one if we detect a `ref` and
need to reload the `lib`.

jonpryor added a commit that referenced this issue Mar 22, 2018

Bump to Java.Interop/d15-7/4e1965d5
Context: #1154
Context: #1356

Commit c7b9a50 [broke the build][0], because we neglected to
cherry-pick a dependency from Java.Interop (doh!):

[0]: https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android-d15-7/13/

	Tasks/ResolveAssemblies.cs(183,32): error CS1739: The best overload for 'Load' does not have a parameter named 'forceLoad'

Bump to Java.Interop/d15-7/4e1965d5, which adds the
`DirectoryAssemblyResolver.Load(string fileName, bool forceLoad)`
overload, which should fix the above error.
@alexdrl

This comment has been minimized.

alexdrl commented Jun 13, 2018

I am getting this error with the same Project that made me opened this issue, using VS 15.7.3. I Thought that the issue was closed because the problem is solved but I tried with no luck.

It is blocked bt Microsoft/msbuild#2776 ?

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