WCF – Cross-machine semaphore with WCF

Came across an interesting question on StackOverflow on how one might be able to throttle the number of requests across multiple servers running the same WCF service. So for instance, if you have 3 servers sitting behind a load balancer and for one reason or another you can only allow 5 requests to be made against the service at any moment in time and any subsequent requests need to be queued until one of the previous requests finish.

For those of you familiar with the programming concept of a semaphore, you might see that the above requirement describes a semaphore which applies across multiple machines. A quick search on Google for ‘cross-machine semaphore’ reveals several implementations of such system using memcached.

Naturally, a distributed cache is a good way to go about implementing a cross-machine semaphore IF you are already using it for something else. Otherwise the overhead and cost of running a distributed cache cluster purely for the sake of a cross-machine semaphore makes this approach a no-go for most of us..

Instead, you could easily implement a semaphore service to provide the same functionality to multiple WCF clients as the bog-standard Semaphore class do to multiple threads. Such a service might look something like this:

[ServiceContract]
public interface ISemaphorService
{
    [OperationContract]
    void Acquire();

    [OperationContract]
    void Release();
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class SemaphoreService
{
    private readonly static Semaphore Pool = new Semaphore(5, 5);

    public void Acquire()
    {
        Pool.WaitOne();
    }

    public void Release()
    {
        Pool.Release();
    }
}

This approach will introduce a single point of failure as for semaphore service to work correctly it’ll need to be running on a single machine. If you were to use this approach you should have build up some infrastructure around it so that you can recover swiftly if and when the server running the semaphore service goes down.

In terms of the client code you should make sure that Release is called for every Acquire call, so would be a good idea to put a try-finally block around it:

var client = new SemaphoreServiceClient();

try
{
    // acquire the semaphore before processing the request
    client.Acquire();

    // process request
    ...
}
finally
{
    // always remember the release the semaphore
    client.Release();
}

WCF – Be ware of the field ordering when using DataContractSerializer

One of the less known aspect of the DataContractSerializer is its dependency on the order in which fields are serialized and deserialized.

As this article points out, the basic rules for ordering include:

  • If a data contract type is a part of an inheritance hierarchy, data members of its base types are always first in the order.
  • Next in order are the current type’s data members that do not have the Order property of the DataMemberAttribute attribute set, in alphabetical order.
  • Next are any data members that have the Order property of the DataMemberAttribute attribute set. These are ordered by the value of the Order property first and then alphabetically if there is more than one member of a certain Order value. Order values may be skipped.

The problem is that when the inbound data is not ordered accordingly the fields which are ‘out of order’ will not be deserialized as highlighted by this StackOverflow question. Though this is unlikely to happen as the serializer will take care of the correct ordering for you, unless like jhersh you are attempting to manually create some data for test purposes.

Parting Thoughts…

Seeing as the DataContractSerializer is also dependent on the ordering of the fields in the serialized type (albeit not transparent to you and well taken care of almost all the time) I have long been tempted to try out the Protocol Buffers wrapper for .Net which are meant to be much faster and more compact because it doesn’t serialize the names of the properties unlike the DataContractSerializer.

For those of you who aren’t aware of it, protocol buffers is the binary serialization used by Google for most of its data communications. In order to use the protobuf-net serialization you need to explicitly specify the order in which your properties should be serialized:

[DataContract]
public sealed class Test1
{
    [DataMember(Name="a", Order=1, IsRequired=true)]
    public int A { get; set; }
}

[DataContract]
public sealed class Test2
{
    [DataMember(Name = "b", Order = 2, IsRequired = true)]
    public string B { get; set; }
}

[DataContract]
public sealed class Test3
{
    [DataMember(Name = "c", Order = 3, IsRequired = true)]
    public Test1 C { get; set; }
}

And inject a new behaviour to the WCFmethod to use the new serializer:

[ServiceContract]
public interface IFoo
{
    [OperationContract, ProtoBehavior]
    Test3 Bar(Test1 value);
}

Oh, such temptation…

References:

StackOverflow question – WCF data contract, some fields do not serialize

MSDN – Data member order

protobuf-net – Is it quick?

WCF – Data Contract version round-tripping using IExtensibleDataObject

With WCF, provided that you’re using the DataContractSerializer and not the NetDataContractSerializer, you have a certain degree of protection against data contract changes from the client’s perspective.

Existing contracts will still work if existing members are not removed from the data contract, which means you are free to add new members to the data contract on the server side without affecting existing clients. This gives you some backward compatibility and allows you to incrementally evolve your data contracts in a non-breaking way.

Round-Tripping

Round-tripping occurs when data passes from a new version to an old version and back to the new version of a data contract. Round-tripping guarantees that no data is lost. Enabling round-tripping makes the type forward-compatible with any future changes supported by the data contract versioning model.

To enable round-tripping your type must implement the IExtensibleDataContract interface and add the ExtensionData property of ExtensionDataObject type (see the MSDN article in the References section for an example).

It’s worth noting that the data stored in the ExtensionData property is not public retrievable and is only used by the WCF infrastructure.

And finally, to turn it off:

The round-tripping feature may be turned off, either by setting ignoreExtensionDataObject to true in the DataContractSerializer constructor or by setting theIgnoreExtensionDataObject property to true on the ServiceBehaviorAttribute. When this feature is off, the deserializer will not populate the ExtensionData property, and the serializer will not emit the contents of the property.

References:

MSDN article on Forward-Compatible Data Contracts

MSDN article on Best Practices on WCF Data Contract Versioning

MSDN – WCF Guildelines and Best Practices

WCF – Using the NetDataContractSerializer to share your type

DataContractSerializer

For those of your who are familiar with WCF you would no doubt know about the DataContractSerializer class, the DataContractSerializer does not include the CLR type information in the serialized XML, which allows for loose coupling between the client and server because they don’t have to share the same CLR types.

However, this also means you often have to re-create the same types on the client, though Visual Studio handles most of this for you when you add a new service reference to your project. However, rather than deserializing the original type, messages are deserialized into a new, but identical CLR type on the client.

NetDataContractSerializer

Whilst DataContractSerializer is used by WCF by default, there is another serializer which you can use if you wish to share the same CLR types between the client and server – the NetDataContractSerializer. The NetDataContractSerializer differs from the DataContractSerializer in that it includes the CLR type information in the serialized XML and can only be used if the same CLR types are serialized and deserialized at both ends.

You can use the NetDataContractSerializer on any type which are marked with the DataContractAttribute or SerializableAttribute, or types that implement the ISerializable interface.

UseNetDataContractSerializerAttribute

Here’s the attribute you need to replace the default DataContractSerializer with the NetDataContractSerializer, taken from Tim Scott’s blog post here:

public class NetDataContractOperationBehavior : DataContractSerializerOperationBehavior
{
    public NetDataContractOperationBehavior(OperationDescription operation) : base(operation)
    {
    }

    public NetDataContractOperationBehavior(
                OperationDescription operation,
                DataContractFormatAttribute dataContractFormatAttribute)
            : base(operation, dataContractFormatAttribute)
    {
    }

    public override XmlObjectSerializer CreateSerializer(
                Type type, string name, string ns, IList knownTypes)
    {
        return new NetDataContractSerializer(name, ns);
    }

    public override XmlObjectSerializer CreateSerializer(
                Type type, XmlDictionaryString name, XmlDictionaryString ns,
                IList knownTypes)
    {
        return new NetDataContractSerializer(name, ns);
    }
}

public class UseNetDataContractSerializerAttribute : Attribute, IOperationBehavior
{
    public void AddBindingParameters(OperationDescription description,
                                     BindingParameterCollection parameters)</pre>
{
}

public void ApplyClientBehavior(OperationDescription description,
System.ServiceModel.Dispatcher.ClientOperation proxy)
{
ReplaceDataContractSerializerOperationBehavior(description);
}

public void ApplyDispatchBehavior(OperationDescription description,
System.ServiceModel.Dispatcher.DispatchOperation dispatch)
{
ReplaceDataContractSerializerOperationBehavior(description);
}

public void Validate(OperationDescription description)
{
}

private static void ReplaceDataContractSerializerOperationBehavior(
OperationDescription description)
{
DataContractSerializerOperationBehavior dcsOperationBehavior =
description.Behaviors.Find();

if (dcsOperationBehavior != null)
{
description.Behaviors.Remove(dcsOperationBehavior);
description.Behaviors.Add(new NetDataContractOperationBehavior(description));
}
}
}

To use it, you can add it to a service method defined in the contract:

[OperationContract]
[UseNetDataContractSerializer]
Company SaveCompany(CompanyUpdater companyUpdater);

.Net Tips – Use Request and Response objects

We’ve all been there before, write a simple service with a simple method:

[ServiceContract]
public interface IService
{
    [OperationContract]
    int SimpleMethod(object param1);
}

As time goes by, the simple method gets more complicated, and the list of parameters grows and eventually simple method is overloaded to provide more variety and simple method is simple no more!

A simple solution to this is the Request-Response pattern, by encapsulating all the input and output values into request and response objects you will be able to:

  • solve the problem with growing parameters
  • have an easy way of providing multiple results
  • add input/output values incrementally

And you’ll be able to do all this without even changing the service contract!

[ServiceContract]
public interface IService
{
    [OperationContract]
    SimpleMethodResponse SimpleMethod(SimpleMethodRequest request);
}

[DataContract]
public void SimpleMethodRequest
{
    [DataMember]
    public object Param1 { get; set; }

    [DataMember]
    public string Param2 { get; set; }

    [DataMember]
    public int Param3 { get; set; }

    …
}

[DataContract]
public void SimpleMethodResponse
{
    [DataMember]
    public bool Success { get; set; }

    [DataMember]
    public int? ErrorCode { get; set; }

    [DataMember]
    public string ErrorMessage { get; set; }

    …
}

In addition, you can also create a hierarchy of request/response objects and consolidate your validation logic in validator classes or custom validation attractions (you can use PostSharp to write attributes that take care of the validation ‘aspect’ of your application).

References:

API Design Patterns – Request/Response