Bug 23806 - HttpWebRequest fails after wifi change
Summary: HttpWebRequest fails after wifi change
Status: RESOLVED DUPLICATE of bug 45761
Alias: None
Product: iOS
Classification: Xamarin
Component: General (show other bugs)
Version: XI 8.2.0
Hardware: PC Mac OS
: Normal major
Target Milestone: Untriaged
Assignee: Miguel de Icaza [MSFT]
URL:
Depends on:
Blocks:
 
Reported: 2014-10-13 23:22 UTC by Cody Beyer (MSFT)
Modified: 2016-12-22 14:21 UTC (History)
13 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
TestCase (13.42 KB, application/zip)
2014-10-13 23:22 UTC, Cody Beyer (MSFT)
Details

Description Cody Beyer (MSFT) 2014-10-13 23:22:30 UTC
Created attachment 8408 [details]
TestCase

The attached app demonstrates the issue and I have reproduced it on an iPhone

Description of Issue:
* User is connected to WiFi access point called 'Network A' running our iPad app
* User successfully calls a web service and gets data back
* User moves locations and connects to WiFi access point called 'Network B' without re-starting the application
* User attempts to call the same web service. The Request times out.
* If the user terminates the application and restarts it while still on 'Network B' the service call will work. If the user re-joins 'Network A' the request works again

To reproduce using the attached project:

1. Make sure the iPad is connected to a wireless network
2. Launch the "NoWorkAfterNetworkChange" app to a physical iPad device.
3. Tap the "Use HttpWebRequest" button -> after a brief delay you should see a message that says "Success: true" which means the service call was successful
4. Tap the "Use NSUrlRequest" button-> after a brief delay you should see a message that says "true" which means the service call was successful
5. Without killing the app, go to device settings and switch the wireless networks. After you have joined a different network return to the app.
6. Tap "Use HttpWebRequest" -> after waiting for 7 seconds, the service call will timeout. This will eventually happen regardless of what the timeout is set to.
7. Tap "Use NSURLRequest" -> you should see "true" which means this was still successful
Comment 1 Arpit Jha 2014-10-14 06:46:17 UTC
I have checked this and unable to reproduce it

I tried to reproduce with the help of bug description and observed that getting success message on Httpwebrequest and NSURLRequest button click after changing Network LAN to wifi  we clicked on Httpwebrequest getting a popup of "Failure:Timeout" and when clicked on NSURLRequest getting  an exception of 
"System.ArgumentNullException"

Screencast regarding same:
http://www.screencast.com/t/k2nU6oAA

Let me know if I missed anything to reproduce it.

Environment Info:
=== Xamarin Studio ===

Version 5.6.1 (build 5)
Installation UUID: 6ea47b0d-1852-4aaf-808d-373ff0a5002b
Runtime:
 Mono 3.10.0 ((detached/633e444)
 GTK+ 2.24.23 (Raleigh theme)

 Package version: 310000020

=== Apple Developer Tools ===

Xcode 6.0.1 (6528)
Build 6A317

=== Xamarin.Mac ===

Version: 1.10.0.18 (Business Edition)

=== Xamarin.Android ===

Version: 4.18.0 (Business Edition)
Android SDK: /Users/jatin66/Desktop/Backup/android-sdk-macosx
 Supported Android versions:
  1.6   (API level 4)
  2.1   (API level 7)
  2.2   (API level 8)
  2.3   (API level 10)
  3.0   (API level 11)
  3.1   (API level 12)
  3.2   (API level 13)
  4.0   (API level 14)
  4.0.3 (API level 15)
  4.1   (API level 16)
  4.2   (API level 17)
  4.3   (API level 18)
  4.4   (API level 19)
Java SDK: /usr
java version "1.7.0_65"
Java(TM) SE Runtime Environment (build 1.7.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)

=== Xamarin.iOS ===

Version: 8.2.0.203 (Business Edition)
Hash: 6049af6
Branch: 
Build date: 2014-10-12 21:49:14-0400

=== Build Information ===

Release ID: 506010005
Git revision: 4a603dc77610b9eff2a41582146c56b69a81ceba
Build date: 2014-10-09 11:07:06-04

=== Operating System ===

Mac OS X 10.9.5
Darwin Jatin66s-iMac.local 13.4.0 Darwin Kernel Version 13.4.0
    Sun Aug 17 19:50:11 PDT 2014
    root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64
Comment 2 kpickard@flightdocs.com 2014-10-14 09:16:34 UTC
I see that you marked the bug as unable to reproduce.  
In the problem description I had put the following: 

"Launch the "NoWorkAfterNetworkChange" app to a physical iPad device.”   

In other words I mean an actual iPad, not the iOS simulator.  Please re-test using a physical device.  if you follow the directions, I think its fairly easy to reproduce.

@Cody Beyer was also able to reproduce so perhaps check with him as well.  This issue is having a big affect on our production users.
Comment 3 Cody Beyer (MSFT) 2014-10-14 10:56:16 UTC
Two items of note

1) This only happens on a physical device

2) The recreation instructions request that this be tested with wifi only such as:

2a) turn off cellular radio
2b) connect to wifi
2c) test app
2d) background (not close) app
2e) switch to a /different/ wifi network
2f) test

It can be hard to switch networks, I had to connect to a public wifi for the 2nd attempt, but it is vital to the testing that this be done.

Thanks
Comment 6 Sebastien Pouliot 2014-11-03 14:12:00 UTC
Our HttpWebRequest comes directly from Mono -> Martin

Note: if anyone knows a version of XI that worked previously (if it's a regression) that could be helpful to poinpoint the change. Thanks!
Comment 10 Adrian Murphy 2014-11-17 18:16:58 UTC
Miguel - Assigning to you for your comments, as per our discussion.
Comment 11 Alain 2014-11-22 09:37:00 UTC
Hi, 

I have the same problem with my application. That's very important for us to resolve this problem faster.

Thank you

Alain
Comment 12 Miguel de Icaza [MSFT] 2014-11-22 09:58:57 UTC
Hey guys,

Let me share with you my debugging thoughts on the issue.

The issue is that the kernel is not shutting down sockets when the IP address on the host changes.   

What happens is that when you hop from one wifi network to another wifi network, the IP changes, but the connection is technically no longer usable.   But an application that keeps a socket open has no way of knowing this.

So what we need to do is hook up the Reachability stack, and when we detect a network change, invalidate the internal cached set of connections.

There are two options: 

* use the native NSUrlConnection/NSUrlSession or CFNetwork stack that does this already.

* Implement a reachability check, and when the network changes, use internal calls to clear the cached ServicePoint data structures.

I will try to get a prototype of the latter for you over the weekend.
Comment 13 Miguel de Icaza [MSFT] 2014-11-22 10:00:05 UTC
In case someone does not want to wait for my prototype, this is the source code for the ServicePointManager where we need to clear the connections on IP address change:

https://github.com/mono/mono/blob/master/mcs/class/System/System.Net/ServicePointManager.cs
Comment 14 Alain 2014-11-22 10:39:15 UTC
OK, thank you !

 I'll wait for your prototype for it.

I saw this problem by changing the 4G to WIFI and it is the same problem that a change in WIFI wireless network to another.

Let me know when you have a solution.

Thank you for your quick response.

Alain
Comment 15 Alain 2014-11-24 09:08:40 UTC
Hi,

are you found a solution for us ?

Thanks

Alain
Comment 16 Miguel de Icaza [MSFT] 2014-11-24 22:07:22 UTC
Two problems:

(a) I am unable to reproduce this problem with my test networks, so there might be something else going on that I do not understand.  Perhaps a keep-alive on the HTTP client?   And perhaps the solution is to disable keep-alive?

(b) The reachability class is not as useful as I thought it was, it merely lets you know when access to a particualr host/endpoint changes, but not necessarily that a network configuration changes.   So changes from one wifi-network to another would not be detected.

Sample code below to detect this


			try {
				reachability = new NetworkReachability ("www.google.com");

			} catch {
			}
			if (reachability != null) {
				reachability.SetCallback ((flags) => {
					l.Text = String.Format ("Rechability: {0}", flags);
                                });
				reachability.SetDispatchQueue (MonoTouch.CoreFoundation.DispatchQueue.MainQueue);
				reachability.Schedule ();
Comment 18 T.J. Purtell 2014-11-25 02:26:42 UTC
Does WebConnectionStream have a SendTimeout/WriteTimeout on the socket it is using?  Default per POSIX is infinite, so it will never detect the connection is "dead" if the router just DROPs vs REJECTs the packets.  I couldn't find a timeout and it looks like it is using blocking IO ops on a thread pool, so the SO_SNDTIMEO might apply.
Comment 19 kpickard@flightdocs.com 2014-11-25 10:11:46 UTC
Miguel - Here's the code I'm using in my test case.  I don't think the keep-alive is being set unless that's happening somewhere under the covers.  Have you tried the sample I uploaded?  Its very easily reproduced for me.  

This will timeout after a wifi network change:

var uri = new Uri("https://api-stg.flightdocs.com/apitest/get");
HttpWebRequest r = new HttpWebRequest(uri);
r.Timeout = 7000;
r.Method = "GET";
using(var response = r.GetResponse())
{
	var encoding = ASCIIEncoding.ASCII;
	string responseText;
	using (var reader = new System.IO.StreamReader(response.GetResponseStream(), encoding))
	{
		responseText = reader.ReadToEnd();
	}
	response.Close();
	return "Success: " + responseText;
}  


I have had partial success with using the following code after a network change, however I don't understand it so I'm hesitant to put it into production.  Also as you said, the reachability class won't notify of a simple switch in networks:

var uri = new Uri("https://api-stg.flightdocs.com/apitest/get");
var svcPoint = ServicePointManager.FindServicePoint(uri);
var closed = svcPoint.CloseConnectionGroup(null);

Brainstorming... Regarding the network switch, could we do something like this to check the SSID to detect a different network?  This could be run whenever the app comes to the foreground to detect a manual network change.  However, if the device went out of range of one network and then automatically joined a different one while the app is still in the foreground this wouldn't help.  In that scenario though, I'm hoping Reachability would notify us.  

static string GetSSID ()
{
    var dict = CaptiveNetwork.CopyCurrentNetworkInfo ("en0");
    return dict [CaptiveNetwork.NetworkInfoKeySSID].ToString ();
}
Comment 20 Miguel de Icaza [MSFT] 2014-11-26 12:43:02 UTC
My issue is just that I do not have a network configuration to reproduce this at this point.   At home, where I have two access points, they both route through the same router at the end, so I suspect that is why I am unable to repro.
Comment 22 Alain 2014-11-26 12:57:56 UTC
Miguel

To reproduce this bug, you put yourself on an iPad WIFI => it works.

You cut WIFI and you're on 3G-4G, you call your WebService and you have a direct connection TimeOut.

It's really urgent that you find a solution to this problem for many of our customers switch between WiFi and 4G, and they must each time attempting to restart the application.

thank you

Alain
Comment 23 kpickard@flightdocs.com 2014-11-26 14:14:21 UTC
Miguel - I've come up with a workaround until you can figure out a long-term solution.  Could you take a look and give me your opinion if you see any pitfalls with what I've come up with or, if there's a better way to implement this workaround?

Here's what I'm doing:

Once there are no pending calls, I manually call ServicePoint.CloseConnectionGroup(...) in order to force close the open connections.  When doing this, the connection will get re-opened with each new set of requests and therefore its unlikely that a user will encounter the problem when switching networks.  This is what closes the connection:

var sp = ServicePointManager.FindServicePoint(new Uri("https://api-test.Flightdocs.com/"));
sp.CloseConnectionGroup(null);

All my API calls have the same base address and therefore share the same ServicePoint instance which makes it easy for me to do this across the board.   The issue is that this can't always be done after every network call finishes since it could cause other requests that are being performed on other threads to fail.  So, I've come up with a way of tracking open network requests and then closing once there are no longer any pending ones.  

I've put together a Gist that shows the full approach.  I would very much appreciate if you could take a look and let me know what you think:  https://gist.github.com/kentpickard/ba94e62febd92a3d35bc  

I agree with Alain that the impact of this is very large.  Our application is used by pilots which are constantly on the move and switching between wireless networks as well as between WiFi and Cellular.  This is a big issue for them and I have been under pressure to provide a resolution since I originally opened this bug over a month ago.  

I'm very glad to see that one of the famous Mono pioneers, Miguel, is on the case.  It gives me confidence that it will get resolved soon :-)
Comment 24 Miguel de Icaza [MSFT] 2014-11-26 16:26:48 UTC
Ok, some comments:

(a) your approach is correct, this will shut down the cached values.  So the issue remains one of finding out when the IP address changes.

(b) The issue in *particular* with this web site is that it keeps the connection open, this is what causes the time out.   A simple fix to this problem is to add to your HttpWebRequest the following:

myWebrequest.KeepAlive = false

Which will shutdown the connection, and insure that the cached value is not used the next time.
Comment 25 T.J. Purtell 2014-11-26 19:37:57 UTC
1) -- Ideal working no network change --
Request A initiated by app
Connection opened
Request A sent
Response A received
Request B initiated by app
Request B sent
Response B received

2) -- Ideal working with network change -- 
Request A initiated by app
Connection opened
Request A sent
Response A received
Network change
Mono evicts Keep-Alive connections or kernel invalidates the connection
Request B initiated by app
Connection opened
Request B sent
Response B received

3) -- Should still work with retry ---
Request A initiated by app
Connection opened
Request A sent
Response A received
Network change
Request B initiated by app
Request B sent (on dead connection)
Request B fails with timeout etc, Connection marked dead by mono **??
Request B re-initiated by app
Connection opened
Request B sent
Response B received

4) -- Workaround KeepAlive = false, extra SSL connect per request required for normal use --
Request A initiated
Connection opened
Request A sent
Response A received
(Network change or not, no difference in behavior)
Request B initiated by app
Connection opened
Request B sent
Response B received

I think that in general an application wants keep alive for performance, and needs to support retry from its own application logic (automatic retry and/or user triggered retry), so at the app level things should be coded to support the style of (3), but ideally mono/kernel would help the situation a bit with detecting the change and usually the situation would be (2).

From the comments above (and my own experience with network changes on mobile mono from the last time we tried wide deployment of the mono http stack), it seems like situation 3, doesn't work right.  If killing the application is required to enable a request to eventually succeed, maybe it means that the "failed via timeout"  request (see **?? above) did not cause the KeepAlive connection to be evicted from the pool, even though that connection shouldn't be eligible for reuse because it has a pending operation which was aborted due to timeout.
Comment 26 Miguel de Icaza [MSFT] 2014-11-26 19:52:03 UTC
After a timeout, the connection gets evicted from the pool.  This is scenario (2), with the added caveat that it will happen after the timeout expires.   Apple's documentation states that you are supposed to retry these operations:

https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/WhyNetworkingIsHard/WhyNetworkingIsHard.html

Your scenario (3) works today.   It is obnoxious, because you have to wait for the timeout, but it works.

The issue with the KeepAlive is that the kernel will happily keep the connection *alive* and will queue any messages you send to it without returning any indication that the network interface has been shut down hoping that you might come back and flush the data out.

You can observe this behavior by switching from one network to another network (the socket continues to be kept alive) and then switching back, and the data will be flushed once the original interface with the original IP address go back.

The timeout message is not raised by the kernel, instead it is raised by the .NET runtime when it determines that the timeout for the connection has expired.

So in short, 3 and 4 is what you can do today.   

To achieve (2) we need to find a reliable way of detecting a network change (which does not seem simple to do, as the Reachability API does not tell you if a network configuration changed, merely whether you can reach a certain host if you initiate a new connection).

Another area of investigation is to use the local IP address as a key for reusing connection groups.   So if the local address is different than the local address of the interface that was used on first connection, we could invalidate this.

It seems flaky, and  might also slow down every HTTP request by forcing us to scan all network interfaces on each new connection.   Perhaps not a big deal.
Comment 27 T.J. Purtell 2014-11-26 23:17:12 UTC
Great :) 

If (3) is working, then we can soon start detailed testing to switch back to the mono http stack from the NativeHttpHandler.  I think we have to wait for https://bugzilla.xamarin.com/show_bug.cgi?id=22724 to be released though.  Will report back more when this happens.
Comment 28 Alain 2014-11-29 07:32:36 UTC
Sorry but I don't understand what I do.

In my application ,I test if I have a network connection before calling my webservice via the class: Reachability

I have a WebService that I call like this:

DLLMedinect.EHealthConnectionWebService.Service EHealth DLLMedinect.EHealthConnectionWebService.Service = new ();


if (EHealth.CreateFallbackSession (strNumeroINAMI, strMotDePasse, Alangue, ref stcErreur) == true)
return true;
else
return false;

If I change my network, I have a connection timeout, what should I do practically?

Thank you

Alain
Comment 29 Miguel de Icaza [MSFT] 2014-11-29 10:50:04 UTC
On your web request, set "KeepAlive" to false.
Comment 30 Alain 2014-11-29 11:31:40 UTC
Miguel,

I use a WebReference and I don't have a WebRequest.

What do I do exactly with a WebReference ?

I don't see where I must to use KeepAlive

In my code, I have a WebReference : EHealthConnectionWebService

and I call the the function simply :

DLLMedinect.EHealthConnectionWebService.Service EHealth = new
DLLMedinect.EHealthConnectionWebService.Service();


if (EHealth.CreateFallbackSession (strNumeroINAMI, strMotDePasse, Alangue, ref
stcErreur) == true)
return true;
else
return false;
Comment 31 Miguel de Icaza [MSFT] 2014-11-29 12:11:04 UTC
Alain,

I have no way of knowing what your EHEalthConnectionWebService is.

You are going to need to find in that class the property or setting that gets you access to the HttpWebRequest.

Perhaps you need to override the GetWebREquest method and customize there.
Comment 32 kpickard@flightdocs.com 2014-12-01 10:32:33 UTC
Miguel - Setting HttpWebRequest.KeepAlive=false is much simpler than what I'm doing.  However, I've discovered another (possibly related) bug that prevented me from discovering this when I tried doing that early on in my testing:

In addition to not detecting when the client IP address changes (which this bug entry addresses), the mono networking stack also does not detect when the host IP address is different after a network change.  Setting KeepAlive=False does not fix this issue.  

For example:  In our office we have 2 wireless networks:  Developers and Employees.  When on the Developers network, https://API-STG.flightdocs.com resolves to a different IP then when on the Employees network.  In this case, one is a public facing IP and the other is a local IP.  When switching from the Developer network to the Employees network it tries to re-use the cached IP address.  

This will be a problem for our production users in the future when we move to having multiple data centers in the cloud which we're currently working on putting in place.  If a pilot takes off on the east coast and then touches down on the west coast, the IP address of the host could change.  If the app is still running (it could be since the pilot could be using it in offline mode during the flight) then I think they'll have the same issue.  The only work-around I can think of for this is manually removing the ServicePoint entry via reflection but that could likely have a lot of unintended consequences.  NSUrlRequest somehow handles this gracefully. 

Should I open a new bug for this?
Comment 33 Miguel de Icaza [MSFT] 2014-12-01 15:14:37 UTC
Hello,

Provided that your pilot does not fly from one point to another in less that 100 seconds (the time that an entry can stay in the ServicePointManager before it gets evicted), that should not be a problem.

That said, you can use the ServicePointManager.MaxServicePointIdleTime to change this from the default of 100 seconds to any other values that are more suitable.   

Come to think of it, setting this to a low value is probably a better idea than setting the KeepAlive to false.

Here is a good explanation:

http://blogs.msdn.com/b/jpsanders/archive/2009/05/20/understanding-maxservicepointidletime-and-defaultconnectionlimit.aspx
Comment 34 kpickard@flightdocs.com 2014-12-01 16:05:37 UTC
Miguel - From what I'm seeing, setting the ServicePointManager.MaxServicePointIdleTime to something low (like 500 milliseconds) did not help with the problem of the Host IP address changing.  (It is indeed another way to address the problem of the client IP address changing)

With this code the network calls still fails after switching from Developer to Employee networks and waiting more than 100 seconds between calls (I should only have to wait a half second).  I think that open connections are shut down by setting max idle time however, the ServicePoint entry still keeps the old host IP address with that was previously resolved.  Here's the example:

ServicePointManager.MaxServicePointIdleTime = 500;

var uri = new Uri("https://api-stg.flightdocs.com/apitest/get");
HttpWebRequest r = new HttpWebRequest(uri);
r.Timeout = 7000;
r.Method = "GET";
r.KeepAlive = false;
string responseText;
using(var response = r.GetResponse())
{
	var encoding = ASCIIEncoding.ASCII;

	using (var reader = new System.IO.StreamReader(response.GetResponseStream(), encoding))
	{
		responseText = reader.ReadToEnd();
	}
	response.Close();
}


I can see that the resolved IP address of the ServicePoint.HostEntry proeprty isn't changing.  I have to use reflection to get the value of the internal ServicePoint.HostEntry property:

// r is the same instance of HttpWebRequest as above
var sp = r.ServicePoint;
var pi = r.ServicePoint.GetType().GetProperty("HostEntry", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance);
var ipHostEntry = pi.GetValue(r.ServicePoint) as IPHostEntry;
var IPs = string.Join("; ", ipHostEntry.AddressList.Select(s => s.ToString()));  
Debug.WriteLine("Host IPs: " + IPs);  // Always outputs the IP address that was resolved during the first call

If I inject this with the reflection code before making the call, I can manually update the HostEntry which will allow the call to succeed:

var actualIPs = Dns.GetHostAddresses("api-stg.flightdocs.com");
ipHostEntry.AddressList = new IPAddress[]{ actualIPs[0] };

I still think this is a bug.  Am I missing something?
Comment 35 Miguel de Icaza [MSFT] 2014-12-01 16:33:30 UTC
If you keep "r" alive, that will keep the ServicePoint alive, so it is normal for it to not be discarded.

What you need is to create a new HttpWebRequest, which will at this point, not use the same ServicePoint.

See:

http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.maxservicepointidletime%28v=vs.110%29.aspx
Comment 36 kpickard@flightdocs.com 2014-12-01 16:45:59 UTC
I'm doing this before any call:

ServicePointManager.MaxServicePointIdleTime = 500; 

And I'm creating a new instance of HttpWebRequest for every call:

HttpWebRequest r = new HttpWebRequest(uri);

In addition to always setting r.KeepAlive = false;

Somehow every new instance of HttpWebRequest ends up with the same service point instance that was previously used.  I'm guessing that internally HttpWebRequest calls ServicePointManager.FindServicePoint(hostName) which always returns the same ServicePoint instance.
Comment 37 Miguel de Icaza [MSFT] 2014-12-03 15:33:57 UTC
What you are doing looks right.

Martin says that it is ok to reuse the same ServicePoint, and even the WebConnectionGroup, what will not be the same is the WebConnection (which is the underlying transport).
Comment 38 Alain 2015-01-05 10:01:05 UTC
Miguel,

Hello,

I added webRequest.KeepAlive = false;

and I still have the same problem. When I switche from one network to another (WIFI => 4G or 4G to Wi-Fi). I have a TimeOut connection.

Here's what I do:

[System.Web.Services.WebServiceBinding(Name="ServiceSoap", Namespace="http://tempuri.org/")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
public class MedinectWebServiceExt : DLLMedinect.MedinectWebService.Service
{

    protected override System.Net.WebRequest GetWebRequest(Uri uri)
    {
		ServicePointManager.MaxServicePointIdleTime = 500;

        System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)base.GetWebRequest(uri);

        webRequest.KeepAlive = false; 
       
        return webRequest;
    }
}


and I call my webservice like this:

MedinectWebServiceExt  medinectWBS = new MedinectWebServiceExt();

lstEmail = medinectWBS.GetListMails(strNumeroINAMI.Substring(0,8),true,ref strErreur);


You have to find a solution because our customers do not understand why they have to close the application and restart it for it to work.

thank you

Alain
Comment 39 Simon Andersen 2015-03-05 09:52:18 UTC
This is truly a serious problem.

It basically eliminates the possibility to use a lot of frameworks that relies on HttpClient. Especially using SignalR is not possible, if you have an environment that switches between wireless and 3g/4g

We just had a serious problem with a customer using SignalR (it is already in use on other devices (non-iOS, such as JavaScript/web and .NET applications)) - we are having to rewrite the iOS-application completely
Comment 40 Miguel de Icaza [MSFT] 2015-03-05 09:56:39 UTC
Simon,

Did you read comment #12?

Because if your application uses HttpClient, you *can* use the native CFNetwork handler:

http://tirania.org/monomac//archive/2013/Jun.html

or the NSURLSession-based handler that plug right into HttpClient with support for OkHttp on Android as well:

https://github.com/paulcbetts/ModernHttpClient
Comment 41 Simon Andersen 2015-03-05 11:05:55 UTC
Miguel,

Yes - CFNetworkHandler and ModernHttpClient does not support NTLM (to my knowledge), and this is a requirement in most enterprise environments.
Comment 42 Simon Andersen 2015-03-05 13:48:38 UTC
Miguel,

We made it work!

Thanks alot for pointing me in the correct way.

To all others who might be interested:

We ended up using ModernHttpClient and implemented NTLM-authentication on didReceiveChallenge

We changed SignalR's DefaultHttpClient to a custom HttpClient using NativeMessageHandler (ModernHttpClient)

Connections between Wifi / 3G and even between different IP's to same DNS (please see kpickard@flightdocs.com comments) works perfectly with ModernHttpClient.
Comment 43 Adam 2016-10-06 02:28:51 UTC
Hi, has this issue recently re-appeared?
I have just updated my Xamari iOS, and this issue has appeared - but I have never experienced this before.

We are noticing, if the user makes a network request on WIFI, then the network drops back to Cellular before the request has completed, the request times out.
If, Wifi is reinstated before the timeout, then the socket is re-established and the request completes successfully (albeit, after a very long delay).

This appears to have shown up only in the latest Xamarin, as we have been holding off releasing due to another bug, but now cannot release because of this.

Thanks,
Comment 44 Sebastien Pouliot 2016-12-22 14:21:08 UTC
@Adam, I suspect this is a dupe #45761 but that did not affect the native handlers [1](which is what was discussed in earlier comments). 

A mono BCL bug affected the managed stack (e.g. WebClient and the default handler for HttpClient) and has been fixed. The next alpha (C9) release will have this fix.

[1] https://bugzilla.xamarin.com/show_bug.cgi?id=46792#c3

*** This bug has been marked as a duplicate of bug 45761 ***

Note You need to log in before you can comment on or make changes to this bug.