Bug 20589

Summary: "Microsoft HTTP Client Libraries" NuGet causes "System.InvalidOperationException" from System.Lightup.Call()
Product: Visual Studio Extensions Reporter: Brendan Zagaeski (Xamarin Team, assistant) <brendan.zagaeski>
Component: iOSAssignee: mag <mag>
Severity: critical CC: alexey, alo, anuj.bhatia, chrisntr, josemiguel, jpmock, m.bolsun, mbradea, pedro.lamas, ramc, saurabhd
Priority: High    
Version: 3.1   
Target Milestone: 3.8   
Hardware: PC   
OS: Mac OS   
Tags: Is this bug a regression?: ---
Last known good build:
Attachments: Test case
App.config for workaround

Description Brendan Zagaeski (Xamarin Team, assistant) 2014-06-13 17:35:22 UTC
Created attachment 7070 [details]
Test case

This is a new report for the old bug 17936 to provide an up-to-date starting point, a test case, and information about workarounds.

## Steps to reproduce

1. Build the attached test case in Visual Studio, and run it on an iOS device.

2. Tap the "Click me" button.

## Result

> Unhandled managed exception: Operation is not valid due to the current state of the object (System.InvalidOperationException)
>   at System.Lightup.Call[HttpWebRequest,Int64] (System.Delegate& storage, System.Net.HttpWebRequest instance, System.String methodName, Int64 parameter) [0x00000] in <filename unknown>:0 
>   at System.Lightup.Set[HttpWebRequest,Int64] (System.Delegate& storage, System.Net.HttpWebRequest instance, System.String propertyName, Int64 value) [0x00000] in <filename unknown>:0 
>   at System.Net.HttpWebRequestLightup.SetContentLength (System.Net.HttpWebRequest instance, Int64 value) [0x00000] in <filename unknown>:0 
>   at System.Net.Http.HttpWebRequest.set_ContentLength (Int64 value) [0x00000] in <filename unknown>:0 
>   at System.Net.Http.HttpClientHandler.StartRequest (System.Object obj) [0x00000] in <filename unknown>:0 
> --- End of stack trace from previous location where exception was thrown ---
>   at System.Runtime.ExceptionServices.ExceptionDis
> patchInfo.Throw () [0x0000b] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:62 
>   at System.Runtime.CompilerServices.TaskAwaiter`1[System.String].GetResult () [0x00000] in <filename unknown>:0 
>   at HttpAsyncTest.MyViewController+<<ViewDidLoad>b__0>d__2.MoveNext () [0x0001b] in c:\Users\%USERNAME%\Desktop\HttpNugetTest\HttpAsyncTest\MyViewController.cs:39 

## Expected result

No exception, and the HTML content from www.example.com gets printed via `Console.WriteLine()`.

## Workaround

Follow the steps under "Close to the finish line" on [1]. Optionally, change the "newVersion" to "". Or simply add the attached `app.config` to the HttpAsyncTest project. This `app.config` redirects all versions of `System.Net.Http` so that the final app will contain the Xamarin.iOS assembly rather than the NuGet version. 

> [1] http://motzcod.es/post/78863496592/portable-class-libraries-httpclient-so-happy

If you set "newVersion" to "", the exception will return.

## Alternative workaround

In the "HttpAsyncLibrary" project, set the "CopyLocal" property for the "System.Net.Http" assembly to "False".

## Additional information

The assembly version number of System.Net.Http was recently changed to

> https://github.com/mono/mono/commit/4c45fe93a1d288dc66df3d26059a167f6ae82785

Unfortunately, at least for this particular test case, it appears that the NuGet package causes the app project to request the "" NuGet version of the assembly. As a result, the final app bundle still contains the NuGet version instead of the Xamarin.iOS version:

> monodis --assembly ~/Library/Caches/Xamarin/mtbs/builds/HttpAsyncTest/2e353ad7-5ee3-4944-89f6-e5ba1c15178f/output/Debug/iPhone/HttpAsyncTest.app/System.Net.Http.dll | grep version
> Version:

## Version information

Note 1: the app runs without error when built and launched from Xamarin Studio on Mac.

Note 2: to workaround the XamarinVS 3.1 SDK sync bug #20588, I manually copied the assemblies from Xamarin.iOS to the Windows side.

### Mac
OS X 10.9.3

### Windows
Microsoft Visual Studio Professional 2013
Version 12.0.30501.00 Update 2
Microsoft .NET Framework
Version 4.5.51641

Xamarin (fb9b274179eab7ecc4c6ff10f9f7b789efe5b7f6)

Windows 8.1 64-bit (in VMWare)
Comment 1 Brendan Zagaeski (Xamarin Team, assistant) 2014-06-13 17:36:13 UTC
Created attachment 7071 [details]
App.config for workaround
Comment 3 Brendan Zagaeski (Xamarin Team, assistant) 2014-06-13 17:43:23 UTC
*** Bug 17936 has been marked as a duplicate of this bug. ***
Comment 4 Ram Chandra 2014-06-16 06:45:43 UTC
I tried this issue and with the help of bug description I am able to reproduce this issue.

Steps to reproduce:

1. Open the attached project in VS 2013
2. Build and deploy the project on device.
3. Click on  "Click Me" button.
4. An "Unhandled managed exception" will be thrown.

When I press "Click Me" button on device I observed that I am also getting an "Unhandled managed exception".

I have also tried the workaround as mentioned on bug description. I have added the attached app.config file on "HttpAsyncTest" project. Which contains the new version "". I am not getting any exception and on the debug window it show "HTML" content, but when I changed the new version to "" I am getting the same exception.

Debug logs:  https://gist.github.com/anonymous/8bb172e96449c3397080

Environment Info:

Windows 7

Microsoft Visual Studio Professional 2013
Version 12.0.21005.1 REL
Microsoft .NET Framework
Version 4.5.50938

Xamarin (d3cf238e3845e930e312b6ec9b4c6c5437c33067)
Visual Studio extension to enable development for Xamarin.iOS and Xamarin.Android

Xamarin.iOS (d3cf238e3845e930e312b6ec9b4c6c5437c33067)
Visual Studio extension to enable development for Xamarin.iOS

Xamarin.iOS Build Host:
Comment 5 Brendan Zagaeski (Xamarin Team, assistant) 2014-08-26 14:59:37 UTC
This problem can also appear as the following exception:

> System.NotSupportedException: HttpClientHandler.PreAuthenticate is not supported on this platform.  Please check HttpClientHandler.SupportsPreAuthenticate() before using HttpClientHandler.PreAuthenticate.
>   at System.Net.Http.HttpWebRequest.set_PreAuthenticate (Boolean value) [0x00000] in <filename unknown>:0 
>   at System.Net.Http.HttpClientHandler.SetDefaultOptions (System.Net.Http.HttpWebRequest webRequest) [0x00000] in <filename unknown>:0 
>   at System.Net.Http.HttpClientHandler.CreateAndPrepareWebRequest (System.Net.Http.HttpRequestMessage request) [0x00000] in <filename unknown>:0 
>   at System.Net.Http.HttpClientHandler.SendAsync (System.Net.Http.HttpRequestMessage request, CancellationToken cancellationToken) [0x00000] in <filename unknown>:0

The same `app.config` workaround solves that exception too.
Comment 7 mag@xamarin.com 2014-11-06 10:25:26 UTC
Closing this bug as By-Design.

The way that PCL's currently work in the presence of platform specific implementations, requires that the native app also installs the NuGet package.

Here's a good explanation of how PCL's should work in different scenarios, including this particular one: http://blogs.msdn.com/b/dsplaisted/archive/2012/08/27/how-to-make-portable-class-libraries-work-for-you.aspx

The RX assemblies uses the same approach. See the RX team blog post in turn for another case that's very well documented: http://blogs.msdn.com/b/rxteam/archive/2012/08/15/reactive-extensions-v2-0-has-arrived.aspx

Microsoft is aware of this issue, and the plan is to solve this for good in the next version of the platform.
Comment 8 Saurabh 2015-02-09 07:38:15 UTC
As per Comment#7 changing the status to Verified.
Comment 9 Jesse Mock 2015-06-18 19:04:45 UTC
I am having this exact issue with the simplest app ever.  I am simply performing a single POST with httpclient.  I don't see a good descriptive fix here.
Comment 10 Jesse Mock 2015-06-18 19:05:23 UTC
by the way, everything is updated...Xamarin, all Nuget Packages, etc
Comment 11 Brendan Zagaeski (Xamarin Team, assistant) 2015-06-18 20:09:14 UTC
To apply comment 7 to the specific test case that is attached to comment 0, the correct intended way to solve the problem is to install the "Microsoft HTTP Client Libraries" NuGet package into the "HttpAsyncTest" iOS _app project_ in addition to having it installed in the "HttpAsyncLibrary" PCL project.

This is the intended way to use NuGet PCL libraries that contain platform-specific code. (And the "Microsoft HTTP Client Libraries" NuGet _does_ include platform-specific code.)

In case it's helpful as an additional example, ModernHttpClient [1] has this same requirement because it also contains platform-specific code: the NuGet package must be installed into both the PCL library dependencies _and_ the app project that uses the dependencies. (See also [2] for more related discussion.)

[1] https://www.nuget.org/packages/modernhttpclient/
[2] http://log.paulbetts.org/the-bait-and-switch-pcl-trick/