# Friday, 12 February 2010

We just caught this one this morning…  It looks like WF 4 reuses activity instances across workflow instances.  So if I have a WorkflowService that’s hosted in IIS, and I call it from two different client threads at the same time, the two workflow instances now running on the server may be using the same activity instances for child activities.  The documentation is not clear on this point, but that’s the behavior we observed. 

The implication is that you have to treat calls to your Activity’s Execute method as stateless, and not maintain any state in your activity between calls to Execute.  (Our specific problem was around EntityFramework containers.  Apparently they don’t like being called on multiple threads. :) )

Makes sense, but it’s not clear at all from the documentation that it would be the case.  You can rely on the thread safety of your InArguments and OutArguments, since they are accessed through the context, but private fields are right out unless whatever you store in them is also threadsafe.

Friday, 12 February 2010 11:14:40 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, 10 February 2010

This is probably one of those things that is obvious to everyone but me, but just in case it’s not…

We’re using Unity as our IoC container, and we are also using .NET 4 Workflow Services hosted in IIS, meaning .xamlx files that are served up by IIS 7.  In order to get full value out of Unity, we need one instance of the Unity container that gets properly configured somewhere that is then available to any WF activity that might need to resolve a reference.  But…since IIS is hosting, there’s no direct access to the WorkflowServiceHost to add the Unity container as an extension (which is how we do it in places where we are hosting using WorkflowApplication in WPF apps, etc.).  I suspected that the solution was a WCF Service Behavior extension, because that’s how you set up a tracking participant if you are hosted in IIS, and luckily that turned out to be the case.  I’d been putting off nailing it down because I suspected it was hard, but as luck would have it (or, rather, the cleverness of the ServiceModel team) it’s not hard at all.

First, we need a behavior extension that creates (and ultimately configures) the Unity container.  It has to implement IServiceBehavior, since we need it to be a service behavior to get access to the host.

public class UnityServiceBehavior : IServiceBehavior
{

    #region IServiceBehavior Members

    public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
    {
        
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
         WorkflowServiceHost host = serviceHostBase as WorkflowServiceHost;
         if (host != null)
         {
             IUnityContainer container = new UnityContainer();
             host.WorkflowExtensions.Add<IUnityContainer>(delegate { return container; });
         }
   
    }

    public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
    {
        
    }

    #endregion
}
Secondly, we want it to be configurable through web.config, which calls for a BehaviorExtensionElement. 
public class UnityBehaviorElementExtension : BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get { return typeof(UnityServiceBehavior); }
    }

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

Then, in our web.config, just register the extension, which in turn will configure and return behavior.

<system.serviceModel>
  <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"/>
        <unityExtension/>
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <extensions>
    <behaviorExtensions>
      <add name="unityExtension" type="UnityBehavior.UnityBehaviorElementExtension, UnityBehavior, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
    </behaviorExtensions>
  </extensions>
  <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>

In this case, the fact that the behavior element doesn’t include a name means the set of behaviors it contains will be applied to any WCF service that is relying on the default configuration (one of the coolest things in .NET 4!) which is how our .xamlx file works in this example.

Once all that’s done, from any activity in my .xamlx workflow I can access the IUnityContainer interface as an extension.

public sealed class CheckForUnity : CodeActivity
{
    // Define an activity input argument of type string
    public OutArgument<bool> HasUnity { get; set; }

    // If your activity returns a value, derive from CodeActivity<TResult>
    // and return the value from the Execute method.
    protected override void Execute(CodeActivityContext context)
    {
        IUnityContainer container = context.GetExtension<IUnityContainer>();

        context.SetValue<bool>(HasUnity, (container != null));
    }
}
.NET 4 | Unity | WF
Wednesday, 10 February 2010 17:03:13 (Pacific Standard Time, UTC-08:00)  #    Disclaimer  |  Comments [0]  |