views:

27

answers:

1

The old version of the WCF was delivering according to the old version of the interface

<endpoint name="ServiceName" address="http://production.server/Service.svc" 
 binding="basicHttpBinding" bindingConfiguration="myBasicHttpBinding" 
 contract="myAPI.IOriginalService" />

with the new version delivering

<endpoint name="ServiceName" address="http://development.server/Service.svc"
 binding="basicHttpBinding" bindingConfiguration="myBasicHttpBinding" 
 contract="myAPI.IDerivedService" />

This works fine. The old clients can connect to either server by asking for IOriginalService and new clients can ask for IDerivedService ... but they can only ask the development server for it, if they ask the production server, an error is thrown. That's all fine.

I'd prefer to have new clients try to be a bit clever, though and use the new format when they can, but use the old if it isn't available. I could just catch the exception, but that's expensive and I'd much rather do a test, than catch a known likely outcome.

So I want to connect to the endpoint and ask it for the contract value, then use the return value to decide which type to ask for, e.g.

var endPoint = someMethod("ServiceName");
var contractName = endPoint.WhatContractDoYouOffer(); 
if(contractName == "IOriginalService") 
  CallAMethod<IOriginalService>(parameters);
else
  CallAMethod<IDerivedService>(newParameters);

Is this feasible?

A: 

There's nothing within WCF "out of the box" to support this feature - except maybe:

  • expose your old service contract on one endpoint
  • expose the new service on a separate, new endpoint (new address, new port - whatever)

But making that decision where to connect to needs to be made client-side.

You could potentially think up a "dispatcher" WCF service which you could ask where to go for which contract - but then at least this WCF service's endpoint and contract would have to remain fixed for all times.

Of course, you can have multiple endpoints in your client-side app.config - and those can be loaded into memory and inspected:

ClientSection cs = ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection;

if(cs != null)
{
    foreach (ChannelEndpointElement ep in clientSection.Endpoints)
    {
        if(ep.Contract == 'IMyService')
        {
           Uri endpointAddress = e.Address;
        }
    }
} 

With this, you could create a single client side config which contains all endpoints, and you can dynamically find the one you're interested in.

marc_s