Short version: Can a WCF Windows Service endpoint address configuration use localhost
as the hostname when the client is Java on a different machine?
Long version:
I have a WCF service that runs as Windows Service. The clients of this service are written in Java, with proxy classes generated using wsimport
. When the endpoint configuration on the WCF service contains an address that includes the hostname on which the WCF service resides I can generate the Java proxy classes with wsimport
and run the client succesfully. Here's what the WCF config file looks like in this scenario:
<service name="crOps.CompanionService" behaviorConfiguration="CompanionServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://chvprdctxxa604.eu.scor.local:8432/crOpsCompanion/service"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" contract="crOps.ICompanionService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
Here's the wsimport
command to generate the proxy:
C:\Program Files\Java\jdk1.7.0_17\bin\wsimport.exe -p crOps.companion -keep http://chvprdctxxa604.eu.scor.local:8432/crOpsCompanion/service?wsdl
This all works fine.
However this WCF service runs on about a dozen servers. My current wish is to make the config file "host-agnostic", meaning that the same configuration file works on all servers. In other words, no hostname in the config file.
I searched around a bit for a way to agnostify the WCF config file, and found nothing. So I decided to try localhost
in place of the hostname. That looks like this...
<service name="crOps.CompanionService" behaviorConfiguration="CompanionServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8432/crOpsCompanion/service"/>
</baseAddresses>
</host>
<endpoint address="" binding="basicHttpBinding" contract="crOps.ICompanionService"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
However when I run the wsimport
command (listed above) I get the following error:
parsing WSDL...
[ERROR]
Unable to parse "http://localhost:8432/crOpsCompanion/service?wsdl=wsdl0" :
Connection refused: connect
line 1 of http://chvprdctxxa604.eu.scor.local:8432/crOpsCompanion/service?wsdl
[ERROR]
Unable to parse "http://localhost:8432/crOpsCompanion/service?wsdl=wsdl0" :
Connection refused: connect
Failed to read the WSDL document:
http://chvprdctxxa604.eu.scor.local:8432/crOpsCompanion/service?wsdl, because
1) could not find the document;
2) the document could not be read;
3) the root element of the document is not <wsdl:definitions
>.
[ERROR] failed.noservice=Could not find wsdl:service in the provided WSDL(s):
http://chvprdctxxa604.eu.scor.local:8432/crOpsCompanion/service?wsdl
At least one WSDL with at least one service definition needs to be provided.
Failed to parse the WSDL.
So, what I'd like to know is: Can a WCF Windows Service endpoint address configuration use localhost
as the hostname when the client is Java on a different machine? If not, why not? If so, how?
24 Hours Later:
Still not solved.
The technique propsed by Shiraz Bhaiji, to use NLB, does in fact accomplish part of my goal: one config file for all servers. The hostname in the endpoint address would then be the "cluster name" that the cluster presents to the world and all services on all servers would have the same name.
The problem in my case for the NLB solution is that each server running this server must contactable individually. It's not really a cluster type service, it's more of a local service that each one of a dozen or so servers needs to run and clients will contact each on individually.
So on to the technique described in Yaron Naveh's reply, which is to use a local WSDL file to generate the proxies. I am able to generate the Java proxy classes with wsimport
but then when I use them to access the web service (which has localhost in the endpoint address) I get this exception. Which is itself curious looking to me, it's the output of a single printStackTrace() call and seems to be an exception wrapping two others, but it doesn't look like what I'm used to seeing from a wrapped exception in a stack trace.
com.sun.xml.internal.ws.wsdl.parser.InaccessibleWSDLException: 2 counts of InaccessibleWSDLException.
javax.xml.stream.XMLStreamException: Invalid WSDL http://chvprdctxxa604:8432/crOpsCompanion/service, expected {http://schemas.xmlsoap.org/wsdl/}definitions found HTML at (lineLine number = 1
Column number = 7
System Id = http://chvprdctxxa604:8432/crOpsCompanion/service
Public Id = null
Location Uri= http://chvprdctxxa604:8432/crOpsCompanion/service
CharacterOffset = 10
)
java.io.IOException: Got Connection refused: connect while opening stream from http://localhost:8432/crOpsCompanion/service?wsdl=wsdl0
at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.tryWithMex(Unknown Source)
at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(Unknown Source)
at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(Unknown Source)
at com.sun.xml.internal.ws.client.WSServiceDelegate.parseWSDL(Unknown Source)
at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(Unknown Source)
at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(Unknown Source)
at com.sun.xml.internal.ws.spi.ProviderImpl.createServiceDelegate(Unknown Source)
at javax.xml.ws.Service.<init>(Unknown Source)
at crOps.companion.CompanionService.<init>(CompanionService.java:58)
at crOps.companion.Main.main(Main.java:14)
I noticed in the stack trace that the proxy classes are trying to connect to localhost
to retrieve the WSDL at runtime, although the proxies were generated with a WSDL that contained no reference to localhost. However, the WSDL emitted by the WCF service DOES contain a localhost reference in the <wsdl:import>
element:
<wsdl:import namespace="http://crOps.CompanionService" location="http://localhost:8432/crOpsCompanion/service?wsdl=wsdl0" />
So Java is trying to retrieve the WSDL in the location
attribute and can't.
I began wondering, would a WCF client written in C# do the same thing? In other words, does a WCF client want to access the WSDL specified in the <wsdl:import>
's location
attribute at runtime? I went through the same procedure creating a WCF client proxy as I did for Java. I used a WSDL with no reference to localhost
to generate the proxy classes and then accessed a WCF service whose configuration file contained localhost
in the WCF endpoint address configuration.
This works! A WCF client does not need to be able to retreieve the WSDL specified in the location
attribute of the <wsdl:import>
element at runtime.
So now this has become a Java/wsimport question in my eyes.
My brain is tired right now. I will come back later and clean up this wall of text to make it something that somebody would be willing to read and respond to.