当客户端是另一台主机上的Java时,WCF端点地址配置是否可以使用“localhost”?

时间:2013-07-14 17:34:13

标签: wcf wsimport

简短版本:当客户端是另一台计算机上的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问题。

我的大脑现在已经累了。我稍后会回来清理这段文字,使其成为某人愿意阅读和回应的东西。

3 个答案:

答案 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;
    }