# 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]  |