Zulfiqar's weblog

Architecture, security & random .Net

Archive for June, 2008

SOAP message size optimization: Encoding vs compression

Posted by zamd on June 18, 2008

Sometimes there is a requirement to reduce the size of the messages sent between client and service. Encoder is a WCF component which transforms a SOAP message (Infoset) into a byte stream and vice versa. Kenny has written about the different encoders available in WCF and I highly recommend reading his post.

His post is focused on the performance characteristics of various encoders for various types of messages (with or without binary data).  Here I will talk about other aspect of the encoders. i.e size of the encoded byte stream.

Usually there are few requirements which derive your message size optimization options.

  1. Whether you own both side of communication (client & service) or not?
  2.  Do you require XML(Infoset) representation on the wire?
  3. Deployment options

 Let’s talk about various options in the light of above requirements.

If you own both sides then the recommendation is to use binary encoding which is the default encoding with NetTcpBinding & NetNamedPipeBinding. The XML structure on the wire will not preserved with this encoding however you will get huge savings in message size without writing any additional code.

If byte stream produced by binary encoding still doesn’t meet your bandwidth constraint then you can think of applying compression on this byte stream. There is a compression encoder available as part of WCF samples which you can use as a base to write your own compression encoder. Again this is only useful if wire format is not important to you. 

If you have a scenario in which message flows through intermediaries (e.g IBM DataPower) and certain policies are applied on the message (based on SOAP headers) then above options will not work. In these scenarios you can devise a scheme to only compress SOAP body and replace the actual body with compressed string (quite similar to XML encryption & Digital Signature) while preserving SOAP headers. Pablo has created a protocol (WS-Compression) to achieve this exact requirement. His sample is not updated to the latest version of WCF but you can get the idea by looking at the code. Also you can achieve this same functionality by extending WCF service model layer. For example, by writing a message inspector and doing compression there. 

I did a quick test of various encoding and compression choices and here are my findings. In my tests I have used a large dataset, consisting of 91 customer records, each having 1-20 orders and each order consist of 5-10 products.  

cid:image002.png@01C8D13A.DE114040

Encoding

Size

Bytes

Kb

Standard Text Encoding

1318179

1288

Standard Binary Encoding

259141

253

Gzip Compression using the compressing encoder        

131242

128

Gzip Compression using a custom compression channel

103428

101

 

 

 

 

 

As you can see there is huge size difference between text and binary encoding of xml messages. Note that in my testing there wasn’t any binary data in SOAP messages at all. If there would be some binary data then text encoded messages would be even bigger because of base64 encoding of binary data. So with binary encoding you can save lot of bandwidth without doing any custom coding and that’s why this should be the first choice.

In addition to using a compression encoder you can also use IIS compression if you are hosting in IIS or WPAS (Windows Server 2008). IIS compression is pretty much similar to compression encoder option with the only different that in the former case compression is done by IIS while in later case it is done by a WCF encoder. IIS compression has the disadvantage that you need to configure compression separate to your WCF configuration (IIS metabase).  Using a compression encoder or a custom compression channel also enables you to use a compression algorithm of your choice (based on your compression requirement) while IIS limits you to GZip compression only. In conclusion, the need for xml structure on the wire will be the deciding factor on what option will best suit you.

Posted in WCF | Leave a Comment »

Setting UserName ClientCredentials in WF SendActivity

Posted by zamd on June 2, 2008

I was recently asked if there is a way to set custom UserName credentials in a SendActivity. I did some investigation and couldn’t find any OOB way do achieve this. So the next step was to look into WCF’s awesome extensibility mechanism **Bahaviors**. Turns out you can achieve this functionality quite easily by writing a custom endpoint behavior.

Step 1 would be to create a custom endpoint behavior:

public class UserNameBehavior : IEndpointBehavior

{

    #region IEndpointBehavior Members

    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)

    {}

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)

    {

        var cc = endpoint.Behaviors.Find<ClientCredentials>();

        cc.UserName.UserName = “zahmed”;

        cc.UserName.Password = “password”;

    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)

    {}

    public void Validate(ServiceEndpoint endpoint)

    {}

    #endregion

}

In the ApplyClientBehavior method, find the appropriate behavior object and override its properties to your desired values. Now you have to specify this behavior in the endpoint configuration of the SendActivity.

To use your custom behavior from config you have to create a BehaviorElementExtension(Step 2)

    public class UserNameBehaviorElement : BehaviorExtensionElement

    {

        protected override object CreateBehavior()

        {

            return new UserNameBehavior();

        }

        public override Type BehaviorType

        {

            get { return typeof(UserNameBehavior); }

        }

    }

Step 3 would be to register your behavior as an extension in the config file:

<extensions>

  <behaviorExtensions>

    <add name=userName type=WorkflowConsoleApplication1.UserNameBehaviorElement, WorkflowConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null/>

  </behaviorExtensions>

</extensions>

At this point your custom behavior is ready to be used in the endpoint configuration used by the SendActivity. Here is the complete config file.

<configuration>

  <system.serviceModel>

    <bindings>

      <basicHttpBinding>

        <binding name=BasicHttpBinding ICalcultor>

          <security mode=Transport>

            <transport clientCredentialType=Basic />

          </security>

        </binding>

      </basicHttpBinding>

    </bindings>

    <client>

      <endpoint address=https://localhost:7000/Calc binding=basicHttpBinding

          bindingConfiguration=BasicHttpBinding ICalcultor contract=ServiceReference1.ICalcultor

          name=BasicHttpBinding ICalcultor behaviorConfiguration=userNameBehavior />

    </client>

    <behaviors>

      <endpointBehaviors>

        <behavior name=userNameBehavior>

          <userName/>

        </behavior>

      </endpointBehaviors>

    </behaviors>

    <extensions>

      <behaviorExtensions>

        <add name=userName type=WorkflowConsoleApplication1.UserNameBehaviorElement, WorkflowConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null/>

      </behaviorExtensions>

    </extensions>

  </system.serviceModel>

</configuration>

Posted in WF | 2 Comments »

 
Follow

Get every new post delivered to your Inbox.