How to change the transaction isolation level in the TransactedReceiveScope activity in Workflow Foundation under IIS

Hello,

Sometimes we have contention problems in database because of the transaction isolation level when we execute a lot of inserts in parallel. To avoid this, if the business allows it, it is useful to “downgrade” the isolation level of .NET transactions. By default, in the .NET framework, it is set to Serializable, but usually we want to use ReadCommited or anything lower instead.

In WCF is easy to change , and in the WF’s TransactionScopes you have a beautiful combo to do it.

But what can we do with the TransactedReceiveScope activity? It doesn’t have any combo to modify the isolation level. It imitates the WCF’s TransactionScopeRequired but we can not set the isolation level of the Workflow easily in the ServiceBehaviour of the header.

At this point we only have one way, create and assign the behaviour by a BehaviourExtensionElement and assign it by configuration. The behaviour:

 ///
<summary> /// Service behaviour that changes the default WCF/WF transaction isolation to ReadCommitted.
 /// http://social.msdn.microsoft.com/Forums/en/wfprerelease/thread/5c4f1c0f-9183-46ae-8c6e-08bdfaa93fd8
 /// </summary>
    public class ReadCommittedServiceBehaviour : BehaviorExtensionElement ,IServiceBehavior
    {

            public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection endpoints, BindingParameterCollection bindingParameters)
            {

            }

            public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                //this looks for the ServiceBehaviour.
                var serviceBehaviour = serviceDescription.Behaviors.FirstOrDefault(b => b.GetType() == typeof(ServiceBehaviorAttribute)) as ServiceBehaviorAttribute;

                //if it doesn't exist... WF XAMLX case add a ServiceBehaviourAttribute, if exists(WCF case) modify it.
                if (serviceBehaviour == null)
                {
                    serviceDescription.Behaviors.Add(new ServiceBehaviorAttribute() { TransactionIsolationLevel = IsolationLevel.ReadCommitted });
                }
                else
                {
                    //remove it and add it again, this way it gets the isolation level
                    serviceDescription.Behaviors.Remove(typeof(ServiceBehaviorAttribute));
                    serviceDescription.Behaviors.Add(serviceBehaviour);
                    serviceBehaviour.TransactionIsolationLevel = IsolationLevel.ReadCommitted;
                }
            }

            public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {

            }

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

            protected override object CreateBehavior()
            {
                return new ReadCommittedServiceBehaviour();
            }
    }

And we tell the IIS app to use it, notice the <ReadCommittedBehaviour /> at the end of the behaviour section.


 <system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name="ReadCommittedBehaviour" type="TransactionsAndExceptions.ReadCommittedServiceBehaviour, TransactionsAndExceptions" />
      </behaviorExtensions>
    </extensions>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true" />
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false" />
                    <sqlWorkflowInstanceStore instanceCompletionAction="DeleteAll" instanceEncodingOption="None" instanceLockedExceptionAction="NoRetry" connectionStringName="ApplicationServerWorkflowInstanceStoreConnectionString" hostLockRenewalPeriod="00:00:30" runnableInstancesDetectionPeriod="00:00:05" />
                    <workflowInstanceManagement authorizedWindowsGroup="AS_Administrators" />
                    <workflowUnhandledException action="Abandon" />
                    <workflowIdle timeToPersist="00:00:00" timeToUnload="00:01:00" />

          <dataContractSerializer maxItemsInObjectGraph="2147483647" />

          <ReadCommittedBehaviour />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>

Hope this helps

Advertisements

One comment

  1. […] Well, as I have explained before, the TransactedReceiveScope activity creates a serializable transaction that causes blocks. I have used a tag to modify this behaviour and create a ReadCommitted transaction, but it doesn&#821… […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: