3

Having a bizarre issue with a Xamarin project I am working on and I'm stumped...

I use HTTPClient to make asynchronous requests. However, my app was rejected from the app store for failing to meet Apple's IPV6 requirements. That is, a request I make using HTTPClient fails when connected through IPV6. What's bizarre is that it only fails when the app is started on an IPV4 network then switched to an IPV6 network. If I restart the application while connected to the IPV6 network, it succeeds! Also, if I start the app connected to IPV6 then switch to an IPV4 network, it also succeeds. It only fails when started in IPV4 then switched to IPV6.

It's utterly bizarre - it's like the HttpClient is caching something, but we create a new client for every request. I'm not using an IP address - just an address, and, as I mentioned, it works when the app is started connected to an IPV6 only network. It's only the switch from IPV4 to IPV6 which seems to cause the issue.

The code which exists in PCL:

var client = new HttpClient();
var urlToCall = new Uri("https://www.something.com/someapi/v1");
// Add some headers
...
response = client.GetAsync(urlToCall);

And the stack trace:

Trace.Message": "Error: ConnectFailure (Network is unreachable)
at System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult) [0x00065] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/System/System.Net/HttpWebRequest.cs:946 
at System.Threading.Tasks.TaskFactory`1[TResult].FromAsyncCoreLogic (IAsyncResult iar, System.Func`2 endFunction, System.Action`1 endAction, System.Threading.Tasks.Task`1 promise, Boolean requiresSynchronization) <0x10019c730 + 0x0005b> in <filename unknown>:0 
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003b] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:199 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:170 
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:142 
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[TResult].GetResult () <0x10013ccc0 + 0x0001b> in <filename unknown>:0 
at System.Net.Http.HttpClientHandler+<SendAsync>c__async0.MoveNext () [0x003d6] in /Library/Frameworks/Xamarin.iOS.framework/Versions/9.6.1.9/src/mono/mcs/class/System.Net.Http/System.Net.Http/HttpClientHandler.cs:372 
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003b] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:199 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:170 
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:142 
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[TResult].GetResult () <0x10013ccc0 + 0x0001b> in <filename unknown>:0 
at System.Net.Http.HttpClient+<SendAsyncWorker>c__async0.MoveNext () [0x000a9] in /Library/Frameworks/Xamarin.iOS.framework/Versions/9.6.1.9/src/mono/mcs/class/System.Net.Http/System.Net.Http/HttpClient.cs:274 
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003b] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:199 
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:170 
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:142 
at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () <0x10013c8c0 + 0x0001b> in <filename unknown>:0 
at MyApp.RestClient.RestService`2+<SendHttpRequest>d__10[TInput,TOutput].MoveNext () [0x00259] in <filename unknown>:0 
Network is unreachable
at System.Net.Sockets.Socket.Connect (System.Net.EndPoint remoteEP) [0x000bc] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/System/System.Net.Sockets/Socket.cs:1235 
at System.Net.WebConnection.Connect (System.Net.HttpWebRequest request) [0x001c2] in /Users/builder/data/lanes/3051/5f11db87/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/System/System.Net/WebConnection.cs:213 

Has anyone seen anything like this before? Does anyone have any idea of how to fix or even debug this?

Brandon Minnick
  • 13,342
  • 15
  • 65
  • 123
Cicada
  • 310
  • 3
  • 15
  • if you can create a reproducible test case, submit a bug to Xamarin: bugzilla.xamarin.com – Jason Sep 01 '16 at 21:48
  • Which implementation provider: Managed, NSUrlSession or CFNetwork? I'm assuming Managed, you might what to try NSUrlSession but beware of the SNI bug in the Apple TLS provider : https://bugzilla.xamarin.com/show_bug.cgi?id=43794 – SushiHangover Sep 01 '16 at 22:27
  • After some testing, some other Xamarin apps exhibit the same behavior so I do believe this is a real bug with Xamarin. – Cicada Sep 01 '16 at 23:00
  • @SushiHangover , thanks so much for your suggestion. Switching to NSUrlSession fixed the issue! – Cicada Sep 01 '16 at 23:53
  • 1
    You can try ModenHttpClient as an option. – Rohit Vipin Mathews Sep 02 '16 at 06:54
  • Has a bug been filed for this yet? Or is there any more information available? – tomandro Oct 03 '16 at 08:40
  • Hi Cicada! Please let me know if we've solved your question, below! If you don't have any follow up questions, let's mark this question as Answered to help fellow developers in the future when they have a similar question! – Brandon Minnick Dec 01 '16 at 06:36

2 Answers2

6

In the iOS Build settings, set HttpClient Implementation to use NSURLSession.

Link to Xamarin Documentation

The default continues to be an HttpClient that is powered by HttpWebRequest, while you can now optionally switch to an implementation that uses iOS’s, tvOS's or OS X's native transports (NSUrlSession or CFNetwork depending on the OS). The upside is smaller binaries, and faster downloads, the downside is that it requires the event loop to be running for async operations to be executed.

iOS Build Settings

You're using a hostname, not a hard-coded IPv4 IP Address, which is good news! Apple will reject your app if you're using a hard-coded IPv4 IP Address.

Make sure to check that your hostname can resolve an IPv6 IP Address. There are also some helpful methods in System.Net.Dns that can help resolve the IP Address for you to see if IPv6 is available or not.

You can also try using the .MapToIPv6() extension method: Link to MSDN documentation.

Brandon Minnick
  • 13,342
  • 15
  • 65
  • 123
  • IPV4 addresses should also work right? As long as you use high level frameworks like NSURLSession etc. – shorty Nov 09 '16 at 08:54
1

Have a look at ModernHttpClient

Awesome explanation from the ModernHttpClient author.

It's great and we using it with all our Xamarin.Forms projects.

P.S.

One of our latest iOS apps was also initially rejected.

Here is how we solved IPV6 issue.

Community
  • 1
  • 1
Mr. L
  • 3,098
  • 4
  • 26
  • 26
  • ModernHttpClient is a great tool, and I've used it for many apps! In the Cycle 8 update, Xamarin provides the same ModernHttpClient functionality in the Build Settings for iOS & Android. By using the baked-in functionality, you can ship your app without ModernHttpClient, decreasing app size and complexity. That being said, I still use ModernHttpClient in my legacy apps, because it still works great! https://developer.xamarin.com/guides/cross-platform/macios/http-stack/ – Brandon Minnick Oct 28 '16 at 16:00
  • @BrandonMinnick Ah, that's great. Wasn't aware about Cycle 8 Update changes. Thanks! – Mr. L Oct 28 '16 at 20:23