Don’t use “Add Service Reference”!

The Visual Studio tools have always been crappy at generating code. The result is acceptable if you are a Microsoft representative selling new technology at some fancy seminar, but it is nothing you want to use in a release version of you application. The Visual Studio “Add Service Reference” (WCF) feature makes no exception.

The “Add Service Reference” feature might become handy when you need to connect to some none-.NET services, but in most other cases I sincerely recommend the manual approach. In this article I’m only going to tell you have, if you need more information check Miguel A. Castro’s article “WCF the Manual Way…the Right Way“.

Start by createing a basic class library project and reference the System.ServiceModel. This library is going to be referenced by both the client and the server. Don’t use the WCF templates as they will only make your life harder on the long run.

Add your service interface to the newly created project:

[ServiceContract(Name = “TestService”, Namespace = http://www.company.com/tests”)]
public
interface ITestService
{
    
    [OperationContract]
    TestData GetData(TestData data);

}

[DataContract]
public
class TestData
{
   
public TestData(string message)
    {
        Message = message;
    }

    [DataMember]
    public
string Message { get; set; }

   
public
override string ToString()
    {
        return “Some shared override”;
    }
}

Now add a new project to your solution and implement the server the same way you normaly would:

public class TestService: ITestService
{

    #region ITestService Members

    public TestData GetData(TestData data)
    {
        return new TestData(“Hello world! + data.Message);
    }

    #endregion
}

Instead of messing around with the XML configuration file, just configure your host by code:

ServiceHost host = new ServiceHost(typeof(TestService), new Uri[] { new Uri(uri) });
NetTcpBinding
binding = new NetTcpBinding(SecurityMode.Transport);

binding.TransferMode = TransferMode.Streamed;
binding.MaxBufferSize = 65536;

binding.MaxReceivedMessageSize = 104857600;
host.AddServiceEndpoint(typeof(ITestService), binding, “service1”);

host.Open();

As you can see there is not much new to implementing the service, but now it’s time for the client!

Create a new project for the client and reference the class library you first created. Instead of going for the “Add Service Reference” option create your own proxy:

public class TestServiceClient: ITestService
{

    private ITestService service;
    
    public TestServiceClient(Uri uri)
    {
        
// Any channel setup code goes here
   
     EndpointAddress address = new EndpointAddress(uri);
        NetTcpBinding binding = new NetTcpBinding(SecurityMode.Transport);
        binding.TransferMode = TransferMode.Streamed;
        binding.MaxBufferSize = 65536;
        binding.MaxReceivedMessageSize = 104857600;

        ChannelFactory<ITestService> factory = new ChannelFactory<ITestService>(binding, address);
        service = factory.CreateChannel();
    }

    #region ITestService Members

    public TestData GetData(TestData data)
    {
        return service.GetData(data);
    }

    #endregion
}

You can now place useful functions in your data classes and utilize them both on the client and server side. If you are running with .NET 3.5 you can even leave out the Data and Member Contract attributes of the data classes (same as choosing “Reuse types in referenced assemblies” when using thee Add Service Reference feature).

The biggest advantages of building your proxy manually compared to using the Add Service Reference feature is that you can now share classes and have the same client class implement several service interfaces instead of only one.