WCF services and Xml namespaces or How to implement overloading
It is trivial that a service can implement many different contracts at the same time and exposing an endpoint per contract. Simple and easy.
[ServiceContract]
public interface IAdd
{
[OperationContract]
int add(int a, int b) ;
}
[ServiceContract]
public interface ISub
{
[OperationContract]
int sub(int a, int b);
}
class Calc : IAdd, ISub
{
...
}
<services>
<service name="WCF_XmlNamespace.Calc">
<endpoint address="Add"
binding="basicHttpBinding"
contract="WCF_XmlNamespace.IAdd"/>
<endpoint address="Sub"
binding="basicHttpBinding"
contract="WCF_XmlNamespace.ISub"/>
</service>
</services>
The problem starts when we need the same function name in both contracts (i.e. Add)
What we actually need is overloading but as we know overloading is not supported for service contracts.
This might happen when we have a service for several customers and each customer wants the same method to have a different signature and to do something different.
We do not want to build the service per customer so we start with using C# namespaces.
namespace Special
{
[ServiceContract]
public interface IAdd
{
[OperationContract]
int Add(int a, int b, int c);
}
}
namespace WCF_XmlNamespace
{
[ServiceContract]
public interface IAdd
{
[OperationContract]
int Add(int a, int b) ;
}
class Calc : IAdd, Special.IAdd
{
#region IAdd Members
public int Add(int a, int b)
{
return (a + b);
}
#endregion
#region Special.IAdd Members
int Special.IAdd.Add(int a, int b, int c)
{
return (a + b + c);
}
#endregion
}
}
<services>
<service name="WCF_XmlNamespace.Calc">
<endpoint address="Add"
binding="basicHttpBinding"
contract="WCF_XmlNamespace.IAdd"/>
<endpoint address="SpecialAdd"
binding="basicHttpBinding"
contract="Special.IAdd"/>
</service>
</services>
This compiles of course but when we run it we get the following exception:
"The Service contains multiple ServiceEndpoints with different ContractDescriptions which each have Name='IAdd' and Namespace='http://tempuri.org/'. Either provide ContractDescriptions with unique Name and Namespaces, or ensure the ServiceEndpoints have the same ContractDescription instance."
In simple words C# namespaces solved the naming problem as far as compilation was concerned but WCF does not care about C# namespaces. A WCF service will accept a soap message with the action "Add" .It does not have any way of distinguishing between the two implementations. Remember that overloading i.e. taking the signature into account is not supported.
To solve the naming problem for the service we must introduce XML namespaces for the contracts.
namespace Special
{
[ServiceContract(Namespace="http://special.com")]
public interface IAdd
{
[OperationContract]
int Add(int a, int b, int c);
}
}
namespace WCF_XmlNamespace
{
[ServiceContract(Namespace="http://normal.com")]
public interface IAdd
{
[OperationContract]
int Add(int a, int b) ;
}
class Calc : IAdd, Special.IAdd
{
#region IAdd Members
public int Add(int a, int b)
{
return (a + b);
}
#endregion
#region Special.IAdd Members
int Special.IAdd.Add(int a, int b, int c)
{
return (a + b + c);
}
#endregion
}
Now it works.
The conclusions is that XML namespaces enables us to solve naming problems in the services XML world exactly like C# namespaces do in the C# programming world.
A final word. If we want no trace of the http://tempuri XML namespace in the WSDL or we want to create a flat WSDL like with old ASMX web services we need the service implementation to agree about the XML namespace with the service contract. We do that with a service behavior.
[ServiceBehavior(Namespace = "http://normal.com")]
class Calc : IAdd, Special.IAdd
{
The problem is that the service can have only one XML namespace and if we have two contracts with each having its own XML namespace we have a problem…