HTTP POST Returns Error: 417 "Expectation Failed."

222,106

Solution 1

System.Net.HttpWebRequest adds the header 'HTTP header "Expect: 100-Continue"' to every request unless you explicitly ask it not to by setting 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

Another way -

Add these lines to your application config file configuration section:

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

Solution 3

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

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

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.

Share:
222,106

Related videos on Youtube

Saeb Amini
Author by

Saeb Amini

Programmer, occasional blogger, C♯/.NET aficionado, team/tech lead, occasional public speaker, newbie gardener, nature lover, "mad keen fisho" If my most-earned badge hasn't already given it away, I also dabble in necromancy! I mostly give back to this helpful community by answering older questions I come across during my work that I feel could benefit from more information.

Updated on November 06, 2020

Comments

  • Saeb Amini
    Saeb Amini over 3 years

    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?

    • Salman A
      Salman A about 12 years
      The issue seems to happen when your application communicates through a proxy server. A .NET application I wrote worked when it was directly connected to internet but not when it was behind a proxy server.
    • Raymond
      Raymond about 12 years
      Observed this condition when a client is running through a HTTP 1.0 (only) proxy server. The client (asmx proxy without any configuration) is sending a HTTP 1.1 request and the proxy (before any server could ever get involved) then rejects what the proxy sends on. Should an end-user have this issue, using the config solution below is an appropriate workaround as it would cause requests to be generated without a reliance on the proxy understanding the Expect header which by default gets added as Expect100Continue is true by default.
  • xcud
    xcud over 15 years
    I had some code that talked to Twitter that suddenly stopped working the day after Christmas. They'd done an upgrade or config change that caused their servers to start choking on that header. It was a pain to find the fix.
  • xcud
    xcud over 15 years
    I think I picked up an extra 10 points for getting an answer accepted in a thread that Jon Skeet posted a solution into.
  • Madeleine
    Madeleine almost 14 years
    Thanks - saved me stacks of time - worked 100%. My solution used to work without this and then stopped working until I added it in... I guess they changed the config on their server..?
  • Eugene
    Eugene over 13 years
    Thanks! This should be noted somewhere in msdn examples such as msdn.microsoft.com/en-us/library/debx8sh9.aspx
  • Nyerguds
    Nyerguds about 13 years
    Hm, didn't work for me, now I'm getting The server committed a protocol violation. Section=ResponseStatusLine
  • Nyerguds
    Nyerguds about 13 years
    well, oddly enough, after some googling I fixed the protocol violation thing simply by setting my HttpWebRequest's "KeepAlive" property to False. Weird stuff.
  • Andre Luus
    Andre Luus about 13 years
    You can also specify that property in your app.config: <system.net> <settings> <servicePointManager expect100Continue="false"/>. nahidulkibria.blogspot.com/2009/06/…
  • Myster
    Myster almost 13 years
    Note: this setting also applies to ServiceReferences and I assume WebReferences.
  • Chris McAtackney
    Chris McAtackney over 11 years
    I know you posted this quite a while ago, but Ruben, you are a life saver. This issue has been driving me crazy until I came across your solution and it works perfectly. Cheers!
  • Raymond
    Raymond over 11 years
    @ChrisMcAtackney You're welcome. It definitely seemed worth the effort of documenting it at them time... the general issue set around the fringes of becoming a top-priority issue and just bothered me until I investigated it properly -- yet there didnt seem to be any google juice for that side of the issue. and it was one of that Attwood chap's posts from way back that pushed me to do it. (An upvote with a comment like this is fantastic BTW)
  • dawebber
    dawebber over 10 years
    Works very well when you have to make an operational change and are not ready for a code change.
  • Fadi Chamieh
    Fadi Chamieh over 10 years
    Wonderful addition and examples. Thanks!
  • RLH
    RLH over 9 years
    You, sir, have saved <strike>my life</strike> me several hours.
  • Chris
    Chris over 9 years
    @Apoorva When using HttpWebRequest it must come before Write-ing to the request stream. For WebClient, probably before UploadValues.
  • Haukman
    Haukman over 9 years
    This also made it work through Southwest's in-flight WiFi (they're using a proxy service for HTTP)
  • Raymond
    Raymond over 9 years
    dup of stackoverflow.com/a/7358457/11635 Please comment there if you want to add a point
  • J86
    J86 about 8 years
    What does that line of config do?
  • HGMamaci
    HGMamaci over 3 years
    Perfect - Thank you. A very small notice. This may take into effect after several seconds/minutes you call the method. I don't know why and weird, but this has not worked out, than it worked after a few minutes.

Related