How to: Exchange Messages Within a Reliable Session
This topic outlines the steps required to enable a reliable session using one of the system-provided bindings that support such a session, but not by default. You enable a reliable session imperatively using code or declaratively in your configuration file. This procedure uses the client and service configuration files to enable the reliable session and to stipulate that the messages arrive in the same order in which they were sent.
The key part of this procedure is that the endpoint configuration element contain a bindingConfiguration
attribute that references a binding configuration named Binding1
. The <binding> configuration element references this name to enable reliable sessions by setting the enabled
attribute of the <reliableSession> element to true
. You specify the ordered delivery assurances for the reliable session by setting the ordered
attribute to true
.
For the source copy of this example, see WS Reliable Session.
Configure the service with a WSHttpBinding to use a reliable session
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); }
Implement the service contract in a service class. Note that the address or binding information isn't specified inside the implementation of the service. You aren't required to write code to retrieve the address or binding 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; } }
Create a Web.config file to configure an endpoint for the
CalculatorService
that uses the WSHttpBinding with reliable session enabled and ordered delivery of messages required.<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <services> <service name="Microsoft.ServiceModel.Samples.CalculatorService"> <!-- This endpoint is exposed at the base address provided by host: http://localhost/servicemodelsamples/service.svc Specify wsHttpBinding binding and a binding configuration to use --> <endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="Microsoft.ServiceModel.Samples.ICalculator" /> <!-- The mex endpoint is exposed at http://localhost/servicemodelsamples/service.svc/mex --> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services> <!-- Configures WSHttpBinding for reliable sessions with ordered delivery. --> <bindings> <wsHttpBinding> <binding name="Binding1"> <reliableSession enabled="true" ordered="true" /> </binding> </wsHttpBinding> </bindings> </system.serviceModel> </configuration>
Create a Service.svc file that contains the line:
<%@ServiceHost language=c# Service="CalculatorService" %>
Place the Service.svc file in your Internet Information Services (IIS) virtual directory.
Configure the client with a WSHttpBinding to use a reliable session
Use the 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>
The generated client 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); }
The generated client application also contains the implementation of the
ClientCalculator
. Note that the address and binding information isn't specified anywhere inside the implementation of the service. You aren't required to write code to retrieve the address or binding 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); } }
Svcutil.exe also generates the configuration for the client that uses the WSHttpBinding class. Name the configuration file App.config when using Visual Studio.
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <client> <!-- Specify wsHttpBinding binding and a binding configuration to use --> <endpoint address="http://localhost/servicemodelsamples/service.svc" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="Microsoft.ServiceModel.Samples.ICalculator" /> </client> <!-- Configures WSHttpBinding for reliable sessions with ordered delivery --> <bindings> <wsHttpBinding> <binding name="Binding1"> <reliableSession enabled="true" ordered="true" /> </binding> </wsHttpBinding> </bindings> </system.serviceModel> </configuration>
Create an instance of the
ClientCalculator
in an application and 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(); } }
Compile and run the client.
Example
Several of the system-provided bindings support reliable sessions by default. These include:
For an example of how to create a custom binding that supports reliable sessions, see How to: Create a Custom Reliable Session Binding with HTTPS.