Changing the Cache Sharing Levels for Send Activities

The SendMessageChannelCache extension enables you to customize the cache sharing levels, the settings of the channel factory cache, and the settings of the channel cache for workflows that send messages to service endpoints using Send messaging activities. These workflows are typically client workflows but could also be workflow services that are hosted in a WorkflowServiceHost. The channel factory cache contains cached ChannelFactory<TChannel> objects. The channel cache contains cached channels.

Note

Workflows can use Send messaging activities to send either messages or parameters. The workflow runtime adds channel factories to the cache that create channels of type IRequestChannel when you use a ReceiveReply activity with a Send activity, and an IOutputChannel when just using a Send activity (no ReceiveReply).

The Cache Sharing Levels

By default, in a workflow hosted by a WorkflowServiceHost the cache used by Send messaging activities is shared across all workflow instances in the WorkflowServiceHost (host-level caching). For a client workflow that is not hosted by a WorkflowServiceHost, the cache is available only to the workflow instance (instance-level caching). The cache is only available for Send activities that do not use endpoints defined in configuration unless unsafe caching is enabled.

The following are the different cache sharing levels available for Send activities in a workflow and their recommended use:

  • Host Level: In the host sharing level, the cache is available only to the workflow instances hosted in the workflow service host. A cache can also be shared between workflow service hosts in a process-wide cache.

  • Instance Level: In the instance sharing level, the cache is available to a particular workflow instance throughout its lifetime but the cache is not available to other workflow instances.

  • No Cache: The cache is turned off by default if you have a workflow that uses endpoints defined in configuration. It is also recommended to keep the cache turned off in this case because turning it on could be unsecure. For example, if a different identity (different credentials or using impersonation) is required for each send.

Changing the Cache Sharing Level for a Client Workflow

To set the cache sharing in a client workflow, add an instance of the SendMessageChannelCache class as an extension to the desired set of workflow instances. This results in sharing the cache across all the workflow instances. The following code examples show how to perform these steps.

First, declare an instance of type SendMessageChannelCache.

// Create an instance of SendMessageChannelCache with default cache settings.  
static SendMessageChannelCache sharedChannelCacheExtension =  
    new SendMessageChannelCache();  

Next, add the cache extension to each client workflow instance.

WorkflowApplication clientInstance1 = new WorkflowApplication(new clientWorkflow1());  
WorkflowApplication clientInstance2 = new WorkflowApplication(new clientWorkflow2());  
  
// Share the cache extension object
  
clientInstance1.Extensions.Add(sharedChannelCacheExtension);  
clientInstance2.Extensions.Add(sharedChannelCacheExtension);  

Changing the Cache Sharing Level for a Hosted Workflow Service

To set the cache sharing in a hosted workflow service, add an instance of the SendMessageChannelCache class as an extension to all the workflow service hosts. This results in sharing the cache across all the workflow service hosts. The following code examples show to perform these steps.

First, declare an instance of type SendMessageChannelCache at the class level.

// Create static instance of SendMessageChannelCache with default cache settings.  
static SendMessageChannelCache sharedChannelCacheExtension = new  
    SendMessageChannelCache();  

Next, add the static cache extension to each workflow service host.

WorkflowServiceHost host1 = new WorkflowServiceHost(new serviceWorkflow1(), new Uri(baseAddress1));  
WorkflowServiceHost host2 = new WorkflowServiceHost(new serviceWorkflow2(), new Uri(baseAddress2));  
  
// Share the static cache to get an AppDomain level cache.  
host1.WorkflowExtensions.Add(sharedChannelCacheExtension);  
host2.WorkflowExtensions.Add(sharedChannelCacheExtension);  

To set the cache sharing in a hosted workflow service to the instance level, add a Func<SendMessageChannelCache> delegate as an extension to the workflow service host and assign this delegate to the code that instantiates a new instance of the SendMessageChannelCache class. This results in a different cache for each individual workflow instance, instead of a single cache shared by all workflow instances in the workflow service host. The following code example shows how to achieve this by using a lambda expression to directly define the SendMessageChannelCache extension that the delegate points to.

serviceHost.WorkflowExtensions.Add(() => new SendMessageChannelCache  
{  
    // Use FactorySettings property to add custom factory cache settings.  
    FactorySettings = new ChannelCacheSettings
    { MaxItemsInCache = 5, },  
    // Use ChannelSettings property to add custom channel cache settings.  
    ChannelSettings = new ChannelCacheSettings
    { MaxItemsInCache = 10 },  
});  

Customizing Cache Settings

You can customize the cache settings for the channel factory cache and the channel cache. The cache settings are defined in the ChannelCacheSettings class. The SendMessageChannelCache class defines default cache settings for the channel factory cache and the channel cache in its parameterless constructor. The following table lists the default values of these cache settings for each type of cache.

Settings LeaseTimeout (min) IdleTimeout (min) MaxItemsInCache
Factory Cache Default TimeSpan.MaxValue 2 16
Channel Cache Default 5 2 16

To customize the factory cache and channel cache settings, instantiate the SendMessageChannelCache class using the parameterized constructor SendMessageChannelCache and pass a new instance of the ChannelCacheSettings with custom values to each of the factorySettings and channelSettings parameters. Next, add the new instance of this class as an extension to a workflow service host or a workflow instance. The following code example shows how to perform these steps for a workflow instance.

ChannelCacheSettings factorySettings = new ChannelCacheSettings{  
                        MaxItemsInCache = 5,
                        IdleTimeout = TimeSpan.FromMinutes(5),
                        LeaseTimeout = TimeSpan.FromMinutes(20)};  
  
ChannelCacheSettings channelSettings = new ChannelCacheSettings{  
                        MaxItemsInCache = 5,
                        IdleTimeout = TimeSpan.FromMinutes(2),  
                        LeaseTimeout = TimeSpan.FromMinutes(10) };  
  
SendMessageChannelCache customChannelCacheExtension =
    new SendMessageChannelCache(factorySettings, channelSettings);  
  
clientInstance.Extensions.Add(customChannelCacheExtension);  

To enable caching when your workflow service has endpoints defined in configuration, instantiate the SendMessageChannelCache class using the parameterized constructor SendMessageChannelCache with the allowUnsafeCaching parameter set to true. Next, add the new instance of this class as an extension to a workflow service host or a workflow instance. The following code example shows how to enable caching for a workflow instance.

SendMessageChannelCache customChannelCacheExtension =
    new SendMessageChannelCache{ AllowUnsafeCaching = true };  
  
clientInstance.Extensions.Add(customChannelCacheExtension);  

To disable the cache completely for the channel factories and the channels, disable the channel factory cache. Doing so also turns off the channel cache as the channels are owned by their corresponding channel factories. To disable the channel factory cache, pass the factorySettings parameter to the SendMessageChannelCache constructor initialized to a ChannelCacheSettings instance with a MaxItemsInCache value of 0. The following code example shows this.

// Disable the factory cache. This results in the channel cache to be turned off as well.  
ChannelCacheSettings factorySettings = new ChannelCacheSettings  
    { MaxItemsInCache = 0 };  
  
ChannelCacheSettings channelSettings = new ChannelCacheSettings();  
  
SendMessageChannelCache customChannelCacheExtension =
    new SendMessageChannelCache(factorySettings, channelSettings);
  
clientInstance.Extensions.Add(customChannelCacheExtension);  

You can choose to use only the channel factory cache and disable the channel cache by passing the channelSettings parameter to the SendMessageChannelCache constructor initialized to a ChannelCacheSettings instance with a MaxItemsInCache value of 0. The following code example shows this.

ChannelCacheSettings factorySettings = new ChannelCacheSettings();  
// Disable only the channel cache.  
ChannelCacheSettings channelSettings = new ChannelCacheSettings  
    { MaxItemsInCache = 0};  
  
SendMessageChannelCache customChannelCacheExtension =
    new SendMessageChannelCache(factorySettings, channelSettings);
  
clientInstance.Extensions.Add(customChannelCacheExtension);  

In a hosted workflow service, you can specify the factory cache and channel cache settings in the application configuration file. To do so, add a service behavior that contains the cache settings for the factory and channel cache and add this service behavior to your service. The following example shows the contents of a configuration file that contains the MyChannelCacheBehavior service behavior with the custom factory cache and channel cache settings. This service behavior is added to the service through the behaviorConfiguration attribute.

<configuration>
  <system.serviceModel>  
    <!-- List of other config sections here -->
    <behaviors>  
      <serviceBehaviors>  
        <behavior name="MyChannelCacheBehavior">  
          <sendMessageChannelCache allowUnsafeCaching ="false" >  
            <!-- Control only the host level settings -->
            <factorySettings maxItemsInCache = "8" idleTimeout = "00:05:00" leaseTimeout="10:00:00" />  
            <channelSettings maxItemsInCache = "32" idleTimeout = "00:05:00" leaseTimeout="00:06:00" />  
          </sendMessageChannelCache>  
        </behavior>  
      </serviceBehaviors>  
    </behaviors>  
    <services>  
      <service name="MyService" behaviorConfiguration="MyChannelCacheBehavior" />  
    </services>  
  </system.serviceModel>  
</configuration>