Came across an inter­est­ing ques­tion on Stack­Over­flow on how one might be able to throt­tle the num­ber of requests across mul­ti­ple servers run­ning the same WCF ser­vice. So for instance, if you have 3 servers sit­ting behind a load bal­ancer and for one rea­son or another you can only allow 5 requests to be made against the ser­vice at any moment in time and any sub­se­quent requests need to be queued until one of the pre­vi­ous requests finish.

For those of you famil­iar with the pro­gram­ming con­cept of a sem­a­phore, you might see that the above require­ment describes a sem­a­phore which applies across mul­ti­ple machines. A quick search on Google for ‘cross-machine sem­a­phore’ reveals sev­eral imple­men­ta­tions of such sys­tem using memcached.

Nat­u­rally, a dis­trib­uted cache is a good way to go about imple­ment­ing a cross-machine sem­a­phore IF you are already using it for some­thing else. Oth­er­wise the over­head and cost of run­ning a dis­trib­uted cache clus­ter purely for the sake of a cross-machine sem­a­phore makes this approach a no-go for most of us..

Instead, you could eas­ily imple­ment a sem­a­phore ser­vice to pro­vide the same func­tion­al­ity to mul­ti­ple WCF clients as the bog-standard Sem­a­phore class do to mul­ti­ple threads. Such a ser­vice might look some­thing 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 intro­duce a sin­gle point of fail­ure as for sem­a­phore ser­vice to work cor­rectly it’ll need to be run­ning on a sin­gle machine. If you were to use this approach you should have build up some infra­struc­ture around it so that you can recover swiftly if and when the server run­ning the sem­a­phore ser­vice 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();
}
Share

One of the less known aspect of the Dat­a­Con­tract­Se­ri­al­izer is its depen­dency on the order in which fields are seri­al­ized and deserialized.

As this arti­cle points out, the basic rules for order­ing include:

  • If a data con­tract type is a part of an inher­i­tance hier­ar­chy, data mem­bers of its base types are always first in the order.
  • Next in order are the cur­rent type’s data mem­bers that do not have the Order prop­erty of the DataMem­ber­At­tribute attribute set, in alpha­bet­i­cal order.
  • Next are any data mem­bers that have the Order prop­erty of the DataMem­ber­At­tribute attribute set. These are ordered by the value of the Order prop­erty first and then alpha­bet­i­cally if there is more than one mem­ber of a cer­tain Order value. Order val­ues may be skipped.

The prob­lem is that when the inbound data is not ordered accord­ingly the fields which are ‘out of order’ will not be dese­ri­al­ized as high­lighted by this Stack­Over­flow ques­tion. Though this is unlikely to hap­pen as the seri­al­izer will take care of the cor­rect order­ing for you, unless like jhersh you are attempt­ing to man­u­ally cre­ate some data for test purposes.

Part­ing Thoughts…

See­ing as the Dat­a­Con­tract­Se­ri­al­izer is also depen­dent on the order­ing of the fields in the seri­al­ized type (albeit not trans­par­ent to you and well taken care of almost all the time) I have long been tempted to try out the Pro­to­col Buffers wrap­per for .Net which are meant to be much faster and more com­pact because it doesn’t seri­al­ize the names of the prop­er­ties unlike the DataContractSerializer.

For those of you who aren’t aware of it, pro­to­col buffers is the binary seri­al­iza­tion used by Google for most of its data com­mu­ni­ca­tions. In order to use the protobuf-net seri­al­iza­tion you need to explic­itly spec­ify the order in which your prop­er­ties 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 behav­iour to the WCFmethod to use the new serializer:

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

Oh, such temptation…

Ref­er­ences:

Stack­Over­flow ques­tion – WCF data con­tract, some fields do not serialize

MSDN – Data mem­ber order

protobuf-net — Is it quick?

Share

With WCF, pro­vided that you’re using the Dat­a­Con­tract­Se­ri­al­izer and not the Net­Dat­a­Con­tract­Se­ri­al­izer, you have a cer­tain degree of pro­tec­tion against data con­tract changes from the client’s perspective.

Exist­ing con­tracts will still work if exist­ing mem­bers are not removed from the data con­tract, which means you are free to add new mem­bers to the data con­tract on the server side with­out affect­ing exist­ing clients. This gives you some back­ward com­pat­i­bil­ity and allows you to incre­men­tally evolve your data con­tracts in a non-breaking way.

Round-Tripping

Round-tripping occurs when data passes from a new ver­sion to an old ver­sion and back to the new ver­sion of a data con­tract. Round-tripping guar­an­tees that no data is lost. Enabling round-tripping makes the type forward-compatible with any future changes sup­ported by the data con­tract ver­sion­ing model.

To enable round-tripping your type must imple­ment the IEx­ten­si­ble­Dat­a­Con­tract inter­face and add the Exten­sion­Data prop­erty of Exten­sion­DataOb­ject type (see the MSDN arti­cle in the Ref­er­ences sec­tion for an example).

It’s worth not­ing that the data stored in the Exten­sion­Data prop­erty is not pub­lic retriev­able and is only used by the WCF infrastructure.

And finally, to turn it off:

The round-tripping fea­ture may be turned off, either by set­ting ignore­Ex­ten­sion­DataOb­ject to true in the Dat­a­Con­tract­Se­ri­al­izer con­struc­tor or by set­ting theIgnore­Ex­ten­sion­DataOb­ject prop­erty to true on the Ser­vice­Be­hav­iorAt­tribute. When this fea­ture is off, the dese­ri­al­izer will not pop­u­late the Exten­sion­Data prop­erty, and the seri­al­izer will not emit the con­tents of the property.

Ref­er­ences:

MSDN arti­cle on Forward-Compatible Data Contracts

MSDN arti­cle on Best Prac­tices on WCF Data Con­tract Versioning

MSDNWCF Guilde­lines and Best Practices

Share

Dat­a­Con­tract­Se­ri­al­izer

For those of your who are famil­iar with WCF you would no doubt know about the Dat­a­Con­tract­Se­ri­al­izer class, the Dat­a­Con­tract­Se­ri­al­izer does not include the CLR type infor­ma­tion in the seri­al­ized XML, which allows for loose cou­pling between the client and server because they don’t have to share the same CLR types.

How­ever, this also means you often have to re-create the same types on the client, though Visual Stu­dio han­dles most of this for you when you add a new ser­vice ref­er­ence to your project. How­ever, rather than dese­ri­al­iz­ing the orig­i­nal type, mes­sages are dese­ri­al­ized into a new, but iden­ti­cal CLR type on the client.

Net­Dat­a­Con­tract­Se­ri­al­izer

Whilst Dat­a­Con­tract­Se­ri­al­izer is used by WCF by default, there is another seri­al­izer which you can use if you wish to share the same CLR types between the client and server – the Net­Dat­a­Con­tract­Se­ri­al­izer. The Net­Dat­a­Con­tract­Se­ri­al­izer dif­fers from the Dat­a­Con­tract­Se­ri­al­izer in that it includes the CLR type infor­ma­tion in the seri­al­ized XML and can only be used if the same CLR types are seri­al­ized and dese­ri­al­ized at both ends.

You can use the Net­Dat­a­Con­tract­Se­ri­al­izer on any type which are marked with the Dat­a­Con­trac­tAt­tribute or Seri­al­iz­ableAt­tribute, or types that imple­ment the ISe­ri­al­iz­able interface.

UseNet­Dat­a­Con­tract­Se­ri­al­iz­er­At­tribute

Here’s the attribute you need to replace the default Dat­a­Con­tract­Se­ri­al­izer with the Net­Dat­a­Con­tract­Se­ri­al­izer, 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<Type> knownTypes)
    {
        return new NetDataContractSerializer(name, ns);
    }

    public override XmlObjectSerializer CreateSerializer(
                Type type, XmlDictionaryString name, XmlDictionaryString ns,
                IList<Type> 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<DataContractSerializerOperationBehavior>();

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

To use it, you can add it to a ser­vice method defined in the contract:

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

We’ve all been there before, write a sim­ple ser­vice with a sim­ple method:

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

As time goes by, the sim­ple method gets more com­pli­cated, and the list of para­me­ters grows and even­tu­ally sim­ple method is over­loaded to pro­vide more vari­ety and sim­ple method is sim­ple no more!

A sim­ple solu­tion to this is the Request-Response pat­tern, by encap­su­lat­ing all the input and out­put val­ues into request and response objects you will be able to:

  • solve the prob­lem with grow­ing parameters
  • have an easy way of pro­vid­ing mul­ti­ple results
  • add input/output val­ues incrementally

And you’ll be able to do all this with­out even chang­ing the ser­vice 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 addi­tion, you can also cre­ate a hier­ar­chy of request/response objects and con­sol­i­date your val­i­da­tion logic in val­ida­tor classes or cus­tom val­i­da­tion attrac­tions (you can use Post­Sharp to write attrib­utes that take care of the val­i­da­tion ‘aspect’ of your application).

Ref­er­ences:

API Design Pat­terns – Request/Response

Share