views:

28

answers:

1

I have three WCF services (.svc) which generate .wsdl references for SOAP messages.

Given that part of the namespace needs to change for all ServiceContract, OperationContract, DataContract attributes, for example

[DataContract(Namespace = "http://old.com.au/types/")]

to

[DataContract(Namespace = "http://new.com.au/types/")]

How is it that I can still support clients which have the old service reference (without them needing to update, because maybe they wont have time to update immediately) and allow clients getting a new service reference to get the new namespace? None of the service is changing, just the namespace.

So far I have read a lot of stuff but the following article suggests it is possible to change the service type from the ServiceHostFactory : http://blog.ranamauro.com/2008/07/hosting-wcf-service-on-iis-site-with_25.html

Which would mean creating two of every contract (putting as much of the implementation as possible in one place), and figuring out at runtime which serivce type to use. This would create some mess in my scenario.

Q. Is there an alternative, nice way to accomplish this or is it expected that this kind of thing should not be done and the client made to update to the new namespace.

(If there is a namespace mismatch from the client I get the error : The message with Action "..." cannot be processed at the receiver, due to a ContractFilter mismatch)

+2  A: 

IMO, you need to host old services for your previous clients at (preferably) old end points and have new services at new end points. You can take out old services when all your old clients migrate to newer version. Perhaps, you can use inheritance to reduce your efforts, for example

[DataContract(OldNameSpace)]
ClassA {
 ...
}

[DataContract(NewNameSpace)]
ClassB : ClassA {
}

Similarly, create new service contract from inheriting from new one. Service implementation need not change expect it needs to implement new contract. Now you have to configure two end point - one for old contract and another for new contract.

Edit: Put sample interfaces and implementation

Let's say your old contract was something like

public interface IOldContract
{
    ClassA GetFoo();
    void DoBar(ClassA a);
}

Now you can choose the new contract either as

public interface INewContract
{
    ClassB GetFoo();
    void DoBar(ClassB b);
    ClassB GetMix(ClassB a);
}

or as

public interface INewContract2 : IOldContract
{
    ClassB GetFoo2();
    void DoBar2(ClassB b);
    ClassB GetMix2(ClassB b);
}

I tend to go with later variation (as new contract remains compatible with old one). But in your case, you can choose former as you will be anyway exposing two endpoints. Now you need modify service implementation as follows:

    public class ServiceImplementation : INewContract2
{
    #region INewContract2 Members

    public ClassB GetFoo2()
    {
        // Your old implementation goes here 
    }

    public void DoBar2(ClassB b)
    {
        DoBar(b);
    }

    public ClassB GetMix2(ClassB b)
    {
        return GetMixHelper(b);
    }

    #endregion

    #region IOldContract Members

    public ClassA GetFoo()
    {
        return GetFoo2();
    }

    public void DoBar(ClassA a)
    {
        // You old implementation goes here
    }


    public ClassA GetMix(ClassA a)
    {
        return GetMixHelper(a);
    }

    #endregion

    private ClassB GetMixHelper(ClassA a)
    {
        // Your old implementation goes here
    }

}

I hope that you get the idea. Even here also you have multiple choices of code organization. You can have two skeleton service implementation classes - one for old contract and another for new contract. Both will delegate actually functionality to a helper class (which is your current implementation).

VinayC
Thanks will try it out
CRice
+1 I would also take this approach.
Ladislav Mrnka
There is a problem if I have 2 of each datacontract than I need to double up on a lot of implementation... where the old service returns a ClassA I now need a new serivce and method which returns a ClassB but it is the same implementation, and I would have to map return types from internal methods which return a ClassA as a ClassB if I want to share part of the existing functionality.
CRice
I have edited my response.
VinayC
As you said, you need to create internal methods where return types should be subclasses (new data contract classes) and parameters will be superclasses (old data contract classes). Check my edited response to get an idea.
VinayC
Thanks for your suggestion, there are a few minor issues with your example but I see what you are pointing out. The return types from the original solution require mapping as return types of the new solution, and can therefore use most of the implementation.
CRice