具有动态端口0和TCP绑定的WCF服务发现

时间:2015-02-13 20:25:14

标签: .net wcf tcp wcf-binding ws-discovery

我想在端口0上启动一个服务(Mex启用mex TCP Binding) - 比如使用net TCP绑定再次在端点上签订合同“IHelloWorldOne”。

从我的服务的App.config

  <service name="Service.One.HelloWorldOne">
    <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" name="Mex" kind="mexEndpoint" listenUriMode="Unique" />
    <endpoint name="Discovery" kind="udpDiscoveryEndpoint" />
    <endpoint address="1/tcp" binding="netTcpBinding" name="Service.One" contract="Service.One.IHelloWorldOne" listenUriMode="Unique" />
    <host>
      <baseAddresses>
        <add baseAddress="net.tcp://localhost:0/service" />
      </baseAddresses>
    </host>
  </service>

请注意,端口为0 - 这基本上让Windows为端点提供了一个开放端口,这意味着“mex”端点可以获得一个随机端口。

在我的客户端:

        FindCriteria findCriteria = FindCriteria.CreateMetadataExchangeEndpointCriteria(typeof(IHelloWorldOne));
        //FindCriteria findCriteria = new FindCriteria(typeof(IHelloWorldOne));
        findCriteria.MaxResults = 1;
        findCriteria.Duration = TimeSpan.FromSeconds(5);
        findCriteria.Scopes.Add(new Uri(string.Format("net.tcp://sharedservice/{0}/", "SHAREDCONTEXT")));

        FindResponse response = discoveryClient.Find(findCriteria);
        try
        {
            if (response.Endpoints.Count > 0)
            {
                var mexClient = new MetadataExchangeClient(MetadataExchangeBindings.CreateMexTcpBinding());
                var contracts = new List<ContractDescription>() { ContractDescription.GetContract(typeof(IHelloWorldOne)) };
                EndpointAddress address = new EndpointAddress(response.Endpoints[0].ListenUris[0]);
                var endpoints = MetadataResolver.Resolve(contracts, address, mexClient);

注意:我正在使用ListenURI来交换元数据。但是,当我尝试这个时 - 我遇到了这个异常

异常

System.InvalidOperationException: Metadata contains a reference that cannot be resolved: 'net.tcp://localhost:50294/service/mex'. --->
System.InvalidOperationException: <?xml version="1.0" encoding="utf-16"?><Fault xmlns="http://www.w3.org/2003/05/soap-envelope"><Code><Value>Sender</Value><Subcode><Value xmlns:a="http://www.w3.org/2005/08/addressing">a:DestinationUnreachable</Value></Subcode></Code><Reason><Text xml:lang="en-US">
The message with To 'net.tcp://localhost:50294/service/mex' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher.  
Check that the sender and receiver's EndpointAddresses agree.</Text></Reason></Fault>

我能够在listenURI上看到mex端点的端口,但无法连接到它。

我尝试的另一种方法是将mex端点保留为常量并发现服务端口 - 我无法完成此操作,因为端口在响应端点的listenURI上不可用。

所以我的问题是,有没有办法绑定到WCF中的端口0以获取Mex和服务端点并发现它们?如果是这样,怎么样?

1 个答案:

答案 0 :(得分:1)

来自您的例外消息:

  

EndpointDispatcher

上的AddressFilter不匹配

这是因为端点地址应与创建端点时指定的完全相同(例如port = 0)

问题是MetadataResolver没有使用以下重载 MetadataExchangeClient类

public MetadataSet GetMetadata(
    EndpointAddress address,
    Uri via
)

此处地址应该是您的情况 response.Address (带端口0)

via 参数应该是它侦听的端点的实际Uri(例如,有实际的端口号) response.Endpoints [0] .ListenUris [0]

似乎没有简单的方法可以将MetadataResolver与动态端口一起使用。

在我的情况下,我在动态端口上提供服务,并使用发现来查找为服务分配的端口。

在客户端,我使用以下代码:

FindResponse response = discoveryClient.Find(findCriteria);
var binding = new NetTcpBinding(SecurityMode.None);
return ChannelFactory<IMyService>.CreateChannel(binding, response.Endpoints[0].Address, response.Endpoints[0].ListenUris[0]);

这里我指定了端口0的端点地址和带有来自ListenUris的动态分配端口的实际地址。

希望这有助于解决您的问题。