How to: Host a WCF Service in WAS

This topic outlines the basic steps required to create a Windows Process Activation Services (also known as WAS) hosted Windows Communication Foundation (WCF) service. WAS is the new process activation service that is a generalization of Internet Information Services (IIS) features that work with non-HTTP transport protocols. WCF uses the listener adapter interface to communicate activation requests that are received over the non-HTTP protocols supported by WCF, such as TCP, named pipes, and Message Queuing.

This hosting option requires that WAS activation components are properly installed and configured, but it does not require any hosting code to be written as part of the application. For more information about installing and configuring WAS, see How to: Install and Configure WCF Activation Components.

Warning

WAS activation is not supported if the web server’s request processing pipeline is set to Classic mode. The web server’s request processing pipeline must be set to Integrated mode if WAS activation is to be used.

When a WCF service is hosted in WAS, the standard bindings are used in the usual way. However, when using the NetTcpBinding and the NetNamedPipeBinding to configure a WAS-hosted service, a constraint must be satisfied. When different endpoints use the same transport, the binding settings have to match on the following seven properties:

  • ConnectionBufferSize

  • ChannelInitializationTimeout

  • MaxPendingConnections

  • MaxOutputDelay

  • MaxPendingAccepts

  • ConnectionPoolSettings.IdleTimeout

  • ConnectionPoolSettings.MaxOutboundConnectionsPerEndpoint

Otherwise, the endpoint that is initialized first always determines the values of these properties, and endpoints added later throw a ServiceActivationException if they do not match those settings.

For the source copy of this example, see TCP Activation.

To create a basic service hosted by WAS

  1. Define a service contract for the type of service.

    [ServiceContract]
    public interface ICalculator
    {
       [OperationContract]
       double Add(double n1, double n2);
       [OperationContract]
       double Subtract(double n1, double n2);
       [OperationContract]
       double Multiply(double n1, double n2);
       [OperationContract]
       double Divide(double n1, double n2);
    }
    
    
  2. Implement the service contract in a service class. Note that address or binding information is not specified inside the implementation of the service. Also, code does not have to be written to retrieve that information from the configuration file.

    public class CalculatorService : ICalculator
    {
       public double Add(double n1, double n2)
       {
          return n1 + n2;
       }
       public double Subtract(double n1, double n2)
       {
          return n1 - n2;
       }
       public double Multiply(double n1, double n2)
       {
          return n1 * n2;
       }
       public double Divide(double n1, double n2)
       {
          return n1 / n2;
       }
    }
    
    
  3. Create a Web.config file to define the NetTcpBinding binding to be used by the CalculatorService endpoints.

    <?xml version="1.0" encoding="utf-8" ?>  
    <configuration>  
      <system.serviceModel>  
        <bindings>  
          <netTcpBinding>  
            <binding portSharingEnabled="true">  
              <security mode="None" />  
            </binding>  
          </netTcpBinding>  
        </bindings>  
      </system.serviceModel>  
    </configuration>  
    
  4. Create a Service.svc file that contains the following code.

    <%@ServiceHost language=c# Service="CalculatorService" %>
    
  5. Place the Service.svc file in your IIS virtual directory.

To create a client to use the service

  1. Use ServiceModel Metadata Utility Tool (Svcutil.exe) from the command line to generate code from service metadata.

    Svcutil.exe <service's Metadata Exchange (MEX) address or HTTP GET address>
    
  2. The client that is generated contains the ICalculator interface that defines the service contract that the client implementation must satisfy.

    //Generated interface defining the ICalculator contract	
    [System.ServiceModel.ServiceContractAttribute(
    Namespace="http://Microsoft.ServiceModel.Samples", ConfigurationName="Microsoft.ServiceModel.Samples.ICalculator")]
    public interface ICalculator
    {
    
        [System.ServiceModel.OperationContractAttribute(
    Action="http://Microsoft.ServiceModel.Samples/ICalculator/Add", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/AddResponse")]
        double Add(double n1, double n2);
    
            [System.ServiceModel.OperationContractAttribute(
    Action="http://Microsoft.ServiceModel.Samples/ICalculator/Subtract", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/SubtractResponse")]
        double Subtract(double n1, double n2);
    
            [System.ServiceModel.OperationContractAttribute(
    Action="http://Microsoft.ServiceModel.Samples/ICalculator/Multiply", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/MultiplyResponse")]
        double Multiply(double n1, double n2);
    
            [System.ServiceModel.OperationContractAttribute(
    Action="http://Microsoft.ServiceModel.Samples/ICalculator/Divide", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/DivideResponse")]
        double Divide(double n1, double n2);
    }
    
  3. The generated client application also contains the implementation of the ClientCalculator. Note that the address and binding information is not specified anywhere inside the implementation of the service. Also, code does not have to be written to retrieve that information from the configuration file.

    // Implementation of the CalculatorClient
    public partial class CalculatorClient : System.ServiceModel.ClientBase<Microsoft.ServiceModel.Samples.ICalculator>, Microsoft.ServiceModel.Samples.ICalculator
    {
    
        public CalculatorClient()
        {
        }
    
        public CalculatorClient(string endpointConfigurationName) :
                base(endpointConfigurationName)
        {
        }
    
        public CalculatorClient(string endpointConfigurationName, string remoteAddress) :
                base(endpointConfigurationName, remoteAddress)
        {
        }
    
        public CalculatorClient(string endpointConfigurationName,
                System.ServiceModel.EndpointAddress remoteAddress) :
                base(endpointConfigurationName, remoteAddress)
        {
        }
    
        public CalculatorClient(System.ServiceModel.Channels.Binding binding, 				System.ServiceModel.EndpointAddress remoteAddress) :
                base(binding, remoteAddress)
        {
        }
    
        public double Add(double n1, double n2)
        {
            return base.Channel.Add(n1, n2);
        }
    
        public double Subtract(double n1, double n2)
        {
            return base.Channel.Subtract(n1, n2);
        }
    
        public double Multiply(double n1, double n2)
        {
            return base.Channel.Multiply(n1, n2);
        }
    
        public double Divide(double n1, double n2)
        {
            return base.Channel.Divide(n1, n2);
        }
    }
    
  4. The configuration for the client that uses the NetTcpBinding is also generated by Svcutil.exe. This file should be named in the App.config file when using Visual Studio.

    
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <system.serviceModel> 
            <bindings> 
                <netTcpBinding> 
                    <binding name="NetTcpBinding_ICalculator"> 
                        <security mode="None"/> 
                    </binding> 
                </netTcpBinding> 
            </bindings> 
            <client> 
                <endpoint 
                  address="net.tcp://localhost/servicemodelsamples/service.svc" 
                  binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ICalculator" 
                  contract="ICalculator" name="NetTcpBinding_ICalculator" /> 
            </client>
        </system.serviceModel> 
    </configuration>
    
    
  5. Create an instance of the ClientCalculator in an application and then call the service operations.

    //Client implementation code.
    class Client
    {
        static void Main()
        {
            // Create a client with given client endpoint configuration
            CalculatorClient client = new CalculatorClient();
    
            // Call the Add service operation.
            double value1 = 100.00D;
            double value2 = 15.99D;
            double result = client.Add(value1, value2);
            Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);
    
            // Call the Subtract service operation.
            value1 = 145.00D;
            value2 = 76.54D;
            result = client.Subtract(value1, value2);
            Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);
    
            // Call the Multiply service operation.
            value1 = 9.00D;
            value2 = 81.25D;
            result = client.Multiply(value1, value2);
            Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);
    
            // Call the Divide service operation.
            value1 = 22.00D;
            value2 = 7.00D;
            result = client.Divide(value1, value2);
            Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
    
            //Closing the client gracefully closes the connection and cleans up resources
            client.Close();
    
            Console.WriteLine();
            Console.WriteLine("Press <ENTER> to terminate client.");
            Console.ReadLine();
        }
    }
    
  6. Compile and run the client.

See also