Category Archives: ws-*

WCF Timeouts

The last two articles about WCF Throttling part 1 and part 2 would not be complete without looking at WCF timeouts. Any potentially lengthy operation must have a timeout or the system might end up waiting indefinitely – this is remarkably prevalent when working across any network connection (Yes, LAN connections too).

Timeouts are not directly related to throttling properties, but effect the way the service (or client) performance under load. Timeout properties can be perceived as an annoyance when sending larger messages or dealing with slow connections or services. The frustration increase as the naming of the properties can be deceiving. Read on… and I’ll explain 🙂

Below are the binding properties that all throw TimeoutExceptions if any of setting thresholds are exceeded:

  • OpenTimeout (TimeSpan) – the interval of time provided for an open operation to complete including security handshakes (WS-Trust, WS-Secure Conversation etc.). The default is 00:01:00.
  • CloseTimeout (TimeSpan) – the interval of time provided for a close operation to complete. The default is 00:01:00.
  • SendTimeout (TimeSpan) – the interval of time provided for an entire operation to complete. This includes both sending of message and receiving reply! The default is 00:01:00.
  • ReceiveTimeout (TimeSpan) – the interval of time that a connection can remain inactive, during which no application messages are received, before it is dropped. The default is 00:10:00.
    • This setting is only used on the server-side and has no effect on client-side.
    • When using Reliable Sessions remember to set the InactivityTimeout property on the reliableSession element to the same value as the ReceiveTimeout property, as both inactivity timers has to be satisfied.

Example of configuration file:

<system.serviceModel>
  <bindings>
    <netTcpBinding>
      <binding name="netTcpBindingConfig"
               openTimeout="00:01:00"
               closeTimeout="00:01:00"
               sendTimeout="00:01:00"
               receiveTimeout="00:10:00">
        <reliableSession enabled="true"
                         inactivityTimeout="00:10:00" />
      </binding>
    </netTcpBinding>
  </bindings>
</system.serviceModel>

WCF Sessions and Reliable Messaging

There are a couple of ways to establish a session between client and service. The session is established by identifying clients via a unique identifier. The unique identifier is either conveyed by

  • the client credentials when WS-Security is utilized to established secure session
  • the TCP/IP socket connection when using an underlying connection-oriented protocol such as TCP
  • the WS-ReliableMessaging protocol token when requiring message ordering and message delivery assurance for transport protocols.

Read more about how WS-Reliable Messaging protocol in my article “How does Reliable Messaging work?

Enabling sessions are all done in the configuration file. Some bindings are sessionful by default like the tcpBinding and wsHttpBinding.

I continue with Hello World WCF code sample from my earlier articles: “Building a Windows Communication Foundation client” and “A simple Windows Communication Foundation Web Service”. You can download the source code from here: Hello World WCF with clients.

Just by changing the binding in the code sample configuration to wsHttpBinding in the service and the clients, you get secure sessions; wsHttpBinding is by default secured with message security. The secure session context is established with the WS-SecureConversation protocol.

In the service type implementation it is possible to retrieve the session identifier via the OperationContext.Current.SessionId.

If you want un-secure reliable ordered messages with sessions, then change the behavior of the wsHttpBinding by configuring the binding like below. The configuration shown is for the service, but the changes (in bold) are exactly the same as required in the clients’ configuration files.

< ?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system .serviceModel>
    <behaviors>
      <servicebehaviors>
        <behavior name="myBehavior">
          <servicemetadata httpGetEnabled="true"
                           httpGetUrl="http://localhost:8080/HelloWorldService" />
        </behavior>
      </servicebehaviors>
    </behaviors>
    <bindings>
      <wshttpbinding>
        <binding name="reliableBinding">
          <reliablesession enabled="true" ordered="true"/>
          <security mode="None" />
        </binding>
      </wshttpbinding>
    </bindings>
    <services>
      <service name="HelloWorldService"
               behaviorConfiguration="myBehavior">
        <endpoint address="http://localhost:8080/HelloWorldService"
                  binding="wsHttpBinding"
                  bindingConfiguration="reliableBinding"
                  contract="IHelloWorldService" />
      </service>
    </services>
  </system>
</configuration>

Now the session identifiers are conveyed by the WS-Reliable Messaging protocol (linie 13-18). It is possible to use secure and reliable messages, but security is disabled to prove the point of WS-Reliable Messaging can be used to establish sessions.

If the implementation of your service requires sessions, decorate the service contract with the SessionMode.Required – this will demand that every endpoint bindings exposing the service support sessions. The possible values of the SessionMode enum are Required, Allowed and NotAllowed where Allowed is default.

[ServiceContract(SessionMode=SessionMode.Required)]
public interface IHelloWorldService
{
    [OperationContract]
    string HelloWorld();
}

If guaranteed ordering of messages is assumed by the implementation and therefore required for dependable behavior of the service, then decorate the service contract with the DeliveryRequirements attribute with the parameter RequireOrderedDelivery set to true.

[ServiceContract(SessionMode=SessionMode.Required)]
[DeliveryRequirements(RequireOrderedDelivery=true)]
public interface IHelloWorldService
{
    [OperationContract]
    string HelloWorld();
}

If the configuration of an endpoint does not fulfill the requirements, the host throws an exception detailing the missing requirements.

When to use the sessions
Sessions in WCF does not deliver the same functionality as in ASP.Net or ASMX based Web Services. For instance the HttpSessionState store is not available, not even if the WCF service is hosted in the IIS. WCF sessions are similar to Remoting sessions and are only for service instancing.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class HelloWorldService : IHelloWorldService
{
    public string HelloWorld()
    {
        Console.WriteLine("Invoked by client with session ID {0}",
            OperationContext.Current.SessionId);

        return "Hello World";
    }
}

To control the instancing of the service type objects, decorate the service type with the ServiceBehavior attribute and specify the InstanceContextMode enum as in the above code.

The InstanceContextMode values are:

  • PerCall – A new InstanceContext object is created prior to and recycled subsequent to each call. If the channel does not create a session this value behaves as if it were PerCall.
  • PerSession – A new InstanceContext object is created for each session.
  • Single – Only one instance of the service type object is used for all incoming calls and is not recycled subsequent to the calls. If a service type object does not exist, one is created.

Download the sample code with reliable messaging here (Hello World WCF Reliable Messaging) and read more about WCF sessions here.

Configuring the DTC for WCF with WS-AtomicTransaction

If interoperability with other platforms is a requirement WS-Atomic Transaction must be used. It requires all the steps for DTC setup in previous blog entry Configuring the DTC for WCF for OleTx, but also a couple of additional ones.

If running Windows XP or Windows Server 2003 a hotfix is required as detailed in the .Net framework 3.0 release notes. The hotfix can be downloaded from here.

WS-Atomic Transaction requires a certificate to establishing Mutual Trust between the parties in a transaction. If a certificate issued by a trusted 3rd party is not available, it is possible to issue one for test purposes by running the below statement in the Visual Studio 2005 Command Prompt. It generates and installs a certificate in the LocalMachineMY store.

MakeCert -sr LocalMachine -pe -n “CN=mytestcertificate.com” -ss My -sky exchange -sp “Microsoft RSA SChannel Cryptographic Provider” -sy 12

To enable a graphical interface for the WS-AtomicTransaction Configuration Utility (wsatConfig.exe) register the WsatUI.dll by running the following command in the Visual Studio 2005 Command Prompt

regasm /codebase %PROGRAMFILES%Microsoft SDKsWindowsv6.0BinWsatUI.dll

Now open the DTC configuration again by the following steps:

  • Administrative Tools | Component Services | Computer | My Computer.
  • Right-click on My Computer and chose Properties – notice a WS-AT tab is now available
    – select it.
  • Check Enable WS-Atomic Transaction network support
  • Select the certificate under Endpoint certificate

WS-AtomicTrnasaction configuration

Now everything is ready to make use of WS-Atomic Transaction in WCF as long as the client and service are on the same machine.

If the client and service are located on different machines, each machine needs a certificate and any machine participating in a transaction must be explicitly authorized by establishing trust with the counterpart’s certificate.

Establishing trust and authorizing trust. These steps have to be performed on all parties.

  • Export the public key
  • Add the public key certificate to the counterpart’s LocalMachineMY and LocalMachineROOT
    stores.
  • Authorize the counterpart’s certificate in the WS-AT tab.

It seems like a daunting task, but it is worth it. I can’t figure out how I ever got by with old-style ASMX web services without transactional support.

Configuring the DTC for WCF with OleTx

When a transaction propagates from one process to another, the DTC (Distributed Transaction Manager) must be utilized, because to two or more independent parties are involved in the transaction.

Beforehand the WCF service must be prepared:

  • Decorate the service contract (interface) with the attribute TransactionFlow and specify
    if it is mandatory or allowed.
  • Specify on the service type (implementation) OperationBehavior attribute that a TransactionScope
    is required.
  • Enable transaction propagation on the binding via the transactionFlow element in the
    configuration file for both service and client.

If the service and client are ready and an attempt to propagate a transaction is executed the following TransactionManagerCommunicationException is thrown:

System.Transactions.TransactionManagerCommunicationException was unhandled by user code Message=”Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool.”

That is because the DTC does not allow inbound of outbound network transactions, by default.

Configure the client DTC to allow outbound network transactions and the service DTC to have inbound network transactions. If both client and service are running on same machine, enable both inbound and outbound network transactions.

To enable inbound or outbound network transaction navigate to

  • Administrative Tools | Component Services | Computer | My Computer.
  • Right-click on My Computer and chose Properties | MSDTC tab | Security Configuration.
  • Check Network DTC Access and under Transaction Communication Manager check Allow Inbound, Allow Outbound or both.

Now transaction propagation via OLE Transactions (OleTx) is possible. These are all the bindings that operate in a homogeneous Windows environment.