简短版本:当客户端是另一台计算机上的Java时,WCF Windows服务端点地址配置是否可以使用localhost
作为主机名?
长版:
我有一个作为Windows服务运行的WCF服务。此服务的客户端使用Java编写,使用wsimport
生成代理类。当WCF服务上的端点配置包含一个包含WCF服务所在的主机名的地址时,我可以使用wsimport
生成Java代理类并成功运行客户端。以下是此方案中WCF配置文件的外观:
<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>
这是生成代理的wsimport
命令:
C:\Program Files\Java\jdk1.7.0_17\bin\wsimport.exe -p crOps.companion -keep http://chvprdctxxa604.eu.scor.local:8432/crOpsCompanion/service?wsdl
一切正常。
然而此WCF服务在大约十二台服务器上运行。我目前的愿望是使配置文件“与主机无关”,这意味着相同的配置文件适用于所有服务器。换句话说,配置文件中没有主机名。
我搜索了一些方法来解决WCF配置文件,并没有发现任何东西。所以我决定尝试用localhost
代替主机名。看起来像这样......
<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>
但是,当我运行wsimport
命令(上面列出)时,我收到以下错误:
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.
所以,我想知道的是:当客户端是不同计算机上的Java时,WCF Windows服务端点地址配置是否可以使用localhost
作为主机名?如果没有,为什么不呢?如果是这样,怎么样?
24小时后:
仍未解决。
Shiraz Bhaiji提出的使用NLB的技术确实实现了我的目标:一个配置文件用于所有服务器。然后,端点地址中的主机名将是群集向全局呈现的“群集名称”,并且所有服务器上的所有服务都具有相同的名称。
我的NLB解决方案的问题是运行此服务器的每台服务器必须单独联系。它不是一个集群类型的服务,它更像是一个本地服务,每十几个服务器中的每一个都需要运行,而客户端将单独联系每个服务器。
接下来是Yaron Naveh的回复中描述的技术,即使用本地WSDL文件生成代理。我可以使用wsimport
生成Java代理类,但是当我使用它们来访问Web服务(在端点地址中有localhost)时,我得到了这个异常。这本身就好奇,它是单个printStackTrace()调用的输出,似乎是一个异常包装其他两个,但它看起来不像我曾经从堆栈跟踪中的包装异常看到的
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)
我在堆栈跟踪中注意到代理类正在尝试连接到localhost
以在运行时检索WSDL,尽管代理是使用不包含localhost引用的WSDL生成的。但是,WCF服务DOES发出的WSDL在<wsdl:import>
元素中包含localhost引用:
<wsdl:import namespace="http://crOps.CompanionService" location="http://localhost:8432/crOpsCompanion/service?wsdl=wsdl0" />
因此,Java正试图在location
属性中检索WSDL而不能。
我开始疑惑,用C#编写的WCF客户端会做同样的事情吗?换句话说,WCF客户端是否想要在运行时访问<wsdl:import>
的{{1}}属性中指定的WSDL?我完成了与Java相同的创建WCF客户端代理的过程。我使用了一个没有引用location
的WSDL来生成代理类,然后在WCF端点地址配置中访问了配置文件包含localhost
的WCF服务。
这个有效! WCF客户端无需在运行时重新查找localhost
元素的location
属性中指定的WSDL。
所以现在这已成为我眼中的Java / wsimport问题。
我的大脑现在已经累了。我稍后会回来清理这段文字,使其成为某人愿意阅读和回应的东西。
答案 0 :(得分:1)
检查出来:
http://msdn.microsoft.com/en-us/library/ee816894.aspx
如果您根本不添加基地址,会发生什么?
请注意,您遇到的问题仅在导入过程中。运行时可以正常工作。所以你可以让java客户端从固定的url(或本地wsdl文件)进行导入。
答案 1 :(得分:1)
Localhost是一个环回地址,用于拨打电话的机器。因此,如果您想从机器A调用机器B,则无法使用localhost。
执行此操作的方法是使用网络负载平衡(NLB)。
使用NLB创建一个所有服务器都会回答的公共IP地址。然后,您可以拥有任何服务器都可以响应的单个地址。
答案 2 :(得分:0)
我的案例中的答案结果是:“不,当您的客户端是Java时,您不能在WCF配置文件的端点地址中使用localhost”。 localhost在运行时在WSDL中的几个地方发出,并导致我在上面的问题中描述的错误。
如果您的客户是C#/ WCF客户端,它确实有效。如果客户端是C#/ WCF,则可以在WCF配置文件的端点地址中使用localhost。
但是,为了让WCF为不包含主机名的所有服务器提供单个配置文件,并使用wsimport
生成Java客户端,您必须将所有端点配置放在代码中。
(补充工具栏:Shiraz Bhaiji提出的解决方案(NLB群集)如果我没有额外要求运行服务的每个主机都可以单独寻址,那么我的目标就是为所有服务实现单个WCF配置。)
无论如何,这就是我最终做的事情:
1&GT;从应用配置文件中删除所有<endpoint>
和<host>
元素。
2 - ;添加以下代码以在我的应用程序中创建我的ServiceHost:
public ServiceHost getServiceHost()
{
string strURL = "http://" + System.Net.Dns.GetHostName() + ":8432/crOpsCompanion/service";
Uri httpAddress = new Uri(strURL);
Uri[] baseAddresses = { httpAddress };
ServiceHost host = new ServiceHost(typeof(crOps.CompanionService), baseAddresses);
host.AddServiceEndpoint(
typeof(crOps.ICompanionService),
new BasicHttpBinding(),
"");
ServiceMetadataBehavior mb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (mb == null)
{
mb = new ServiceMetadataBehavior();
mb.HttpGetEnabled = true;
host.Description.Behaviors.Add(mb);
}
host.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex");
return host;
}