A good friend of mine contacted me over MSN yesterday with a really strange problem (or so, he thought). Here's the scenario.
He had made a .NET web service that exposes information from an internal system. Everything worked perfectly well in his development environment, but when he tried to publish his web service to one of their "live" webservers, strange things happened. Like any developer, the first thing he tried to do was to call the .asmx page directly to ensure that it was actually running. I'll use some made-up URLs, just for good measure ;-) Here's what he saw:
When calling http://www.mycompany.com/Service.asmx from his machine, he saw what he expected - the default web service test page (I thought something was weird here but I'll get back to that). However, when he tried to invoke the web service with some test input, it tried to make a call to http://localhost:8080/Service.asmx.
This means that if you tried to add a web reference in Visual Studio, you would get all sorts of errors, since the web service kept trying to contact localhost instead of www.mycompany.com.
Now, from the subject of this post you've probably already guessed what was going on:
Now, the web server and reverse proxy are located physically on the same machine. The proxy is set up to forward all incoming requests to the web server running on port 8080. That means that seen from the point of view of the web service, the request is for http://localhost:8080/service.asmx and not for the URL that the client thinks it's calling. Here's where I found out something really fishy was going on - because when I called the web service on the public URL, it showed me the complete debug form. Normally, the form is ONLY visible when you connect to the web service from localhost (unless you muddle with your web.config file of course).
Anyway, at first we thought there simply wasn't a way to circumvent this problem. The .asmx page automatically generates the proxy for us when we add a web reference.
But there is a really simple solution, it turned out. In the .NET Framework folder, there's a tool for generating web service proxy classes, called wsdl.exe. Call it as follows to have a proxy class generated, which you can simply include in your project:
wsdl.exe /language:cs /out:c:\dev\test\myproxy.cs http://www.mycompany.com/service.asmx?wsdl
Now, open the myproxy.cs file and notice that there is a this.URL property being set in the constructor (in this case this.URL was set to http://localhost:8080/service.asmx). Simply change the URL to http://www.mycompany.com/service.asmx and your proxy class is ready for use.
You shouldn't make a web reference now. Simply include myproxy.cs in your project and go ahead and initialise it in your code:
MyCompanyWebService ws = new MyCompanyWebService();
DataSet ds = ws.GetCustomerList();
It's as simple as that. Lots of you probably already know that this can be done, but I just didn't think it was obvious - so now it's blogged for the rest of the world to see.
(Note, I didn't figure out all of this on my own... it took a bit of trial and error and a few hints and clues from here and there, but we finally got it)