Skip to content
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

Minimal Android cross platform project with Microsoft.EntityFrameworkCore gives reference error #2534

Closed
samhouts opened this issue Dec 14, 2018 · 8 comments

Comments

@samhouts
Copy link
Member

@samhouts samhouts commented Dec 14, 2018

From @davefxy on September 17, 2018 21:16

Description

Create a Android cross platform solution without adding any code, add the Microsoft.EntityFrameworkCore
nuget package to both of the projects in the solution, gets the reference error.

Steps to Reproduce

  1. Create a Android cross platform project and add nuget pkg Microsoft.EntityFrameworkCore

  2. Compile

  3. Error Can not resolve reference: System.Buffers, referenced by System.Memory. Please add a NuGet package or assembly reference for System.Buffers, or remove the reference to System.Memory. EFAndroidProblem.Android

Expected Behavior

Clean compile

Actual Behavior

Compiles with reference error

Basic Information

  • Version with issue:
    Xamarin forms 3.2.0.839982
  • Last known good version:
  • IDE:
    Visual Studio 2017 (PC) 15.8.4
  • Platform Target Frameworks:
    Android: 8.1 (Oreo) & 9.0
  • Android Support Library Version:
  • Nuget Packages:
    Xamarin.Forms v3.2.0.839982
    NETStandard.Library v2.0.3
    Microsoft.EntityFrameworkCore v2.1.3
  • Affected Devices:

Screenshots

Reproduction Link

Copied from original issue: xamarin/Xamarin.Forms#3810

@samhouts

This comment has been minimized.

Copy link
Member Author

@samhouts samhouts commented Dec 14, 2018

From @hartez on October 19, 2018 4:48

See also: dotnet/efcore#13631

@samhouts

This comment has been minimized.

Copy link
Member Author

@samhouts samhouts commented Dec 14, 2018

From @hartez on October 19, 2018 4:48

Reproduction of issue:

_3810 Repro.zip

@samhouts

This comment has been minimized.

Copy link
Member Author

@samhouts samhouts commented Dec 14, 2018

From @divega on November 4, 2018 16:50

@marek-safar just to have it cross-referenced here, this seems similar to the issue reported in dotnet/efcore#13631, only different versions of EF Core are used.

If this repros consistently, it may be a blocker for using recent versions of EF Core with Xamarin Android.

@samhouts

This comment has been minimized.

Copy link
Member Author

@samhouts samhouts commented Dec 14, 2018

From @tipa on December 5, 2018 12:9

This issue also happens using Xamarin.Android

@samhouts

This comment has been minimized.

Copy link
Member Author

@samhouts samhouts commented Dec 14, 2018

From @fourth-vasilpopov on December 10, 2018 9:57

For now, seems there is "compatible" System.Memory nuget package (labelled "v.4.5.n-servicing-27114-05"). To install, you need to click on "Include prerelease" checkbox to get it.

@brendanzagaeski

This comment has been minimized.

Copy link
Member

@brendanzagaeski brendanzagaeski commented Dec 16, 2018

I took a first look at this to see who would know the most about it. I think @dellis1972, @jonathanpeppers, and @jonpryor might all be interested. I found a few things that might help in deciding how to address the issue.

Steps to Reproduce

Attempt to build the sample project attached earlier in this report, or:

  1. Create a new Xamarin.Android application project.
  2. Add the Microsoft.EntityFrameworkCore version 2.2.0 NuGet package.
  3. Attempt to build the project in the Debug or Release configuration.

Actual Behavior

The build fails with an error:

(_ResolveAssemblies target) -> 
 C:\Program Files (x86)\Microsoft Visual
 Studio\2017\Enterprise\MSBuild\Xamarin\Android\Xamarin.Android.Common.targets(1898,2):
 error XA2002: Can not resolve reference: `System.Buffers`, referenced by
 `System.Memory`. Please add a NuGet package or assembly reference for
 `System.Buffers`, or remove the reference to `System.Memory`.

Workaround

Explicitly install the System.Buffers NuGet package into the Xamarin.Android app project.

(This is a workaround rather than a fix because it should not be necessary to reference the System.Buffers package explicitly when using PackageReference-style package management. The fact that the Microsoft.EntityFrameworkCore package has a dependency on the System.Buffers package should be sufficient.)

Preliminary Investigation

The Microsoft.AspNetCore.SignalR.Client.Core version 1.1.0 NuGet package also depends on the System.Memory package, so why doesn't a project that references that instead of the EntityFrameworkCore package hit the same error?

The obj\project.assets.json files that get generated when using the NuGet packages provide some clues. Here is a diff of the System.Buffers entry from that file, comparing what gets generated when the project has a package reference to EntityFrameworkCore versus a package reference to SignalR.Client.Core:

-      "System.Buffers/4.4.0": {
+      "System.Buffers/4.5.0": {
         "type": "package",
         "compile": {
-          "ref/netstandard2.0/_._": {}
+          "ref/netstandard2.0/System.Buffers.dll": {}
         },
         "runtime": {
           "lib/netstandard2.0/System.Buffers.dll": {}

So the reason the SignalR.Client.Core scenario doesn't produce a build error is that the build process references ref/netstandard2.0/System.Buffers.dll rather than the empty placeholder _._.

Is the compile entry different because the System.Buffers version is 4.5.0 rather than 4.4.0?

It looks like the answer is "no." I haven't checked the NuGet package manager source to confirm it, but I think the important difference is instead related to whether any of the compile entries in obj\project.assets.json point to a library that has an assembly reference to System.Buffers. For example, the compile entry for SignalR.Common points to the full lib/netstandard2.0/Microsoft.AspNetCore.SignalR.Common.dll assembly:

"Microsoft.AspNetCore.SignalR.Common/1.1.0": {
  "type": "package",
  "dependencies": {
    "Microsoft.AspNetCore.Connections.Abstractions": "2.2.0",
    "Microsoft.Extensions.Options": "2.2.0",
    "Newtonsoft.Json": "11.0.2",
    "System.Buffers": "4.5.0"
  },
  "compile": {
    "lib/netstandard2.0/Microsoft.AspNetCore.SignalR.Common.dll": {}
  },
  "runtime": {
    "lib/netstandard2.0/Microsoft.AspNetCore.SignalR.Common.dll": {}
  }
},

Which does have an assembly reference to System.Buffers as shown by the MANIFEST in ildasm:

.assembly extern System.Buffers
{
  .publickeytoken = (CC 7B 13 FF CD 2D DD 51 )                         // .{...-.Q
  .ver 4:0:2:0
}

In contrast, in the EntityFrameworkCore case, only the System.Memory NuGet package depends on the System.Buffers package, and the compile entry for that is a reference assembly:

"System.Memory/4.5.1": {
  "type": "package",
  "dependencies": {
    "System.Buffers": "4.4.0",
    "System.Runtime.CompilerServices.Unsafe": "4.5.0"
  },
  "compile": {
    "ref/netstandard2.0/System.Memory.dll": {}
  },
  "runtime": {
    "lib/netstandard2.0/System.Memory.dll": {}
  }
},

Which does not have an assembly reference to System.Buffers. (I suspect this is normal for reference assemblies. The runtime library lib/netstandard2.0/System.Memory.dll does have an assembly reference to System.Buffers.)

So why does compile point to lib/ in one case and ref/ in the other?

It appears the answer is just that the NuGet package for Microsoft.AspNetCore.SignalR.Common does not have a ref/ directory at all, so the NuGet package manager falls back to the lib/ assembly instead. In other words, the NuGet package manager preferentially chooses reference assemblies if they exist, but uses the full libraries if they don't.

Potential Fixes

Based on the story up to this point, it seems that the special handling of reference assemblies in ResolveAssemblies might need to be extended so that it not only looks up and adds the runtime assembly for each reference assembly but also looks up any corresponding dependencies entries in the obj\project.assets.json lock file and adds the runtime assemblies for each of those dependencies too.

Here are a couple remaining questions that might change the story:

  • As noted in the earlier comment by fourth-vasilpopov, installing the System.Memory prerelease version 4.5.2-servicing-27114-05 NuGet package solves the error about System.Buffers. The reason is that it does not contain reference assemblies. I'm not yet familiar enough with reference assemblies to know why this would have changed or if it might mean that in the future Xamarin.Android won't have to worry about handling reference assemblies in NuGet packages at all because they won't contain any anymore.
  • How do .NET Framework console projects determine which assemblies to copy into the output bin directory for PackageReference items? Could that mechanism be re-used for Xamarin.Android, or does the ResolveAssemblies task do some other special things that are unique to Xamarin.Android? (From a quick look at ResolveAssemblies, I see that one thing that might require special handling is .mdb files.)
@jonathanpeppers

This comment has been minimized.

Copy link
Member

@jonathanpeppers jonathanpeppers commented Dec 18, 2018

@brendanzagaeski I tried on master and I think this is working: master...jonathanpeppers:efcore-test

I suspect the latest Mono and this PR fixes this problem: #2450 where they added System.Buffers.dll as a facade assembly.

Should I still make a PR adding this test? I feel like I keep seeing issues about EF Core broken on Xamarin.Android, maybe it's always been the same issue?

@brendanzagaeski

This comment has been minimized.

Copy link
Member

@brendanzagaeski brendanzagaeski commented Jan 31, 2019

The original cause of the problem for the Microsoft.EntityFrameworkCore version 2.2.0 NuGet package is indeed now resolved in Visual Studio 2019 Preview 2. The latest Xamarin.Android now provides its own System.Memory.dll facade assembly, circumventing the NuGet package problem. I will accordingly close this original issue as resolved in Visual Studio 2019 Preview 2 by #2450

I have filed a separate follow-up issue #2674 for the more general problem that could affect other NuGet packages in the future if they use the exclude="Compile" attribute in their .nuspec files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.