Bug 37342 - [Mono 4.2] ArgumentOutOfRangeException when using ChannelFactory if BasicHttpBinding.SendTimeout is set to TimeSpan.MaxValue
Summary: [Mono 4.2] ArgumentOutOfRangeException when using ChannelFactory if BasicHttp...
Status: NEW
Alias: None
Product: Class Libraries
Classification: Mono
Component: WCF assemblies (show other bugs)
Version: 4.2.0 (C6)
Hardware: PC Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: marcos.henrich
: 37338 (view as bug list)
Depends on:
Reported: 2015-12-31 02:14 UTC by Brendan Zagaeski (Xamarin Team, assistant)
Modified: 2017-09-06 16:55 UTC (History)
3 users (show)

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

Test case (5.65 KB, application/zip)
2015-12-31 02:14 UTC, Brendan Zagaeski (Xamarin Team, assistant)

Description Brendan Zagaeski (Xamarin Team, assistant) 2015-12-31 02:14:27 UTC
Created attachment 14418 [details]
Test case

[Mono 4.2] ArgumentOutOfRangeException when using ChannelFactory if BasicHttpBinding.SendTimeout is set to TimeSpan.MaxValue

## Regression status: a "new feature" in Mono 4.2 has exposed a new problem 

In Mono 4.0.5 (1d8d582) and earlier, the local `value` variable was always "60000" during the call to `System.Net.HttpWebRequest.set_Timeout()` that happened during a `BasicHttpBinding` WCF channel setup.

In Mono 4.2 and later, if the user sets `BasicHttpBinding.SendTimeout`, that number now propogates correctly into the `value` variable in the `set_Timeout()` method. Unfortunately, this exposes a place where the .NET behavior differs from the current Mono behavior.

In .NET, you can set `BasicHttpBinding.SendTimeout` to `TimeSpan.MaxValue` and everything works without error.

In Mono, using `TimeSpan.MaxValue` causes an integer overflow, and leads to an ArgumentOutOfRangeException.

There's a chance this is an arbitrary implementation decision in .NET, so Mono's behavior might not necessarily be "wrong." For example, the documentation for `Binding.SendTimeout` [1] does not specify that `TimeSpan.MaxValue` is a valid input value.

[1] https://msdn.microsoft.com/en-us/library/system.servicemodel.channels.binding.sendtimeout.aspx

## Steps to replicate

1. Build the project:
> $ xbuild /t:Build /p:Configuration=Debug ConsoleWCFClient.csproj

2. Run the resulting `.exe`:
> $ mono bin/Debug/ConsoleWCFClient.exe

## Results

### Mono 4.2 (39edf24)

If you set Xamarin Studio to break on all exceptions, you can see that the program fails because `TimeSpan.MaxValue` overflows the integer `value` variable at:

> System.Net.HttpWebRequest.set_Timeout(int value) in /private/tmp/source-mono-mac-4.2.0-branch/bockbuild-mono-4.2.0-branch/profiles/mono-mac-xamarin/build-root/mono-4.2.1/mcs/class/System/System.Net/HttpWebRequest.cs:605
> System.ServiceModel.Channels.HttpRequestChannel.BeginProcessRequest(System.ServiceModel.Channels.HttpRequestChannel.HttpChannelRequestAsyncResult result) in /private/tmp/source-mono-mac-4.2.0-branch/bockbuild-mono-4.2.0-branch/profiles/mono-mac-xamarin/build-root/mono-4.2.1/mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpRequestChannel.cs:128

#### The stack trace output directly on the standard output of the program is less informative

> System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
> Parameter name: value
>   at (wrapper managed-to-native) System.Object:__icall_wrapper_mono_remoting_wrapper (intptr,intptr)
>   at (wrapper remoting-invoke) TempConvertSoap:EndFahrenheitToCelsius (System.IAsyncResult)
>   at ConsoleWCFClient.MainClass.OnTestMethodCompleted (IAsyncResult asyncResult) <0x2cc9828 + 0x000aa> in <filename unknown>:0 

### .NET 4.5 on Windows

The program completes successfully with the following output:

> Sent request...
> The converted value is: 37

Taking a guess that the .NET stack would also call `System.Net.HttpWebRequest.set_Timeout()`, I set a symbolic breakpoint on that method in Visual Studio. I discovered that the code that sets the timeout in .NET uses some extra logic that prevents the WCF channel from trying to set a timeout that overflows the integer. In particular, `HttpWebRequest.set_Timeout()` is called indirectly via `HttpChannelUtilities.SetRequestTimeout()` [2]. And that helper method in turn uses another `TimeoutHelper.ToMilliseconds()` helper method [3] that cleans up the maximum return value, avoiding the overflow.

[2] https://github.com/Microsoft/referencesource/blob/e458f8df6ded689323d4bd1a2a725ad32668aaec/System.ServiceModel/System/ServiceModel/Channels/HttpChannelHelpers.cs#L3279-L3289

[3] https://github.com/Microsoft/referencesource/blob/fa352bbcac7dd189f66546297afaffc98f6a7d15/System.ServiceModel.Internals/System/Runtime/TimeoutHelper.cs#L48-L63
Comment 1 Brendan Zagaeski (Xamarin Team, assistant) 2015-12-31 02:28:15 UTC
*** Bug 37338 has been marked as a duplicate of this bug. ***

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