Can we use ChannelFactory<T> when the contracts (.NET classes, interfaces) are NOT defined in some common library consumed by client and service?

StackOverflow https://stackoverflow.com/questions/16931750

Question

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?

Was it helpful?

Solution 2

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 OperationContracts!

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.

OTHER TIPS

Try this, get the WSDL document from each version of your service. Compare the WSDL documents (.NET 4.5 supports single file WSDL documents out of the box) to see what WCF is expecting in the soap message for each service. Chances are a default XML namespace was taken from the .NET (different) namespaces somewhere thus making the "identical" service contracts actually be different. WCF does a lot for you in naming the XML namespaces and you will likely need to manually override those defaults throughout the service, operation and data contracts to make both services support identical soap messages.

On integrating with Java, as long as the Java client can be generated from the WSDL the service outputs there's a chance there won't be any issues. The big exception is configuring the security and authentication aspects of the Java client. This good blog post on specific WCF bindings for Java interop would be worth a look when working with Java based clients.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top