Xamarin-macios: Toolchain prefers buildin facade SDKs over NuGet packages depending on RestoreProjectStyle

Created on 3 Mar 2020  路  14Comments  路  Source: xamarin/xamarin-macios

Steps to Reproduce

  1. Create a solution with an iOS project and a Core project as a NET Standard 2.0 library. Reference the Core from the iOS project
  2. Ensure the linker is turned on, at least to SdkOnly.
  3. In the iOS project set the RestoreProjectStyle to PackageReference
  4. Add a reference to the System.IO.FileSystem.AccessControl nuget in both projects
  5. Use the FileSystemAclExtensions.Create extension method for DirectoryInfo like so:
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "docs");
var info = new DirectoryInfo(path);
info.Create(new DirectorySecurity()); // <--
  1. Compile the iOS project

Why am I trying to include this extension method? I'm not directly doing that but other libraries like System.IO.Abstractions do.

Additionally the same setup works for Android just fine.

Expected Behavior

The project should compile just fine.

Actual Behavior

The compilation fails with this error:

MTOUCH: Error MT2101: Can't resolve the reference 'System.Void System.IO.FileSystemAclExtensions::Create(System.IO.DirectoryInfo,System.Security.AccessControl.DirectorySecurity)', referenced from the method 'System.Void Solution.Core.DirectoryStuff::DoStuff()' in 'System.IO.FileSystem.AccessControl, Version=4.0.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. (MT2101) (Solution.IOS)

Additional Information

When building my real project I also get the following warning in the build log but not for the example project. Not sure what's the reason for that.

MTOUCH : warning MT0109: The assembly 'System.IO.FileSystem.AccessControl.dll' was loaded from a different path than the provided path (provided path: /Users/mkuckert/.nuget/packages/system.io.filesystem.accesscontrol/4.7.0/runtimes/win/lib/netstandard2.0/System.IO.FileSystem.AccessControl.dll, actual path: /Library/Frameworks/Xamarin.iOS.framework/Versions/13.10.0.17/lib/mono/Xamarin.iOS/Facades/System.IO.FileSystem.AccessControl.dll). [REALPROJECT.iOS/REALPROJECT.iOS.csproj]

As one can see in the build logs the System.IO.FileSystem.AccessControl.dll is included twice: Once from the nuget package and than again from the SDK facades from /Library/Frameworks/Xamarin.iOS.framework/Versions/13.10.0.17/lib/mono/Xamarin.iOS/Facades/System.IO.FileSystem.AccessControl.dll. The later does not include the FileSystemAclExtensions::Create(DirectoryInfo,DirectorySecurity) extension method.

The project does compile if RestoreProjectStyle is not set to PackageReference and the nuget package is referenced using the older Reference element with the HintPath. The warning changes to the following:

MTOUCH : warning MT0109: The assembly 'System.IO.FileSystem.AccessControl.dll' was loaded from a different path than the provided path (provided path: /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/mono/Xamarin.iOS/Facades/System.IO.FileSystem.AccessControl.dll, actual path: /Users/mkuckert/Downloads/sandbox2/Solution1/packages/System.IO.FileSystem.AccessControl.4.7.0/lib/netstandard2.0/System.IO.FileSystem.AccessControl.dll).

In this case the toolchain prefers the nuget package over the SDKs facade.

Is it possible to include the FileSystemAclExtensions in the shipped facade dll so that RestoreProjectStyle=PackageReference is possible? Or make some project settings so that the toolchain prefers the nuget version over the shipped facade dll? Or can I instruct the linker to completely remove all calls to the non-existing extension method, which would work in my special case?

Environment

=== Visual Studio Community 2019 for Mac ===

Version 8.4.7 (build 17)
Installation UUID: 68405758-72b3-4c99-a0d5-f9c4c70e8bb9
    GTK+ 2.24.23 (Raleigh theme)
    Xamarin.Mac 5.16.1.25 (issue-7441-d16-3-vsmac / 881172e73)

    Package version: 606000166

=== Mono Framework MDK ===

Runtime:
    Mono 6.6.0.166 (2019-08/d9001b5ae70) (64-bit)
    Package version: 606000166

=== Roslyn (Language Service) ===

3.4.0-beta4-19562-05+ff930dec4565e2bc424ad3bf3e22ecb20542c87d

=== NuGet ===

Version: 5.3.0.6192

=== .NET Core SDK ===

SDK: /usr/local/share/dotnet/sdk/3.1.102/Sdks
SDK Versions:
    3.1.102
    3.1.101
    3.0.100
    2.2.402
    2.2.203
    2.2.105
    2.1.504
    2.1.503
    2.1.302
    2.1.301
    2.1.300
    2.1.101
    2.1.4
    2.0.3
    2.0.0
    1.0.4
MSBuild SDKs: /Library/Frameworks/Mono.framework/Versions/6.6.0/lib/mono/msbuild/Current/bin/Sdks

=== .NET Core Runtime ===

Runtime: /usr/local/share/dotnet/dotnet
Runtime Versions:
    3.1.2
    3.1.1
    3.0.0
    2.2.7
    2.2.4
    2.2.3
    2.1.15
    2.1.8
    2.1.7
    2.1.2
    2.1.1
    2.1.0
    2.0.6
    2.0.5
    2.0.3
    2.0.0
    1.1.2
    1.0.5

=== Xamarin.Profiler ===

Version: 1.6.13.11
Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler

=== Updater ===

Version: 11

=== Xamarin Designer ===

Version: 16.4.0.479
Hash: 074544417
Branch: remotes/origin/d16-4
Build date: 2020-01-22 22:50:22 UTC

=== Xamarin.Android ===

Version: 10.1.3.7 (Visual Studio Community)
Commit: xamarin-android/d16-4/d66aed0
Android SDK: /Library/Developer/android-sdk
    Supported Android versions:
        5.1 (API level 22)
        8.1 (API level 27)

SDK Tools Version: 26.1.1
SDK Platform Tools Version: 29.0.5
SDK Build Tools Version: 29.0.2

Build Information: 
Mono: fd9f379
Java.Interop: xamarin/java.interop/d16-4@c4e569f
ProGuard: xamarin/proguard/master@905836d
SQLite: xamarin/sqlite/3.28.0@46204c4
Xamarin.Android Tools: xamarin/xamarin-android-tools/master@9f4ed4b

=== Microsoft Mobile OpenJDK ===

Java SDK: /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home
1.8.0_181
Android Designer EPL code available here:
https://github.com/xamarin/AndroidDesigner.EPL

=== Android SDK Manager ===

Version: 16.4.0.10
Hash: 2c49a7d
Branch: remotes/origin/d16-4
Build date: 2020-02-20 19:25:52 UTC

=== Android Device Manager ===

Version: 16.4.0.32
Hash: 7a5cb8b
Branch: remotes/origin/d16-4
Build date: 2020-02-20 19:26:14 UTC

=== Apple Developer Tools ===

Xcode 11.2.1 (15526.1)
Build 11B500

=== Xamarin.Mac ===

Version: 6.10.0.21 (Visual Studio Community)
Hash: 02c4b3bdc
Branch: xcode11.3
Build date: 2020-02-18 14:13:31-0500

=== Xamarin.iOS ===

Version: 13.10.0.21 (Visual Studio Community)
Hash: 02c4b3bdc
Branch: xcode11.3
Build date: 2020-02-18 14:13:32-0500

=== Xamarin Inspector ===

Version: 1.4.3
Hash: db27525
Branch: 1.4-release
Build date: Mon, 09 Jul 2018 21:20:18 GMT
Client compatibility: 1

=== Build Information ===

Release ID: 804070017
Git revision: 35c9b9b9315ec81feec25ebabe131761b304257d
Build date: 2020-02-21 16:06:09+00
Build branch: release-8.4
Xamarin extensions: 35c9b9b9315ec81feec25ebabe131761b304257d

=== Operating System ===

Mac OS X 10.14.6
Darwin 18.7.0 Darwin Kernel Version 18.7.0
    Sun Dec  1 18:59:03 PST 2019
    root:xnu-4903.278.19~1/RELEASE_X86_64 x86_64

Build Logs

https://gist.github.com/MKuckert/5f09017d4d8a6fc20501e0cabe6ddaab

Example Project

Solution.zip

bug external-xsdk iOS

All 14 comments

Hi,

Does anyone have a fix or workaround for this issue? I'm having the same issue with a nuget referencing System.IO.Abstractions. I'm getting the same error where the following method is missing : FileSystemAclExtensions::Create(DirectoryInfo,DirectorySecurity)

Thank you

I'm able to workaround this issue by using the old packages.config file instead of the PackageReference in csproj to reference my nuget packages from the iOS project.

Thanks for the workaround, but in my case I seem to have way more trouble using packages.config instead of PackageReference... but it's not related to this issue.

To add more information to this issue:
While this issue mention netstandard2.0, my library is on netstandard2.1 and I'm experiencing the same error.
I've tried using "--linkskip=System.IO.FileSystem.AccessControl", but same result.

I am having the exact same problem and I could solve it by downgrading the package that was using it to the version that was using System.IO.FileSystem.AccessControl to version 4.6.0 instead of 4.7.0

I was using System.IO.Abstractions v12.0.5 which had an implicit dependency on System.IO.FileSystem.AccessControl v4.70.

I had to drop System.IO.Abstractions all the way back to v7.0.7 before it would build on iOS, but then my unit tests which were using that version started failing with

System.TypeLoadException : Method 'Decrypt' in type 'System.IO.Abstractions.TestingHelpers.MockFile' from assembly 'System.IO.Abstractions.TestingHelpers, Version=7.0.0.0, Culture=neutral, PublicKeyToken=96bf224d23c43e59' does not have an implementation.

I had to fiddle with it, but System.IO.Abstractions and System.IO.Abstractions.TestingHelpers to 7.0.15 before everything built AND tests passed again.

Hey @rolfbjarne @spouliot. I am the maintainer of the mentioned package Systems.IO.Abstractions. Unfortunately I don't know much about how Xamarin works :/ Could you provide some guidance on how to fix this?

The problem seems to be that the library project's restore style is package reference, while the main project's restore style is not set, and there are no actual package references in the main project, only a project reference to the library project. Package references don't flow through project references, which means the main project's restore style is the old-style packages.config, and things end up confused.

I found two workarounds in the example project in the original description:

  • Explicitly add <RestoreProjectStyle>PackageReference</RestoreProjectStyle> to the main csproj.
  • Add any package reference to the main project (using <PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.7.0" /> works fine, but it seems any package reference works).

I'm closing this since it seems this is not a bug in Xamarin.iOS, just a side effect of unintentionally using two different restore styles.

Feel free to reopen if it's still possible to reproduce this with any of those workarounds (and please attach a test project as well).

@rolfbjarne I can still reproduce this here: https://github.com/Cheesebaron/sys-io-abstraction-build-fail

@Cheesebaron

This was fixed in https://github.com/xamarin/xamarin-macios/commit/8ecc47d08884c879bf8754ce46a8583156bfc4c7.

The fix wasn't intentional, but here's what happened:

  • A long time ago we copied the ImplicitlyExpandDesignTimeFacades target from Microsoft.NETFramework.CurrentVersion.targets. Xamarin.iOS and Xamarin.Mac each got their own copy, at different times (and thus got different versions of the ImplicitlyExpandDesignTimeFacades target).
  • Each copy of the ImplicitlyExpandDesignTimeFacades target evolved in our repo, in their own separate way.
  • I decided to merge these (and found all the differences), and in merging them I also looked at the latest version of the ImplicitlyExpandDesignTimeFacades target in Microsoft.NETFramework.CurrentVersion.targets to figure out how the final code should look like.
  • The end result is that we picked up https://github.com/dotnet/msbuild/pull/1520, which fixes https://github.com/dotnet/msbuild/issues/1345, which looks like exactly this issue (preferring a system facade instead of a facade from a NuGet).

Unfortunately this is a very recent fix, which means it's not in the current stable, nor in the preview. We're also fairly late in the release schedule for the upcoming release, and the fix has already proven to contain surprises, so I'm not comfortable with backporting the fix to the current preview. This means this will be fixed in the next main release (d16-9).

If anybody wants to try the fix, they can grab a package from our main branch (https://github.com/xamarin/xamarin-macios/wiki#downloading-a-build)

Whilst it does not adversely effect my application, it produces a warning once the app has been built.

/.../MTOUCH: Warning MT0109: The assembly 'System.IO.FileSystem.AccessControl.dll' was loaded from a different path than the provided path (provided path:
/Users/.../.nuget/packages/system.io.filesystem.accesscontrol/4.7.0/runtimes/win/lib/netstandard2.0/System.IO.FileSystem.AccessControl.dll, actual path:
/Library/Frameworks/Xamarin.iOS.framework/Versions/14.0.0.0/lib/mono/Xamarin.iOS/Facades/System.IO.FileSystem.AccessControl.dll). (MT0109) (...)

I tried both suggestions that you recommended @rolfbjarne :

  • Adding <PropertyGroup><RestoreProjectStyle>PackageReference</RestoreProjectStyle></PropertyGroup> to my shared projects csproj
  • Adding a direct package reference to the dll version I want: <PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.7.0" /> in my shared project csproj

I also played about adding these references to the iOS project to see if the error went away and no success. I would really like to get rid of this warning, and I don't particularly want to revert the implementation of my File Access class, which was the reason why I installed System.IO.Abstractions so I could easily test it 馃様

I'm fully up to date with XCode, Xamarin.iOS, Xamarin.Mac & Visual Studio for Mac:

Xamarin.Mac
Version: 6.20.2.2 (Visual Studio Professional)
Hash: 817b6f72a
Branch: d16-7
Build date: 2020-07-18 18:44:59-0400

Xamarin.iOS
Version: 14.0.0.0 (Visual Studio Professional)
Hash: 7ec3751a1
Branch: xcode12
Build date: 2020-09-16 11:33:15-0400

Do you have any suggestions for resolving this issue?

Do you have any suggestions for resolving this issue?

If you just want to silence the warning, you can add --nowarn:109 to the additional mtouch arguments in the project's iOS Build options.

Looks like the issue is more serious as the app can't be built for release, won't be able to sweep the warning under the rug unfortunately 馃様

/.../MTOUCH: Error MT2101: Can't resolve the reference 'System.Void System.IO.FileSystemAclExtensions::Create(System.IO.DirectoryInfo,System.Security.AccessControl.DirectorySecurity)', 
referenced from the method 'System.Void System.IO.Abstractions.DirectoryInfoWrapper::Create(System.Security.AccessControl.DirectorySecurity)' 
in 'System.IO.FileSystem.AccessControl, Version=4.0.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. (MT2101) (...)

For now I can sidestep the issue by doing what is suggested in the System.IO.Abstractions issue by downgrading that specific dependency to 7.1.1 or 7.0.15. But as I say this is a workaround and not one I'm particularly comfortable doing, I don't particularly want to be downgrading dependencies to really outdated versions.

Do you know the eta for d16-9 so I can verify the fix? I could update my local copy of vsmac but my release is all done in azure pipelines and I need to make sure the pipelines will work also 馃槆

@Axemasta it will be a while until d16-9 is released, given that we haven't released d16-8 yet.

That being said, it would be nice if you could test a package locally, at least to make sure the fix works, because if it's a different issue and we only discover this when d16-9 comes out, it will be a long time until it's fixed.

Here is a recent package from our main branch: xamarin.ios-14.7.0.55.pkg, you can just download it, install it, restart Visual Studio for Mac and try. When you're done and want to return to the stable channel, just "upgrade" to it in Visual Studio for Mac.

@rolfbjarne I've installed the version of Xamarin.iOS that you linked, I can confirm there are no warnings or errors build associated with the loading of System.IO.FileSystem.AccessControl.dll.

Interestingly there are 2 new warnings, coming from the .netstandard2.0 package 馃槯

System.Buffers.dll

/Users/alex.duffell/Documents/AzDO/MyApp/src/MyApp/MyApp.iOS/MTOUCH: 
 Warning MT0109: The assembly 'System.Buffers.dll' was loaded from a different path than the provided path (provided path:
 /Users/alex.duffell/.nuget/packages/system.buffers/4.5.0/lib/netstandard2.0/System.Buffers.dll, actual path:
 /Library/Frameworks/Xamarin.iOS.framework/Versions/14.7.0.55/lib/mono/Xamarin.iOS/Facades/System.Buffers.dll). (MT0109) (MyApp.iOS)

System.Security.SecureString.dll

/Users/alex.duffell/Documents/AzDO/MyApp/src/MyApp/MyApp.iOS/MTOUCH: 
 Warning MT0109: The assembly 'System.Security.SecureString.dll' was loaded from a different path than the provided path (provided path:
 /Users/alex.duffell/.nuget/packages/system.security.securestring/4.3.0/runtimes/win/lib/netstandard1.3/System.Security.SecureString.dll, actual path:
 /Library/Frameworks/Xamarin.iOS.framework/Versions/14.7.0.55/lib/mono/Xamarin.iOS/Facades/System.Security.SecureString.dll). (MT0109) (MyApp.iOS)

Specifying the package restore in the csproj does not appear to make a difference:

 <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>
  </PropertyGroup>

Nor does adding an explicit package reference:

<ItemGroup>
    ...
    <PackageReference Include="System.Security.SecureString" Version="4.3.0" />
</ItemGroup>

The problem appears to be solved for the library I wanted to use System.IO.Abstractions but looks like there may be other still unresolved issues 馃槹


Side thank-you for explaining what I needed to do to update to the preview version, it always scares me going to previews but it was very easy! I'm now back in the safety of the stable channel 馃槑

Was this page helpful?
0 / 5 - 0 ratings