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

NuGet PackageReference style incorrectly selects 'bait' dll in NuGet package using 'bait and switch' pattern #2776

Closed
kelly987654 opened this issue Dec 5, 2017 · 28 comments
Labels

Comments

@kelly987654
Copy link

Summary

A Xamarin.Forms project using a NetStandard class library for the Portable code, and the PackageReference NuGet package style in the corresponding Android project, incorrectly selects the 'bait' dll within a referenced 'Bait and Switch'-style NuGet package when compiling the Android App, resulting in a 'method or operation not implemented' exception on starting the App.

Note: The same project correctly compiles the Android-specific 'Switch' dll when using the packages.config NuGet style in the Android project.

Steps to reproduce

  1. Create a Xamarin.Forms PCL project using the PackageReference NuGet package style
  2. Update the Portable project to target NetStandard
  3. Install a NuGet package in the Portable and Android projects that uses the 'bait and switch' pattern (i.e. SocketLite.Pcl)
  4. Build the Android project
  5. Open the \obj\Debug\android\assets folder, find the installed 'bait and switch' dll. The build process has incorrectly grabbed the 'bait' dll instead of the platform-specific implementation.
  6. Deploy the app -> the app crashes due to an 'un-implemented message

Sample projects

The below sample projects use SocketLite.PCL as an example package using the Bait-and-Switch pattern.

The below project uses the packages.config style in the Android project, and correctly compiles the Android-specific SocketLite.dll
BaitAndSwitchSample.zip

The below project is identical, but uses the PackageReference style in the Android project, and incorrectly compiles the 'bait' dll instead of the Android-specific SocketLite.dll. This project catches and displays the 'unimplemented method' exception.
BaitAndSwitchSample-X.zip

Environment data

Visual Studio Version 15.4.4

@jalbertSyncroTech
Copy link

I'm seeing this as well, seems to be related to this issue

Android 7.1 project using project.json chooses netstandard-1.6 dependencies, over monoandroid #5759
NuGet/Home#5759

@kelly987654
Copy link
Author

Has anyone had a chance to take a look at this? We have encountered this issue several times now in different applications.

@dsplaisted
Copy link
Member

dsplaisted commented Jan 13, 2018 via email

@kzu
Copy link
Contributor

kzu commented Jan 13, 2018

I've no idea where to even start looking @dsplaisted :(. Wouldn't this be a NuGet restore issue rather?

@dsplaisted
Copy link
Member

@kzu Yes, it sounds like something NuGet related, but I haven't heard of this issue before, so I think it might be specific to Xamarin projects.

@kzu
Copy link
Contributor

kzu commented Jan 16, 2018 via email

@mhutch
Copy link
Member

mhutch commented Jan 16, 2018

The NuGet has implementation assemblies for Android, but the reference assembles are NetStandard.

"compile": {
  "ref/netstandard1.0/ISocketLite.PCL.dll": {},
  "ref/netstandard1.0/SocketLite.dll": {}
},
"runtime": {
  "lib/MonoAndroid10/ISocketLite.PCL.dll": {},
  "lib/MonoAndroid10/SocketLite.dll": {}
}

Xamarin.Android packaging (and resource extraction) steps appear to be picking up the reference assemblies instead of the implementation assemblies. /cc @dellis1972 @jonpryor

@dellis1972
Copy link

This is related to dotnet/android#1154 and dotnet/android#1162

My investigation however shows that the @(ReferencePath) ItemGroup which MSBuild provides us contains the ref version of the NetStandard assembly, not the lib version for Android Projects.

@kelly987654
Copy link
Author

Okay thanks for looking into this! So you think it is an msbuild issue?

@muhaym
Copy link

muhaym commented Jan 31, 2018

It seems this issue is affecting lot of Nuget libraries, even in Xamarin iOS. Any workaround?

@dellis1972
Copy link

The only work around I can think of for now is to directly reference the lib version of the library in the iOS/Andorid app.

@radical I think this is related to dotnet/android#1154 and dotnet/android#1162. Looks like it effects iOS too.

@kelly987654
Copy link
Author

kelly987654 commented Jan 31, 2018

My current "workaround" is to change the Android project to use packages.config instead.

I tried directly referencing the lib from the Android project, and I was getting compilation errors.

@muhaym
Copy link

muhaym commented Feb 1, 2018

I'm trying to update my Library https://github.com/muhaym/CrossPlacePicker, and can't test it in Android because of this issue

@jalbertSyncroTech
Copy link

jalbertSyncroTech commented Feb 19, 2018

I recently updated my Android project, which was already using PackageReference successfully, to update all of the 3rd party dependencies, which also required updating my target from MonoAndroid71 to MonoAndroid80.

One of the dependencies is ReactiveUI 8.0.0-alpha0117, which uses the bait and switch pattern.

Everything initially worked, however I later needed to back date to MonoAndroid71 after which I started getting the following error from ReactiveUI: "You are referencing the Portable version of ReactiveUI in an App. Reference the platform-specific version." I verified that going back to MonoAndroid80 resolves the issue.

I'm going to put my update on hold, but can anybody here with more information on the issue explain why I might be seeing this with MonoAndroid71 and not with MonoAndroid80?

@kelly987654
Copy link
Author

Is there any update on this?

@kzu
Copy link
Contributor

kzu commented Mar 9, 2018

Related to this: dotnet/android#1154 and dotnet/android#1162

@MagicAndre1981
Copy link

any update? This also blocks me

@kzu
Copy link
Contributor

kzu commented Aug 24, 2018

@dellis1972 I think there was a fix for this, right?

@MagicAndre1981
Copy link

@kzu I "fixed" it by using packages.config instead of PackageReference

@dellis1972
Copy link

We merged a fix for our ResolveAssemblies but that I suspect doesn't help in this case. This looks like a different msbuild issue. If I remember rightly it was because the PackageRefernce did not contain a hint path .. but the one added via a package.config did. And that path had the correct lib path.

@MagicAndre1981
Copy link

what is the status of the issue?

@bgavrilMS
Copy link

Starting a few weeks ago, Microsot.Identity.Client uses bait and switch and customers have started reporting issues. What is the status of this issue?

@bugail
Copy link

bugail commented Jan 24, 2019

We've started to see this issue using the latest version of Microsoft.Identity.Client (2.7.0) in our Xamarin android app when building remotely, everything seems fine when building locally. Are there updates on this?

@veikkoeeva
Copy link

veikkoeeva commented Apr 28, 2019

It seems like this same issues comes up using ProjectReference Include (currently on VS 2019, likely elsewhere too) when the target is NET 4.6.1 and use Worker or Web Roles and includes packages such as System.Runtime.CompilerServices.Unsafe (possibly others such as System.Memory etc.). The result is a runtime failure some type could not be loaded, such as ReadOnlySpan if a dependent library/Nuget package or code uses it either directly or functions such as AsSpan (as an aside, maybe one fix is also to install the appropriate .NET Core/Standard libraries to the target environment).

Going into Nuget packages and replacing ref packages with lib ones fixes the issue. I tried quickly a targets fix as proposed at dotnet/android#1162 (comment) (amongst other places), but it doesn't work. MSBuild reports

The target "_ResolveAssemblies" listed in an AfterTargets attribute at "\ReplaceRefAssemblies.targets (2,39)" does not exist in the project, and will be ignored.

So maybe it's different in Xamarin or something has shifted (or maybe I just looked the output too hastily and it was a different project, it's Sunday and this is more work related. :)). If someone knows of the cuff the right target/changes, that'd be nice. Hopefully I dropped enough key words for search engine fu too to those who come from another angle. :)

@veikkoeeva
Copy link

FYI, I don't know if something like this would better

<Project>
  <Target Name="ReplaceRefAssemblies" AfterTargets="ResolveAssemblyReferences">
    <ItemGroup>
      <ResolvedAssembliesFixedWindows Include="@(ReferencePath->Replace('\ref\','\lib\'))" />
      <ResolvedAssembliesFixedUnix Include="@(ReferencePath->Replace('/ref/','/lib/'))" />
      <ResolvedAssembliesFixed Include="@(ResolvedAssembliesFixedWindows)" Condition="@(ResolvedAssembliesFixedWindows) != @(ReferencePath)" />
      <ResolvedAssembliesFixed Include="@(ResolvedAssembliesFixedUnix)" Condition="@(ResolvedAssembliesFixedUnix) != @(ReferencePath)" />
      <ResolvedAssemblies Condition="'@(ResolvedAssembliesFixed->Count())' &gt; 0" Remove="@(ReferencePath)" />	  
      <ReferencePath Include="@(ResolvedAssembliesFixed)" />
    </ItemGroup>
  </Target>
</Project>

Or perhaps

<Project>
  <Target Name="ReplaceRefAssemblies" AfterTargets="ResolveAssemblyReferences">
    <ItemGroup>
      <ResolvedAssembliesFixedWindows Include="@(_ResolveAssemblyReferenceResolvedFiles->Replace('\ref\','\lib\'))" />
      <ResolvedAssembliesFixedUnix Include="@(_ResolveAssemblyReferenceResolvedFiles->Replace('/ref/','/lib/'))" />
      <ResolvedAssembliesFixed Include="@(ResolvedAssembliesFixedWindows)" Condition="@(ResolvedAssembliesFixedWindows) != @(_ResolveAssemblyReferenceResolvedFiles)" />
      <ResolvedAssembliesFixed Include="@(ResolvedAssembliesFixedUnix)" Condition="@(ResolvedAssembliesFixedUnix) != @(_ResolveAssemblyReferenceResolvedFiles)" />
      <ResolvedAssemblies Condition="'@(ResolvedAssembliesFixed->Count())' &gt; 0" Remove="@(_ResolveAssemblyReferenceResolvedFiles)" />	  
      <_ResolveAssemblyReferenceResolvedFiles Include="@(ResolvedAssembliesFixed)" />
    </ItemGroup>
  </Target>
</Project> 

but they don't work. The first one print an error

CSC error CS0006: Metadata file 'C:\Program Files\dotnet\sdk\NuGetFallbackFolder\system.text.encoding.codepages\4.3.0\lib\netstandard1.3\System.Text.Encoding.CodePages.dll' could not be found [C:<path>some.csproj]

And the reason appears to be that the ref folder in this particular case isn't "symmetrical" with the lib one. So there ought be another way, perhaps listing the changed paths one-by-one or have an exclusion list if it doesn't matter (e.g. the program functions properly).

@bugail
Copy link

bugail commented Jul 11, 2019

This is still an issue for Microsoft.Identity.Client (4.1.0) in our Xamarin android app when building remotely, everything seems fine when building locally. Are there updates on this?

@rainersigwald
Copy link
Member

Closing in favor of the Xamarin issues (which may now be fixed? Not totally clear to me at the moment.)

@MagicAndre1981
Copy link

MagicAndre1981 commented Mar 18, 2020

Closing in favor of the Xamarin issues (which may now be fixed? Not totally clear to me at the moment.)

For VS2017, the issue is still present, but even worse, I get issues about System.Threading.Tasks.Extensions.

For VS2019, the Xamarin Team, made a lot of changes compared to 15.9 but with VS2019 the compile also randomly fails with useless messages about missing files (from used nugets).

I gave it up on both (VS2017, VS2019) using PackageReference Include and always use the packages.config, which always works fine.

@AR-May AR-May added the triaged label Feb 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests