28 February 2008

Forcing a web service proxy to use a specific http version

A short one this time, and a rare one too, but taken from real life. Sometimes a web service is implemented in such a way that it only understands http 1.1 or 1.0 but the proxy class that Visual Studio.NET generated does not know that (because the service is badly implemented, or for some other reason). If you cannot change the service implementation, you will have to change your client implementation. Say, you added a web reference to a web service and called the generated proxy class "MyService". The only thing you need to do is:
using System;
using System.Net;

namespace MyApplication
{
  public class MyFixedHTTPService : MyService
  {
    protected override WebRequest GetWebRequest(Uri uri)
    {
      HttpWebRequest w = base.GetWebRequest(uri) as HttpWebRequest;
      w.ProtocolVersion = HttpVersion.Version10;
      return w;
    }
  }
}
and then use this class to call your service. This forces the proxy to use HTTP 1.0. The best thing about the subclassing approach is that you can simply regenerate the proxy class if you need to, while still retaining your modifications

3 comments:

Dhananjay said...

Hi,
I am facing little problem and think you would be capable to answer it.

The environment contains, web-service hosted on internet, a proxy server and a client machine which needs to connect first to proxy to hit the web service.

In one of my sample application, I have to call the webservice first and then require to download a file from internet, both on different servers.

Proxy information is set on IE and I do nothing programatically as far as proxy settings are concerned.

Its strange to see that I am able to hit the web service but could not download the file. I use standard HttpWebRequest and HttpResponse classes for file download.

The error message I receive is: The remote server returned an error: (404) Not Found. at System.Net.HttpWebRequest.GetResponse()

I tried running different web-services but I observe same behaviour. However If I call the download method first, it runs without any error.

I would appreciate any help.

Thanks!
dgoyani@gmail.com

Joost van Schaik said...

Hello Dhananjay

I have looked into your code and while I fail to see what you are trying to accomplish, I can one thing for sure: you set a proxy for your plain HTTP request, but you fail to do so for your web service call. I have changed the code of your CallWebService2 method using a little copy-and-past from your own code

private void CallWebService2()
{
bool bAuto = chkAuto.Checked;
string strIP = txtIP.Text;
string strPort = txtPort.Text;
string strUser = txtUser.Text;
string strPass = txtPass.Text;

SampleWebService.SimpleWebService service = new ProxyCheck.SampleWebService.SimpleWebService();
if (bAuto == false)
{
//use user provided proxy settings
service.Proxy = new WebProxy(strIP, Convert.ToInt16(strPort));
service.Credentials = new NetworkCredential(strUser, strPass);
}
string result = service.EchoInput("Hello World!");
WriteToTextbox("Result: " + result);
}

and now it seems to work fine. Nice program that AnalogX Proxy btw. Might come in handy one day

Cheers, Joost

Dhananjay said...

Hello Joost,

Few updates:

I created sample application which GETs google logo through HTTP web request in first place and then call one sample asp.net web-service through HTTP POST method. Surprisingly, in Fiddler, I found Google page not found error-page for the second asp.net web-service call. And vice versa, if asp.net web-service is called in first place, I got asp.net page not found error-page for the google logo request. i.e. first good connection was used for consecutive web calls in the same application life cycle.

Reason:
The default ‘Keep Alive’ in web-service call or in HTTP web request (that we do for file downloads) is true, meaning the same TCP connection will be used for all requests be it web-service or HTTP calls.

Fix:
In order to fix the problem, we must have to set Keep-Alive property to FALSE explicitly for both HTTP and Web-service calls. However there is a possibility of performance hit.

Trick for Web-service calls:
We may never want to call web-service through raw HTTP web requests. But web-service proxy class which is created through .NET IDE doesn't expose http web request object. Anyways, you can write a partial class extending .NET IDE generated class and override onGetRequest and assign Keep Alive to false.

It works. Thank you for your co operation so far.

Thanks!
Dhananjay