Working Web Services

Working with web services in .NET (starting from 2.0) should be as easy as 1-2-3. Tools are provided for auto-generating code based on a WSDL. With .NET 3 Microsoft tries to direct every developer to use WCF for handling web services. Trying to get a Axis based Java web service to work proved to require some tricks.

I first generated a web service client (proxy) using the Add Service Reference tool in Visual Studio. This got a me a WCF based class to interact with the web service. All this was easy, but when I tried to call one of the remote methods, I was literally left with nothing (null).

As the diagnostic features (message tracking and tracing) of WCF really didn’t reveal anything usefull, I had to implement my own custom behavior with a message inspector to see what was really happening behind the secenes. This revealed that messages where sent and received, but the data did not get processed by the client. In the end, there wasn’t much else to do than to fall back and to make use of the older .NET web service handling technology (System.Web.Services).

Once again generating a client based on the WSDL was easy. And when I now tried calling the remote function I was returned with the data I expected. So, once again legacy technology prevailed when the newer failed.

As authentication (basic HTTP) is required by most we services I needed my client to support this. Normally this should only require to supply some valid credentials:

MatrixWebServicesServiceproxy = new MatrixWebServicesService();
proxy.PreAuthenticate =
true;
proxy.Credentials =
new NetworkCredential("user", "password");

But this did not do the trick. Using a TCP sniffer I was able to see that the “Authorized” HTTP header did not get sent to the server. After some research I came to the following conclution: The .NET client (this also applies to WCF) is designed to expect a “Unauthorized” HTTP error (401) from the server to respond to, without that the credentials are not sent. Also setting the PreAuthenticate property to true will only force the client to send the credentials with every message after this has first been required by the server. The problem with the Java web service was that is sent a “Internal Server Error” HTTP error (501) and a valid SOAP error when the authentication failed. So the credentials where never sent.

The only solution I found for this was to modify the generated client code and force it to send the credentials with every message. This can be done by overriding the clients GetWebRequest method. As the client is based on a bunch of partial classes, you only need to add your own with the following code to get things running:

public partial class SomeJavaWebServices : System.Web.Services.Protocols.SoapHttpClientProtocol {

protected override WebRequest GetWebRequest(Uri uri)
{
    HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(uri);

    if (PreAuthenticate)
   
{

        NetworkCredential networkCredentials = Credentials.GetCredential(uri, “Basic”);
        if (networkCredentials != null)
        {

            byte[] credentialBuffer = new System.Text.UTF8Encoding().GetBytes(networkCredentials.UserName + “:” + networkCredentials.Password);

            request.Headers[“Authorization”] = “Basic “ + Convert.ToBase64String(credentialBuffer);
        }
        else
        {
            throw new ApplicationException(“No network credentials”);
        }
    }    return request;
}

 

}

Advertisements

2 thoughts on “Working Web Services

  1. To find the “Add Web Reference” function select the “Add Service Reference” option and click on the Advanced button.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s