Share via


Creating a duplex web-hosted service using netTcpBinding

We already have a sample that shows you how to use the NetTcpBinding in a web-hosted service here. And we have a sample showing you how to create a duplex service (one where the client calls the service and the service can call back into the client) here. But that sample uses HTTP. We've had some customers asking how they can create a duplex service that communicates over TCP. I have taken these two samples and basically merged them to come up with just that.

The service defines a service contract and a callback contract:

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode = SessionMode.Required,
                 CallbackContract = typeof(ICalculatorDuplexCallback))]
public interface ICalculator
{
 [OperationContract(IsOneWay = true)]
        void Clear();
        [OperationContract(IsOneWay = true)]
        void AddTo(double n);
        [OperationContract(IsOneWay = true)]
        void SubtractFrom(double n);
        [OperationContract(IsOneWay = true)]
        void MultiplyBy(double n);
        [OperationContract(IsOneWay = true)]
        void DivideBy(double n);
}
 
public interface ICalculatorDuplexCallback
{
        [OperationContract(IsOneWay = true)]
        void Equals(double result);
        [OperationContract(IsOneWay = true)]
        void Equation(string eqn);
} 
 
Implement the service contract:
 
public class CalculatorService : ICalculator
{
        double result = 0.0D;
        string equation;
 
 public CalculatorService()
  {
            equation = result.ToString();
        }
 
        public void Clear()
        {
            Callback.Equation(equation + " = " + result.ToString());
            equation = result.ToString();
        }
 
        public void AddTo(double n)
        {
            result += n;
            equation += " + " + n.ToString();
            Callback.Equals(result);
        }
 
        public void SubtractFrom(double n)
        {
            result -= n;
            equation += " - " + n.ToString();
            Callback.Equals(result);
        }
 
        public void MultiplyBy(double n)
        {
            result *= n;
            equation += " * " + n.ToString();
            Callback.Equals(result);
        }
 
        public void DivideBy(double n)
        {
            result /= n;
            equation += " / " + n.ToString();
            Callback.Equals(result);
        }
 
        ICalculatorDuplexCallback Callback
        {
            get
            {
                return OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();
            }
        }
}

Here's the service's web.config:

<?xml version="1.0" encoding="utf-8" ?>
 <!--Copyright (c) Microsoft Corporation.  All Rights Reserved.-->
<configuration>
  <system.serviceModel>
 
    <services>
      <service behaviorConfiguration="DuplexCalcBehavior"
               name ="Microsoft.Samples.TcpActivation.CalculatorService">
        <endpoint address="net.tcp://localhost/ServiceModelSamples/Service.svc"
                  binding="netTcpBinding"
                  contract="Microsoft.Samples.TcpActivation.ICalculator"/>
        <endpoint address="http://localhost/ServiceModelSamples/service.svc"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange"/>
      </service>
    </services>
    <bindings>
      <netTcpBinding>
        <binding  portSharingEnabled="true">
          <security mode="None" />
        </binding>
      </netTcpBinding>
    </bindings>
 
    <!--For debugging purposes set the includeExceptionDetailInFaults attribute to true-->
    <behaviors>
      <serviceBehaviors>
        <behavior name="DuplexCalcBehavior">
          <serviceMetadata httpGetEnabled ="true"/>
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
 
  </system.serviceModel>
</configuration>
 
On the client side, implement the callback contract:
 
 class CallbackHandler : ICalculatorCallback
    {
        public void Equals(double result)
        {
            Console.WriteLine("Equals called: " + result);
        }
 
        public void Equation(string eqn)
        {
            Console.WriteLine("Equation called: " + eqn);
        }
    }

Instantiate the type the CallbackHandler type, wrap it in a InstanceContext, and pass it to the proxy:

ICalculatorCallback callback = new CallbackHandler();
InstanceContext context = new InstanceContext(callback);

// Create a client with given client endpoint configuration
CalculatorClient client = new CalculatorClient(context);

Then we can call the service operations:

 // Call the AddT0 service operation.
double value1 = 100.00D;

client.AddTo(value1);
Console.WriteLine("AddTo({0}) called", value1);

// Call the SubtractFrom service operation.
value2 = 76.54D;
client.SubtractFrom(value2);
Console.WriteLine("SubtractFrom({0}) called", value2);

// Call the MultiplyBy service operation.
value1 = 10.00D;
client.MultiplyBy(value1);
Console.WriteLine("MultiplyBy({0}) called", value1);

// Call the DivideBy service operation.
value1 = 22.00D;
value2 = 7.00D;
client.DivideBy(value2);
Console.WriteLine("DivideBy({0}) called", value2);

Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();
//Closing the client gracefully closes the connection and cleans up resources
client.Close();

The config needed for the client is generated automatically when you add a service reference in Visual Studio 2010 in your client project.

You can find the complete sample here.