Thursday 15 March 2012

How to sniff SOAP messages exchanged between WCF Service Host and Test Client

In my article "How to create and test WCF Web Service" I described how to implement simple Calculator service and test it from standalone WCF Service Host and Test Client.

SOAP Web Service and client exchange SOAP messages (request and response) during web method calls. SOAP messages are wrapped with HTTP messages and could be viewed and analysed by using some HTTP sniffer application.

For HTTP (SOAP) debugging I usually use Fiddler. It is a HTTP Proxy running on port 8888 on the local host. By default it intercepts HTTP traffic between web browsers and servers but can be set to sniff HTTP packets for any application that accepts HTTP proxies.

If we set Calculator web service to listen on port 8733 (defined in baseAddress URL in App.config) we can run WCF Service Host:

C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE>WcfSvcHost.exe /service:"c:\DEVELOPMENT\RESEARCH\C#\WCF\Web Services\CalculatorServiceLibrary\CalculatorServiceLibrary\bin\Debug\CalculatorServiceLibrary.dll" /config:"c:\DEVELOPMENT\RESEARCH\C#\WCF\Web Services\CalculatorServiceLibrary\CalculatorServiceLibrary\bin\Debug\CalculatorServiceLibrary.dll.config

...and Test Client:

C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE>WcfTestClient.exe http://localhost:8733/Design_Time_Addresses/CalculatorServiceLibrary/Service1/mex

Their model of communication is simple: Web Service Host listens on port 8733 for incoming SOAP requests (on service endpoint with URL http://localhost:8733/Design_Time_Addresses/CalculatorServiceLibrary/Service1) or metadata requests (on metadata endpoint with URL http://localhost:8733/Design_Time_Addresses/CalculatorServiceLibrary/Service1/mex). Once client sends request, host is loading Web Service dll, executing web method, packing result into SOAP response and sending it back within HTTP response:


WCF-host-clt-no-proxy


Fiddler is by default listening on port 8888 and in this constellation cannot intercept traffic between WCF Host and Client. We need to set it as a HTTP proxy which will forward all HTTP traffic to port where WCF Host is listening - port 8733. This can be achieved by adding ReverseProxyForPort DWORD value to HKCU\SOFTWARE\Microsoft\Fiddler2 and setting it to 8733. Fiddler must be restarted to fetch this change.

Client can send now HTTP requests to port 8888 in which case Fiddler will be able to intercept and display HTTP messages. It will forward them to port 8733 so they will reach Web Service Host. Of course, client can still send HTTP requests directly to port 8733, bypassing Fiddler.

When we run WCF Test Client we are providing it with metadata URL. This metadata contains service URL which is one defined in the service's App.config. This URL contains port number and it is set to 8733. Client will use this URL in order to make web service call. But how can we trick client so it uses port 8888 instead of 8733? When client gets metadata, it stores it in its own config file - client.dll.config. This file is stored in user's temporary folder, e.g. in c:\Users\Bojan\AppData\Local\Temp\Test Client Projects\10.0\636e9680-a905-4c50-a9ed-99562eb36701\ and looks something like this:

client.dll.config:


We can modify this config file before invoking web methods. We can do it manually through any text editor or simply from Test Client application. We can navigate client to target port 8888 now (make sure Fiddler is running - it listens on port 8888):

C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE>WcfTestClient.exe http://localhost:8888/Design_Time_Addresses/CalculatorServiceLibrary/Service1/mex

WCF Test Client:

WCFTestClient-before-editing-endpoint-port

If we select and right click Config File node, a context menu appears with option Edit with SvcConfigEditor:

WCFTestClient-config-context-menu

If we click on it, Service Configuration Editor starts and loads client.dll.config:

WCFTestClient-config-editor

We can change port to 8888:

WCFTestClient-config-editor-after-editing

We can now invoke some web method, let's say Add:

WCFTestClient-invoke-add

Fiddler will capture exchanged HTTP messages and we can view their content (SOAP). This is a XML view:

Fidller-WCF-WS-Calc-XML-view

HTTP headers can be analysed in raw view:

Fidller-WCF-WS-Calc-Raw-View

This is the model of communication between WCF Test Client and Host via HTTP proxy we implemented above:


WCF-host-clt-Fiddler-proxy


Links and References:
Using Fiddler as a Reverse Proxy

No comments: