views:

138

answers:

1

When you have to introduce a breaking change in a ServiceContract, a best practice is to keep the old one and create a new one, and use some version identifier in the namespace.

If I understand this correctly, I should be able to do the following:

[ServiceContract(Namespace = "http://foo.com/2010/01/14")]
public interface IVersionedService
{
    [OperationContract]
    string WriteGreeting(Person person);
}

[ServiceContract(Name = "IVersionedService", Namespace = "http://foo.com/2010/02/21")]
public interface IVersionedService2
{
    [OperationContract(Name = "WriteGreeting")]
    Greeting WriteGreeting2(Person2 person);
}

With this I can create a service that supports both versions. This actually works, and it looks fine when testing from soapUI.

However, when I create a client in Visual Studio using "Add Service Reference", VS disregards the namespaces and simply sees two interfaces with the same name. In order to differentiate them, VS adds "1" to the name of one of them. I end up with proxies called

ServiceReference.VersionedServiceClient

and

ServiceReference.VersionedService1Client

Now it's not easy for anybody to see which is the newer version.

Should I give the interfaces different names? E.g

IVersionedService1
IVersionedService2

or

IVersionedService/2010/01/14
IVersionedService/2010/02/21

Doesn't this defeat the purpose of the namespace?

Should I put them in different service classes and get a unique URL for each version?

+1  A: 

Well, typically, you would not have a service implementation that implements both the old and the new interface at the same time. Therefore, if a new client comes along and connects to your new service, it would only get the new interface and all is fine.

If you need to be able to offer up both interfaces, then yes - you need to do some "magic" to make this possible:

  • if you can, derive the new interface from the old. This works as long as you're only adding on new stuff. A new service implementation would then implement both the old-style interface, as well as the new

    public interface IVersionedService2 : IVersionService1
    {
        [OperationContract(Name = "WriteNewGreeting")]
        Greeting WriteNewGreeting(Person2 person);
    }
    

    So your service implementation would then have both a WriteGreeting as well as a WriteNewGreeting method - the new clients could connect to and use either, while older clients would still see their IVersionService1 interface and the "old" namespace, and thus be able to continue to call your service

  • if you cannot derive the new service from the old, create a completely new service, and expose it on a new endpoint, e.g. a new address or port. That way, existing clients can keep on calling the existing and well known service, while new ones can be directed to a separate service on a separate endpoint and things should be fine for them, too

marc_s
Thanks. I actually don't have to derive the new interface from the old one in order to implement both. My service does public class VersionedService : IVersionedService, IVersionedService2and it works fine. My question is more about, do I have to add an incremented number to the interfaces when I'm already using versioned XML namespaces? Your answer seems to imply that I have to.
Tor Hovland
@Tor: no, not necessarily. If you have the same interface - old and new - in two separate XML namespaces, and exposed on two separate endpoints (two URL's) - then the client will always pick one or the other, and it will not have any clashes in naming, I think.
marc_s