WCF: Security Sessions and Service Throttling 

WCF includes support for establishing a security session through a simple configuration attribute. The primary reason of a security session is a shared security context which enables clients and services to use a faster, symmetric cryptographic exchange.

WCF sessions should not be thought of in terms of HTTP based sessions, since the former are initiated by clients and the latter by the servers. In other terms, WCF sessions are there to support some kind of shared context between a particular client and a service. This context can be anything, and is not limited to security contexts.

The attribute that establishes a security session and shared context is called, well, establishSecurityContext and is present in binding configuration. An example of such a binding would be:

<bindings>
  <wsHttpBinding>
    <binding name="SecureBinding">
      <security mode ="Message">
        <message clientCredentialType="Certificate" establishSecurityContext="true"/>
      </security>
    </binding>
  </wsHttpBinding>
<bindings>

This binding allows HTTP based communication, demands message based security (think WS-Security) and uses certificates to sign/encrypt the message content. The attribute establishSecurityContext is set to true, which actually enforces a WS-SecureConversation session between the client and the service.

The following is a simplified version of what is going on under the covers:

  • Client instantiates the service proxy
    No message exchange is taking place yet.
  • Client requests a SCT (Secure Context Token)
    This is done by the infrastructure, when the first service method is called. SCT (again simplified) represents a secure context, which includes the symmetric key. The message which demands it is (per WS-SecureConversation spec) called RST (Request Secure Token).
  • Service responds with RSTR (Request Secure Token Response) message
    Session bootstraps and is ready to piggyback all further message exchanges.

What is not well known is that there is a very low limit on the number of sessions a service is willing to accept. The default is set to 10 sessions and this was changed (from 64) late in the WCF development cycle (summer 2006). So RTM ships with this default.

Service session count is greatly influenced by the instancing scheme the service is using. Since instancing is a completely different beast, let's leave this for another post (uhm, I already wrote something here). Let's just say that hitting the session problem is a non-issue when using singleton instancing (InstanceContextMode = InstanceContextMode.Single).

The main issue is, that most developers think of Indigo WCF services in terms of simple request-response semantics and forget that such sessions get queued up on the service side if you do not terminate them appropriately.

This is the default service throttling behavior in the shipping version of WCF:

<behaviors>
  <serviceBehaviors>
    <behavior name="DefaultThrottlingBehavior">
      <serviceThrottling maxConcurrentCalls="16"
                         maxConcurrentSessions="10"
                         maxConcurrentInstances="<Int32.MaxValue>" />
    </behavior>
  </serviceBehaviors>
</behaviors>

Every service is throttled, even if you don't specify it. You can, of course, override all three throttling parameters.

Sessions can only be initiated by the client. They can be explicitly terminated only by the client. There are three ways a session can get terminated:

  • Explicitly by the client
  • Implicitly by a timeout
  • Implicitly by errors

Timeout can pass on a client or a service and, if the timeout happens, the transport channel that ensured communication gets faulted (Channel.State = CommunicationState.Faulted). Session is also terminated if an error is detected, thus invalidating the possibility to continue.

Remember that every service proxy you use will demand a new session on the service side (when using
sessionful services). If you spawn 11 threads and use a non-singleton proxy you will cause 10 sessions on the service side. The 11th will not get setup and will block the client thread until the timeout expires. In this case, the WCF infrastructure on the service side will issue a warning in the trace log, but nothing will be returned to the client. It seems as if the service would stop working. Nada.

There is a method on every service proxy and it's there for a reason. The method is called Close(). It closes the transport channel graciously and terminates the security session, thus freeing up service resources. The same happens for reliable messaging session or a combination of both.

Note: Another message (pair) is exchanged on Close(). This message is saying "We are done." to the service. Thus, one should be cautious when calling Close() for any exceptions, like CommunicationObjectFaultedException.

The best practice is to catch any CommunicationException exceptions when closing the channel.

To illustrate this, consider the following. You call a single method on a sessionful service. Then hang on to the service proxy instance for an hour. The inactivity timeout (attribute inactivityTimeout on a RM binding) is set to 10 minutes. So, ten minutes after the first call the channel gets faulted. Then you call Close(). This call will fail and throw an exception.

The following is the expected way of communication with sessionful services:

ServiceClient proxy = new ServiceClient("<Configuration>");
try
{
  // call service methods
  int intSum = proxy.Add(1, 2);

  // ... call all other methods ...

  
// call service methods
  int intSum = proxy.Subtract(1, 2);

  // close session
  proxy.Close();
}
catch (TimeoutException ex)
{
  // handle timeout exceptions
  proxy.Abort();
}
catch (FaultException<T1> ex)
{
  // handle typed exception T1
  proxy.Close();
}
...
catch (FaultException<Tn> ex)
{
  // handle typed exception Tn
  proxy.Close();
}
catch (FaultException ex)
{
  // handle all other typed exceptions
  proxy.Close();
}
catch (CommunicationException ex)
{
  // handle communication exceptions
  proxy.Abort();
}

Note that using the using statement is not recommended. The problem of using statement in this case is that CLR automatically calls Dispose() method on the using variable when exiting the statement. Since Close() can fail (remember, another message is exchanged), you can miss this important exception.

Everything in this post is true for all kinds of WCF sessions. It is not limited to security or RM sessions only.

Categories:  .NET 3.0 - WCF | Architecture
Tuesday, 27 February 2007 17:04:52 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 WCF, MSMQ et al: Durable Reliable Messaging 

I'm thinking about reliable messaging these days (isn't it evident?). There are a couple of specific reasons for that. First, I can imagine a wonderful world of seamless message delivery. Second, currently there are technology limitations that prohibit what most of the industry would like to see.

Let's take a look.

There's a sentence in the first post of the series that says:

There is no durable reliable messaging support in WCF.

This is conditionally true. There are built-in bindings that support MSMQ integration and use MSMQ transport as a delivery mechanism, thus making the message exchange durable. Limitations of this approach include platform dependence, durable store dependence and more importantly, one-way messaging. To implement a durable duplex session one would need to implement two one-way service contracts. Downside? Forget about clients sitting behing a NAT without poking holes in your firewalls.

There are multiple uses for having durable messaging, the most prominent being different client/service lifetimes. Why can't I dispatch a message to a service when the service is down or I have no network connectivity?

Reliable messaging support in WCF is designed to support reliable transport and does not make any assurances of what happens to messages when they hit both ends of the wire. The problem is not in the WCF implementation but rather the WS-RM spec, which does not imply on how and when a message should/must be persisted.

There are different implementations of durable transports or at least, some people are already thinking about it. Amazon's SQS Transport for WCF is a good idea, and so is SQL Server SSB usage... if you control both ends of the wire.

The industry (read WS-* stack) needs a specification which will cover interoperable + durable message delivery. BYODS ("bring your own durable store") concept would be efficient only when demanding a durable store on the other side of the wire, is governed by a messaging specification.

Categories:  .NET 3.0 - WCF
Wednesday, 21 February 2007 23:25:32 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 BITS Download Manager: Version 1.1.0 Available 

I updated my BITS Download Manager yesterday, making it even more Vista compatible.

Well, the compatibility was there from 1.0.2. But now, it shouldn't make any unnecessary UAC prompts go off.

If not for large HTTP based file downloads, I use it to track podcast downloads RSSBandit makes when using the new feature set.

Categories:  Other | Personal
Wednesday, 21 February 2007 16:26:14 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 WCF: About Exposing Metadata 

Everything about WCF is about keeping your service boundary intact. By default this also applies to exposing/publishing metadata. In ASMX days, one would need to opt-out of exposing metadata, while in WCF, one has to opt-in.

Let's say, for example, you have the following service config declaration:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name = "Exposing.Metadata">
        <host>
          <baseAddresses>
            <add baseAddress =
                 "http://localhost:123/MetadataService
">
          </baseAddresses>
        </host>
        <endpoint address = ""
                  binding = "wsHttpBinding" 
                  contract = "Exposing.IServiceContract"/>
      </service>
    </services>
  </system.serviceModel>
</configuration>

This would host Exposing.Metadata service and define a single wsHttpBinding based endpoint listening at the base address.

So, the service endpoint address is http://localhost:123/MetadataService. If you would hit the endpoint URL with a web browser, a nice service page would be returned telling you that you have created a service, but there is no metadata exposed. So, hitting the endpoint with svcutil.exe would not allow you to grab metadata and generate the proxy code.

WCF, by default, does not expose any metadata. You have to ask for it nicely.

There are a couple of options to expose metadata of WCF services. The most basic way of doing it would be to expose it via HTTP based Get requests and retrieve WSDL. The following code fragment would do it, if you hosted the service using a ServiceHost class:

[ 1]  using (ServiceHost sh = new ServiceHost(typeof(OpService)))
[ 2]  {
[ 3]   ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
[ 4]   smb.HttpGetEnabled = true;
[ 5]   sh.Description.Behaviors.Add(smb);
[ 6]   sh.Open();
[ 7]   Console.WriteLine("Service running...");
[ 8]
[ 9]   Console.ReadLine();
[10]   sh.Close();
[11]  }
 
Lines 3-5 instantiate and add a service behavior that allows a simple HTTP Get request to succeed for metadata retrieval. Also, the mentioned service page would now render a link to the WSDL definition of the service.

Declarative configuration with the same effect is this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name = "MetadataBehavior">
         <serviceMetadata httpGetEnabled = "true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name = "Exposing.Metadata"
               behaviorConfiguration = "MetadataBehavior">
        <host>
          <baseAddresses>
            <add baseAddress =
                 "
http://localhost:123/MetadataService"/>
          </baseAddresses>
        </host>
        <endpoint address = "" 
                  binding = "wsHttpBinding"
                  contract = "Exposing.IServiceContract"/>
      </service>
    </services>
  </system.serviceModel>
</configuration>

We declared a behavior, called MetadataBehavior and assigned it to our Exposing.Metadata service.

There are a couple attributes in <serviceMetadata> element worth discussing:

  1. externalMetadataLocation allows you to specify the path to your WSDL metadata file, so you can provide it out of band and not rely on the infrastructure to generate it for you.
  2. httpGetEnabled exposes this metadata via HTTP transport.
  3. httpGetUrl enables you to define a different relative WSDL metadata endpoint address. If 'wsdl' was used, our service would expose WSDL metadata at http://localhost:123/MetadataService/wsdl.
  4. httpsGetEnabled allows you to expose metadata via HTTPS transport.
  5. httpsGetUrl is analog to httpGetUrl but for HTTPS.

This nails down all options one would want for exposing HTTP based metadata endpoints.

Now, exposing metadata using the WS-MetadataExchange (WS-MEX or MEX) protocol is also opt-in. First, you have an option to include only HTTP based metadata, as described. Second, there is a way to expose all metadata only using WS-MEX.

Here's how, first the config file:

<serviceBehaviors>
  <behavior name = "MetadataBehavior">
    <serviceMetadata />
  </behavior>
</serviceBehaviors>

Note: This is only the <serviceBehaviors> section, not the complete service config file.

You have to tell the hosting infrastructure to expose metadata by adding a service behavior with the <serviceMetadata> element. What this does, essentially, is add an interface called IMetadataExchange to your contract - but does not expose it yet. You have to add a metadata endpoint to your service and bind it to a transport of choice.

Continuing with previous service configuration, here's what we get:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name = "MetadataBehavior">
          <serviceMetadata/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name = "Exposing.Metadata"
               behaviorConfiguration = "MetadataBehavior">
        <host>
          <baseAddresses>
            <add baseAddress =
                 "
http://localhost:123/MetadataService"/>
          </baseAddresses>
        </host>
        <endpoint address = ""
                  binding = "wsHttpBinding"
                  contract = "Exposing.IServiceContract"/>
        <endpoint address = "mex"
                  binding = "mexHttpBinding"
                  contract = "IMetadataExchange"/>
      </service>
    </services>
  </system.serviceModel>
</configuration>

When this service is hosted, MEX metadata is exposed at http://localhost:123/MetadataService/mex and you can reach it with svcutil.exe or 'Add Service Reference' in Visual Studio. HTTP based WSDL access is not allowed since <serviceMetadata> element does not include the httpGetEnabled property with the value of true. It's false by default, which resonates nicely in terms of WCF's opt-in scenarios.

Remember, service orientation is about defining boundaries. And reaching metadata about your service should be confined to your choosing, not the platforms.

Categories:  .NET 3.0 - WCF
Monday, 19 February 2007 14:05:46 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 WCF: Reliable Message Delivery Continued 

In the previous post we discussed possible scenarios and methods for configuring reliable message delivery in WCF. Let's look further into this great WCF feature.

Delivery assurances can have a large impact on the way your code processes incoming messages. Especially, ordering can be of importance if your code relies on ordered message delivery. Since configuration can be changed by any WCF service administrator there is a knob in WCF which lets you demand the appropriate binding. The knob is in a form of a declarative attribute, called DeliveryRequirementsAttribute.

Here's how it's used:

[DeliveryRequirements(RequireOrderedDelivery = true,
   QueuedDeliveryRequirements =
      QueuedDeliveryRequirementsMode.Required)]
interface IServiceContract
{
   int Operation(int a, int b);
}

DeliveryRequirementsAttribute can be set on any service interface or service class implementation. It has three properties:

  1. QueuedDeliveryRequirements which has three possible values, Allowed, NotAllowed and Required. Setting NotAllowed or Required makes the binding either demand or prevent WS-RM usage. Setting Allowed does not make any requirements.
  2. RequireOrderedDelivery demands a binding that supports and has ordered delivery turned on.
  3. TargetContract property is applicable only when the attibute is applied to a class definition. Since WCF service interfaces can be implemented by multiple classes, one can specify a specific interface for which the queued delivery requirements are defined.

The specified contract interface would demand a WS-RM capable binding and thus prevent service administrators to turn reliable delivery off.

In case where an administrator would turn reliable delivery (or ordering, in this case) off, the service host would throw an exception while trying to host the service.

So, DeliveryRequirementsAttribute guards developers from wrongdoings of service administrators. It should set QueuedDeliveryRequirements = QueuedDeliveryRequirementsMode.Required or RequireOrderedDelivery = true, when there are objective reasons to demand guaranteed and/or ordered delivery of messages.

Categories:  .NET 3.0 - WCF | Architecture
Monday, 19 February 2007 12:50:01 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 WCF: Reliable Message Delivery 

Windows Communication Foundation includes concepts which enable the developer to insist on reliably delivering messages in both directions. The mechanism is actually transport agnostic and allows messages to be flown reliably from client to service and replies from service to client.

Underneath, WS-ReliableMessaging (WS-RM) implementation is used. Click here for Microsoft's specification. Content is the same.

WS-RM is based on a concept of a message sequence. You can think of it in terms of a session, although it does not carry HTTP session semantics (remember, it's transport agnostic). A communication initiator (RM source) sends a <CreateSequence> element inside the message body to establish a RM sequence. Service side (RM destination) responds with either <CreateSequenceReponse> or <CreateSequenceRefused>, in cases where new sequence is not welcome.

After the sequence is initialized, there is an additional SOAP Header in messages. It identifies the message number being transferred. The following is a simple example of headers of the first two messages:

<S:Envelope>
   <S:Header>
      ...
      <wsrm:Sequence>
         <wsrm:Identifier>http://webservices.gama-system.com/RM/Service</wsrm:Identifier>
         <wsrm:MessageNumber>1</wsrm:MessageNumber>
      </wsrm:Sequence>
   </S:Header>
   ...
   <S:Body>
      ...
   </S:Body>
</S:Envelope>

<S:Envelope>
   <S:Header>
      ...
      <wsrm:Sequence>
         <wsrm:Identifier>http://webservices.gama-system.com/RM/Service</wsrm:Identifier>
         <wsrm:MessageNumber>2</wsrm:MessageNumber>
      </wsrm:Sequence>
   </S:Header>
   ...
   <S:Body>
      ...
   </S:Body>
</S:Envelope>

After all messages have been exchanged and acknowledged, the RM destination sends a <SequenceAcknowledgement> inside the body of the message. RM source (communication initiator) then tears down the sequence with a <TerminateSequence> message.

So, how can this specification be implemented in various technology stacks? Well, WCF implements reliable messaging using the in-memory message buffers. There is no durable reliable messaging support in WCF.

Here's how it works:

  • Communication initiator (client) sends a <CreateSequence> message.
  • Service side responds with a <CreateSequenceResponse>.
  • Client sends 1..n messages and buffers them, while waiting for all acknowledgements.
  • Service side can and will dispatch the received messages as soon as possible. Now, there are two options:
    • Communication is configured for ordered delivery
      First message will be dispatched to the service model as soon as it arrives, noting that it has been processed. Every other message is processed in order. If message number 5 has been processed and the next received message carries sequence number 7, it will not be dispatched until message 6 is received and processed by the service model.
    • Communication allows out-of-order delivery
      First message will be dispatched to the service model as soon as it arrives, so will all the following messages. Since we did not demand ordered delivery the processing pipeline does not care on when to process the messages. It will process them as soon as they are received. They are acknowledged as soon as possible, but not before acknowledgement interval.
  • Service side sends a <SequenceAcknowledgement> message only when all messages have been acknowledged.
  • Initiator then stops the sequence with a <TerminateSequence> message.

So, how do we go about enabling WS-RM and realizable delivery in WCF? Simple. Here's the config file:

<wsHttpBinding>
   <binding configurationName="myReliableBinding">
      <reliableSession enabled="true" ordered="true" />
   </binding>
</wsHttpBinding>

The <reliableSession> element has two attributes. The first one, enabled, enables reliable message delivery. The second one, ordered, enables in-order processing by the service model.

One has to acknowledge that the following is true for different WCF bindings:

basicHttpBinding - RM not supported
wsHttpBinding - RM supported, not default
wsDualHttpBinding - RM implicit
netTcpBinding - RM supported, not default

There are a couple of options available for anyone using the custom binding, in regard to reliable messaging behavior:

  1. acknowledgementInterval specifies the time lapse duration of message acknowledgement. The default is two seconds, while always acknowledging the first message. This gives you an efficient way to group the acknowledgement messages, thus conserving network traffic.
  2. flowControlEnabled enables message sender to acknowledge the receive buffer on the recipient side. It turns out that every acknowledgement message includes a service buffer status and if this attribute is set, sender will not send messages if the recipient buffer is full, thus not occupying network resources.
  3. inactivityTimeout defines the absolute duration of a no-message (infrastructure and application messages) session. After the timeout, the session is torn down.
  4. maxPendingChannels defines how many reliable channels the service can put in its waiting-to-open queue. If there's a significant load, the pending requests can queue up and the service refuses to open a reliable session (think <CreateSequenceRefused>).
  5. maxRetryCount defaults to 8. It defines how many times the infrastructure retries with message delivery. If the limit is achieved, the channel will become faulted.
  6. maxTransferWindowSize defines how many messages should be buffered. On service side all messages that have not been acknowledged increase the count. On the client side, all messages which have not received their acknowledgement pair are counted.
  7. ordered defines in-order delivery. It's values are true and false.

There is some confusion in the wsHttpBinding's <reliableSession> config element. There's an enabled property in the Visual Studio config schema, which should not have any influence on reliable session establishment (and does not have a matching object model method/property). It does, however. There is a difference if you setup a reliable session by using a customBinding or wsHttpBinding.

I.e., here's the custom binding config:

<customHttpBinding>
   <binding configurationName="customReliableBinding">
      <reliableSession ordered="true" />
   </binding>
</customBinding>

This will enable reliable and ordered session support in any custom binding.

So, in general - WCF implementation of WS-ReliableMessaging gives you automatic message retries, duplicate detection, and ordering. It should be turned on for any multi-hop message paths, but can be very valuable even in high latency/packet loss network scenarios.

Update 2007-02-19

William Tay, a friend and distributed systems expert, replies with a terrific message exchange pattern for groking WS-RM specification. Don't walk, run.

Categories:  .NET 3.0 - WCF | Architecture
Sunday, 18 February 2007 21:24:28 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

 .NET 3.0 Middleware Technologies Day: Third Incarnation 

Third incarnation of the .NET 3.0 Middleware Technologies day went through yesterday.

Here are the deliverables:

If you did not get/notice the printed articles, here's what should put you to sleep over the weekend:

Also, the accompanying book is available here.

[1] Only available in Slovene.

Thursday, 15 February 2007 06:09:56 (Central Europe Standard Time, UTC+01:00)  #    Comments

 

Copyright © 2003-2024 , Matevž Gačnik
Recent Posts
RD / MVP
Feeds
RSS: Atom:
Archives
Categories
Blogroll
Legal

The opinions expressed herein are my own personal opinions and do not represent my company's view in any way.

My views often change.

This blog is just a collection of bytes.

Copyright © 2003-2024
Matevž Gačnik

Send mail to the author(s) E-mail