1

简短版本:localhost当客户端是不同机器上的 Java 时, WCF Windows 服务端点地址配置可以用作主机名吗?

长版:

我有一个作为 Windows 服务运行的 WCF 服务。该服务的客户端是用 Java 编写的,代理类使用wsimport. 当 WCF 服务上的端点配置包含包含 WCF 服务所在主机名的地址时,我可以生成 Java 代理类wsimport并成功运行客户端。在这种情况下,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.

所以,我想知道的是:localhost当客户端是不同机器上的 Java 时,WCF Windows 服务端点地址配置可以用作主机名吗?如果不是,为什么不呢?如果是这样,怎么做?

24 小时后:

还是没有解决。

Shiraz Bhaiji 提出的使用 NLB 的技术确实实现了我的部分目标:为所有服务器提供一个配置文件。端点地址中的主机名将是集群呈现给世界的“集群名称”,并且所有服务器上的所有服务都将具有相同的名称。

在我的 NLB 解决方案中,问题是运行该服务器的每台服务器都必须单独联系。它不是真正的集群类型服务,它更像是一种本地服务,十几个服务器中的每一个都需要运行,并且客户端将单独联系每个服务。

继续使用 Yaron Naveh 的回复中描述的技术,即使用本地 WSDL 文件生成代理。我能够生成 Java 代理类,wsimport但是当我使用它们访问 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 生成的。<wsdl:import>但是,WCF 服务发出的 WSDL 确实在元素中包含 localhost 引用:

<wsdl:import namespace="http://crOps.CompanionService" location="http://localhost:8432/crOpsCompanion/service?wsdl=wsdl0" /> 

所以Java试图检索location属性中的WSDL并且不能。

我开始想,用 C# 编写的 WCF 客户端会做同样的事情吗?换句话说,WCF 客户端是否想在运行时访问<wsdl:import>'slocation属性中指定的 WSDL?我经历了创建 WCF 客户端代理的相同过程,就像我为 Java 所做的那样。我使用了一个没有引用 to 的 WSDLlocalhost来生成代理类,然后访问了一个 WCF 服务,该服务的配置文件包含localhost在 WCF 端点地址配置中。

这行得通!WCF 客户端不需要能够在运行时检索在元素的location属性中指定的 WSDL。<wsdl:import>

所以现在这已成为我眼中的 Java/wsimport 问题。

我的大脑现在很累。我稍后会回来清理这堵文字墙,让它成为有人愿意阅读和回应的东西。

4

3 回答 3

1

看一下这个:

http://msdn.microsoft.com/en-us/library/ee816894.aspx

如果您根本不添加基地址会发生什么?

请注意,您遇到的问题只是在导入过程中。运行时将正常工作。因此,您可以让 java 客户端从固定 url(或本地 wsdl 文件)进行导入。

于 2013-07-14T17:43:36.793 回答
1

本地主机是一个环回地址,它会转到发出呼叫的机器。因此,如果您想从机器 A 调用机器 B,则不能使用 localhost。

这样做的方法是使用网络负载平衡 (NLB)。

使用 NLB 创建一个所有服务器都会响应的公共 IP 地址。然后,您可以拥有任何服务器都可以响应的单个地址。

于 2013-07-14T20:01:11.413 回答
0

我的答案是:“不,当您的客户端是 Java 时,您不能在 WCF 配置文件的端点地址中使用 localhost”。localhost 在运行时在 WSDL 中的多个位置发出,并导致我在上面的问题中描述的错误。

如果您的客户端是 C#/WCF 客户端,它确实有效。如果您的客户端是 C#/WCF,您可以在 WCF 配置文件的端点地址中包含 localhost。

但是为了让 WCF 为所有不包含主机名的服务器提供一个单一的配置文件,并让 Java 客户端使用 生成wsimport,您必须将所有端点配置放入代码中。

(边栏:Shiraz Bhaiji 提出的解决方案(NLB 集群)如果我没有额外要求运行服务的每个主机都可以单独寻址,那么我将实现我为所有服务配置单个 WCF 的目标。)

无论如何,这就是我最终做的事情:

1> 从应用配置文件中删除所有<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;
    }
于 2013-07-18T20:05:58.010 回答