Archive for January, 2009

Extensible Objects in WCF

Posted: January 26, 2009 in WCF
Tags: ,

While exploring the instance context initializer and call context initializer in WCF I came across the extensible objects in WCF.This extensible object pattern is used for extending the runtime behavior of the existing classes or to add custom state information.In this pattern we have an object which wants to provide facility to extend it’s behavior using other custom objects.So this object is an Extensible Object.The custom objects extending the behaviors are Extensions.This is what is modelled using the three interfaces.

  • IExtensibleObject <T> where T is the extensible class.This interface enables an object to provide extension point for custom functionality.This interface has only one readonly property:
    • IExtensionCollection<T> Extensions { get; }
  • IExtension<T> where T is a type of IExtensibleObject<T>.It enables to extend an object of type IExtensibleObject through aggregation.This interface defines two methods:
    • Attach – Enables an extension object to find out when it has been aggregated.This is called when an extension object is added to the IExtensibleObject<T>.Extensions collection
    • Detach – Enables an extension object to find out when it is no longer aggregated.This is called when an extension object is removed from the IExtensibleObject<T>.Extensions collection
  • IExtensionCollection<T> where T is an IExtension object.

In WCF classes following classes provide extension points by implementing the IExtensibleObject interface.

  • System.ServiceModel.ServiceHostBase
  • System.ServiceModel.InstanceContext
  • System.ServiceModel.OperationContext
  • System.ServiceModel.IContextChannel

in my next post while discussing about context initializers I will use extensible object in the examples.But this pattern can be used outside WCF as well.This is explained by a nice example in Prajeesh’s blog.

http://blogsprajeesh.blogspot.com/2008/10/using-extensible-object-pattern-to.html

In my earlier post I explained the different types of behaviors available in the WCF framework.In this post we will discuss about how to develop a custom operation invoker.Now the obvious question is what is an operation invoker.Operation invoker is the class responsible invoking the service method with a set of parameters and generate the output parameters and return value.The class responsible for this needs to implement the System.ServiceModel.Dispatcher.IOperationInvoker interface.This interface defines the following methods

  1. AllocateInputs – Returns an array of parameters required for the method call.
  2. Invoke – This method accepts the instance of the service object,array of parameter values ,array of output values as a parameters and returns the value returned by the service method.
  3. InvokeBegin – This is the asynchronous version of the Invoke method and initiates the call.
  4. InvokeEnd – This is the asynchronous version of the Invoke method and it completes the call.

Operation invoker is attached to the System.ServiceModel.DispatchOperation via the Invoker property.The default invoker provided by WCF framework for synchronous method call is System.ServiceModel.Dispatcher.SyncMethodInvoker.The custom invoker we are going to develop will be added to the DispatchOperation via Invoker property.

This custom invoker will provide a caching functionality.It will check that for a given set of parameters if output and return value exists in cache then it will use the cached values otherwise invoke the method and add results to cache.As a first step we will develop a class implementing IOperationBehavior and it will also wrap the instance of the default operation as shown below:

    public class CacheOperationInvoker:IOperationInvoker
    {
        /// <summary>
        /// This variable keeps a reference to the IOperationInvoker instance of DispatchOperation.
        /// </summary>
        private IOperationInvoker invoker;
        public CacheOperationInvoker(IOperationInvoker invoker)
        {
            this.invoker = invoker;
        }

    …………………
    }

We will now implement the logic to check from cache in the Invoke method as shown below:

public object Invoke(object instance, object[] inputs, out object[] outputs)
{

    //Generate Key method generates the key for cache store by concatenating the input params.
     string key = GenerateKey(inputs);

    //CacheOutput is a custom C# class that encapsulates the output parameter array and return value
     CacheOutput  item = null;
     object retval = null;
     outputs = null;
     if (!string.IsNullOrEmpty(key))
     {

        //Get from Cache
         item = CacheManager.GetItemFromCache(key) as CacheOutput ;
         if (item != null)
         {

            //return from Cache
             retval = item.ReturnValue;
             outputs = item.Outputs;
         }
         else
         {

            //Invoke the method using default invoker instance and set values in cache.
             retval = invoker.Invoke(instance, inputs, out outputs);
             item = new CacheOutput();
             item.Outputs = outputs;
             item.ReturnValue = retval;
             CacheManager.SetItemInCache(key, item);
         }
     }
     return retval;
}

Now we add a operation behavior and add our invoker to DispatchOperation as shown below:

public class CacheOperationBehavior:Attribute,IOperationBehavior
  {

      public void ApplyDispatchBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
      {
          //Get the instance of the default invoker
          IOperationInvoker invoker = dispatchOperation.Invoker;
          //Override with cache based invoker
          dispatchOperation.Invoker = new CacheOperationInvoker(invoker);
      }

  }

Finally the behavior can be added to the service as shown below:

[ServiceContract]
    public interface ICalculator
    {
        [OperationContract]
        [CacheOperationBehavior]
        int Add(int i, int j);
    }

The entire sample code can be found at:

http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=wcfsamples&DownloadId=4496

WCF Behavior

Posted: January 4, 2009 in Uncategorized, WCF
Tags: ,

I ended my last post on WCF Dispatcher extension points with the note that we need WCF behavior to attach the components extending WCF functionality to the runtime.In this post I will describe the various WCF behaviors and how they can be plugged into the WCF runtime.

There are 4 types of behaviors in WCF : Service ,Endpoint,Operation and Contract ,each with a different scope of effect.To create each of this behavior we need to implement a separate interface having the same methods with similar intentions but with different parameters.The purpose of these methods is described below:

  1. AddBindingParameters – This method is used to pass custom information to the binding.
  2. Validate – This method is used to validate the service description.
  3. ApplyDispatchBehavior/ApplyClientBehavior – This method is used to add the extension components to DispatchRuntime/ClientRuntime e.g. MessageInspector,ParameterInspectors etc.

The WCF behaviors can be added to the runtime using the following ways:

  • Programmatically – This I will discuss in details with the individual types of behavior
  • Attributes – In this case the behavior class needs to implement the corresponding behavior interface and extend the attribute class.Then that attribute needs to be applied to the service class implementing the ServiceContract as shown below:

         public class ServicePoolBehavior : Attribute,IServiceBehavior
         {
             …..
         }

          [ServiceContract]

          public interface ITest
          {
             …..
          }
         [ServicePoolBehavior(MaxPoolSize=10,MinPoolSize=2,IncrementSize=2)]

         public class Test:ITest
         {
            ……
         }

  • Configuration – Here we need to implement a custom behavior extension element by extending the System.ServiceModel.BehaviorExtensionElement class and then add the new behavior in the config as shown below:

         public class ServicePoolBehaviorExtensionElement:BehaviorExtensionElement
        {
          ………..

          …………..

          public override Type BehaviorType
           {
              get { return  typeof(ServicePoolBehavior); }
           }

           protected override object CreateBehavior()
           {
              ServicePoolBehavior behavior = new ServicePoolBehavior();
              behavior.MaxPoolSize = Convert.ToInt32( this.ElementInformation.Properties[“maxPoolSize”].Value);
              behavior.MinPoolSize = Convert.ToInt32( this.ElementInformation.Properties[“minPoolSize”].Value);
              behavior.IncrementSize =Convert.ToInt32( this.ElementInformation.Properties[“incrementSize”].Value);
              return behavior;
          }
      }

      <extensions>
            <behaviorExtensions>
                <add name=”poolBehavior” type=”SB.ServiceModel.Pool.ServicePoolBehaviorExtensionElement, SB.ServiceModel.Pool, Version=1.0.0.0,  Culture=neutral, PublicKeyToken=null” />
            </behaviorExtensions>
        </extensions>
        <behaviors>
            <serviceBehaviors>
                <behavior name=”testBehavior”>
                    <serviceDebug includeExceptionDetailInFaults=”true” />
                    <serviceMetadata httpGetEnabled=”true” httpGetUrl=”
http://localhost:9001/Meta” />
                    <poolBehavior minPoolSize=”2″ maxPoolSize=”10″ incrementSize=”2″/>
                </behavior>
            </serviceBehaviors>
        </behaviors>

Now we will discuss about the individual types of behaviors:

  • ServiceBehavior
    • Need to implement the System.ServiceModel.Description.IServiceBehavior interface.
    • This behavior applies for the entire service runtime including the ServiceHostBase.
    • This behavior can be added by attribute,configuration or code.The following snippet shows how we can add a service behavior programmatically:

                    using (ServiceHost host = new ServiceHost(typeof(SampleService.Test)))
                    {

                       SB.ServiceModel.Pool.ServicePoolBehavior behavior = new SB.ServiceModel.Pool.ServicePoolBehavior();
                       behavior.IncrementSize = 2;
                       behavior.MaxPoolSize = 10;
                       behavior.MinPoolSize = 2;
                       host.Description.Behaviors.Add(behavior);

                       …….

                  }

  • EndpointBehavior
    • Need to implement the System.ServiceModel.Description.IEndpointBehavior interface.
    • This behavior customizes the runtime of a particular endpoint and associated EndpointDispatcher object.
    • This behavior can be added by configuration or code.The following snippet shows how we can add a endpoint behavior programmatically:

                    foreach (ServiceEndpoint se in host.Description.Endpoints) se.Behaviors.Add(new CustomBehavior());

  • ContractBehavior
    • Need to implement the System.ServiceModel.Description.IContractBehavior interface.
    • This behavior customizes the runtime of a particular contract and associated DispatchRuntime/ClientRuntime object.
    • This behavior can be added by attribute or code.The following snippet shows how we can add a contract behavior programmatically:

                   foreach (ServiceEndpoint se in host.Description.Endpoints)
                   {
                        se.Contract.Behaviors.Add(new CustomBehavior);
                    }

  • OperationBehavior
    • Need to implement the System.ServiceModel.Description.IOperationBehavior interface.
    • This behavior customizes the runtime of a particular operation and associated DispatchOperation/ClientOperation object.
    • This behavior can be added by attribute or code.The following snippet shows how we can add a operation behavior programmatically:

                    foreach (ServiceEndpoint se in host.Description.Endpoints)
                    {
                          foreach (OperationDescription od in se.Contract.Operations)
                          {
                                  od.Behaviors.Add(new CustomBehavior);
                          }
                   }

With this much understanding what all different behaviors are available and how to hook them to the runtime we are ready to explore the individual extension points in details from next post onwards.