2

I would like to start a service (with Mex enabled with mex TCP Binding) on port 0 - say for contract "IHelloWorldOne" on a end point using net TCP binding again.

From my service's 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>

Note that, port is 0 - this basically lets windows give me an open port for the end point and this would mean that "mex" endpoint could get a random port.

On my client:

        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);

Note: I am using the ListenURI to get the metadata exchanged. However, when I try that - I run into this exception

Exception

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>

I am able to see the port for mex endpoint on the listenURI but unable to connect to it.

The other approach I tried was to leave the mex end point as a constant and discover the service port - I was not able to get this done as well as the port is not available on the listenURI of the endpoint from the response.

So my question is, is there a way to bind to port 0 in WCF for Mex and service end points and also discover them? If so, how?

1 Answers1

1

From your exception message:

AddressFilter mismatch at the EndpointDispatcher

This is because endpoint address should be exactly the same as you specified when creating endpoint (e.g. port = 0)

The problem is that MetadataResolver not using following overload of MetadataExchangeClient class

public MetadataSet GetMetadata(
    EndpointAddress address,
    Uri via
)

Here address should be in your case response.Address (with port 0)

The via parameter should be actual Uri of your endpoint it listens on (e.g. have actual port number) in your case response.Endpoints[0].ListenUris[0].

It appears that there is no simple way to use MetadataResolver with dynamic port.

In my case I have service on dynamic port and using discovery to find what port was assigned to the service.

On the client side I'm using following code:

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]);

Here I'm specifying both endpoint address with port 0 and actual address with dynamically assigned port from ListenUris.

Hope this will help to solve your problem.

Alexey
  • 251
  • 2
  • 8