I was exploring ChannelFactory
and while doing so I did following:
A service contract in assembly named "Common":
namespace Common
{
using System.ServiceModel;
[ServiceContract(Name = "ITestService", Namespace = "http://test/")]
public interface ITestService
{
[OperationContract(Name = "SayHello")]
string SayHello(string request);
}
}
A service hosted under web application called "WcfServiceApp":
Note that I have created another service interface (contract) to create a service. But the names of contracts and the namespaces are same as the contract defined in the "Common" assembly.
namespace WcfServiceApp
{
[ServiceContract(Name = "ITestService", Namespace = "http://test/")]
public interface ITestServiceWithDiffDotNetName
{
[OperationContract(Name = "SayHello")]
string SayHelloAgain(string name);
}
// This service implements new service contract.
public class TestService : ITestServiceWithDiffDotNetName
{
public string SayHelloAgain(string request)
{
return "hello " + request;
}
}
// This service implements common service contract
public class TestService2 : Common.ITestService
{
public string SayHello(string request)
{
return "hello " + request;
}
}
}
There are two ".svc" files (TestService.svc and TestService2.svc), each for services created above. Web.config
has following:
<system.serviceModel>
<services>
<service name ="WcfServiceApp.TestService" >
<endpoint binding="basicHttpBinding" contract="WcfServiceApp.ITestServiceWithDiffDotNetName"></endpoint>
</service>
<service name ="WcfServiceApp.TestService2" >
<endpoint binding="basicHttpBinding" contract="Common.ITestService"></endpoint>
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
A client which calls these two services:
Note that client is using ChannelFactory
and the service contract defined in "Common" library.
ChannelFactory<ITestService> commonServiceChannel = new ChannelFactory<ITestService>(new BasicHttpBinding(), "http://localhost/WcfServiceApp/TestService.svc");
var proxy = commonServiceChannel.CreateChannel();
var response = proxy.SayHello("Mike"); // response = "Hello"
ChannelFactory<ITestService> commonServiceChannel2 = new ChannelFactory<ITestService>(new BasicHttpBinding(), "http://localhost/WcfServiceApp/TestService2.svc");
var proxy2 = commonServiceChannel2.CreateChannel();
var response2 = proxy2.SayHello("Mike"); // response2 = "Hello Mike"
Question:
I observed that first service (created using some different service contract) receives the null
argument whereas argument received in second service (created using service contract used to create ChannelFactory
) is "Mike" as expected.
In Fiddler, I can see that request parameter correctly.
Why does this happen?
If all XML names and namespaces are same (although names of .NET interfaces are different), should the service call not succeed as underlying SOAP messages would be same?
I am afraid what will happen if my customer's applications want to create service in Java and my application is supposed to call it?
Thanks to Sixto Saez first.
I compared the WSDL files generated (using svcutil.exe) by both the services and found that they were NOT EXACTLY SAME. However, it was not due to any conflict in the name or namespace of either ServiceContract
or OperationContract
itself!
It was due to difference in the parameter names used in the definition of the OperationContract
s!
You can see that OperationContract
"SayHello" has a parameter named "request". On the other hand, OperationContract
named "SayHelloAgain" has a parameter named "name". When I changed the name of the parameter from "request" to "name" as it is in second OperationContract
, it worked!
So the conclusion is:
ChannelFactory WORKS when the contracts (.NET classes, interfaces) are NOT defined in some common library consumed by client and service. Only thing is that WSDLs generated by those service contracts have to match with each other.