HTTP POST Returns Error: 417 "Expectation Failed."

C#.NetHttpHttp PostWebclient

C# Problem Overview


When I try to POST to a URL it results in the following exception:

> The remote server returned an error: > (417) Expectation Failed.

Here's a sample code:

var client = new WebClient();

var postData = new NameValueCollection();
postData.Add("postParamName", "postParamValue");

byte[] responseBytes = client.UploadValues("http://...", postData);
string response = Encoding.UTF8.GetString(responseBytes); // (417) Expectation Failed.

Using an HttpWebRequest/HttpWebResponse pair or an HttpClient doesn't make a difference.

What's causing this exception?

C# Solutions


Solution 1 - C#

System.Net.HttpWebRequest adds the header 'HTTP header "Expect: 100-Continue"' to every request unless you explicitly ask it not to by setting http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.expect100continue(VS.80).aspx">this static property to false:

System.Net.ServicePointManager.Expect100Continue = false;

Some servers choke on that header and send back the 417 error you're seeing.

Give that a shot.

Solution 2 - C#

Another way -

Add these lines to your application config file configuration section:

<system.net>
    <settings>
        <servicePointManager expect100Continue="false" />
    </settings>
</system.net>

Solution 3 - C#

This same situation and error can also arise with a default wizard generated SOAP Web Service proxy (not 100% if this is also the case on the WCF System.ServiceModel stack) when at runtime:

  • the end user machine is configured (in the Internet Settings) to use a proxy that does not understand HTTP 1.1
  • the client ends up sending something that a HTTP 1.0 proxy doesnt understand (commonly an Expect header as part of a HTTP POST or PUT request due to a standard protocol convention of sending the request in two parts as covered in the Remarks here)

... yielding a 417.

As covered in the other answers, if the specific issue you run into is that the Expect header is causing the problem, then that specific problem can be routed around by doing a relatively global switching off of the two-part PUT/POST transmission via System.Net.ServicePointManager.Expect100Continue.

However this does not fix the complete underlying problem - the stack may still be using HTTP 1.1 specific things such as KeepAlives etc. (though in many cases the other answers do cover the main cases.)

The actual problem is however that the autogenerated code assumes that it's OK to go blindly using HTTP 1.1 facilities as everyone understands this. To stop this assumption for a specific Web Service proxy, one can change override the default underlying HttpWebRequest.ProtocolVersion from the default of 1.1 by creating a derived Proxy class which overrides protected override WebRequest GetWebRequest(Uri uri) as shown in this post:-

public class MyNotAssumingHttp11ProxiesAndServersProxy : MyWS
{
    protected override WebRequest GetWebRequest(Uri uri)
    {
      HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(uri);
      request.ProtocolVersion = HttpVersion.Version10;
      return request;
    }
}

(where MyWS is the proxy the Add Web Reference wizard spat out at you.)


UPDATE: Here's an impl I'm using in production:

class ProxyFriendlyXXXWs : BasicHttpBinding_IXXX
{
	public ProxyFriendlyXXXWs( Uri destination )
	{
		Url = destination.ToString();
		this.IfProxiedUrlAddProxyOverriddenWithDefaultCredentials();
	}

	// Make it squirm through proxies that don't understand (or are misconfigured) to only understand HTTP 1.0 without yielding HTTP 417s
	protected override WebRequest GetWebRequest( Uri uri )
	{
		var request = (HttpWebRequest)base.GetWebRequest( uri );
		request.ProtocolVersion = HttpVersion.Version10;
		return request;
	}
}

static class SoapHttpClientProtocolRealWorldProxyTraversalExtensions
{
	// OOTB, .NET 1-4 do not submit credentials to proxies.
	// This avoids having to document how to 'just override a setting on your default proxy in your app.config' (or machine.config!)
	public static void IfProxiedUrlAddProxyOverriddenWithDefaultCredentials( this SoapHttpClientProtocol that )
	{
		Uri destination = new Uri( that.Url );
		Uri proxiedAddress = WebRequest.DefaultWebProxy.GetProxy( destination );
		if ( !destination.Equals( proxiedAddress ) )
			that.Proxy = new WebProxy( proxiedAddress ) { UseDefaultCredentials = true };
	}
}

Solution 4 - C#

Does the form you are trying to emulate have two fields, username and password?

If so, this line:

 postData.Add("username", "password");

is not correct.

you would need two lines like:

 postData.Add("username", "Moose");
postData.Add("password", "NotMoosespasswordreally");

Edit:

Okay, since that is not the problem, one way to tackle this is to use something like Fiddler or Wireshark to watch what is being sent to the web server from the browser successfully, then compare that to what is being sent from your code. If you are going to a normal port 80 from .Net, Fiddler will still capture this traffic.

There is probably some other hidden field on the form that the web server is expecting that you are not sending.

Solution 5 - C#

Solution from proxy side, I faced some problems in the SSL handshake process and I had to force my proxy server to send requests using HTTP/1.0 to solve the problem by setting this argument in the httpd.conf SetEnv force-proxy-request-1.0 1 SetEnv proxy-nokeepalive 1 after that I faced the 417 error as my clients application was using HTTP/1.1 and the proxy was forced to use HTTP/1.0, the problem was solved by setting this parameter in the httpd.conf on the proxy side RequestHeader unset Expect early without the need to change anything in the client side, hope this helps.

Solution 6 - C#

For Powershell it is

[System.Net.ServicePointManager]::Expect100Continue = $false

Solution 7 - C#

If you are using "HttpClient", and you don't want to use global configuration to affect all you program you can use:

 HttpClientHandler httpClientHandler = new HttpClientHandler();
 httpClient.DefaultRequestHeaders.ExpectContinue = false;

I you are using "WebClient" I think you can try to remove this header by calling:

 var client = new WebClient();
 client.Headers.Remove(HttpRequestHeader.Expect);

Solution 8 - C#

In my situation, this error seems to occur only if my client's computer has a strict firewall policy, which prevents my program from communicating with the web service.

So only solution I could find is to catch the error and inform user about changing the firewall settings manually.

Solution 9 - C#

Check that your network connection isn't redirecting.

I had this issue when on the wrong wifi and any web request was redirecting to a corporate login page.

Solution 10 - C#

The web.config approach works for InfoPath form services calls to IntApp web service enabled rules.

  <system.net>
    <defaultProxy />
	<settings> <!-- 20130323 bchauvin -->
        <servicePointManager expect100Continue="false" />
    </settings>
  </system.net>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSaeb AminiView Question on Stackoverflow
Solution 1 - C#xcudView Answer on Stackoverflow
Solution 2 - C#Engin ArdıçView Answer on Stackoverflow
Solution 3 - C#Ruben BartelinkView Answer on Stackoverflow
Solution 4 - C#MooseView Answer on Stackoverflow
Solution 5 - C#HythamView Answer on Stackoverflow
Solution 6 - C#TNTView Answer on Stackoverflow
Solution 7 - C#Aviram FirebergerView Answer on Stackoverflow
Solution 8 - C#Emre Can SerteliView Answer on Stackoverflow
Solution 9 - C#justjoshinView Answer on Stackoverflow
Solution 10 - C#BobCView Answer on Stackoverflow