Unity 3: Passing parameters to policy injection custom call handlers through a configuration file

Jan 28, 2014 at 4:46 PM
Edited Jan 28, 2014 at 4:48 PM
Hi,
I'm writing a custom call handler and I'm having trouble trying to figure out how to pass it parameters through a configuration file. I can't find documentation saying how to do this. For example I have a call handler like this
[ConfigurationElementType(typeof(CustomCallHandlerData))]
public class DetailedLogCallHandler : ICallHandler
{
    public DetailedLogCallHandler()
    {
        TraceExecution = false;
    }

    public DetailedLogCallHandler(bool traceExecution)
    {
        TraceExecution = traceExecution;
    }

    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
       ...
    }

    public bool TraceExecution { get; set; }
}
With the following configuration file
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
  <sectionExtension
    type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration, Version=3.0.0.0, Culture=neutral"  />

  <alias alias="DetailedLogCallHandler" type="Foo.DetailedLogCallHandler, Foo" />

  <container>
    <extension type="Interception" />
    <interception>
      <policy name="Bar">
        <matchingRule name="Bar" type="TagAttributeMatchingRule">
          <constructor>
            <param name="tagToMatch" value="TagOnBar" />
          </constructor>
        </matchingRule>
        <callHandler name="DetailedLogCallHandler" type="DetailedLogCallHandler">
          <constructor>
            <param name="traceExecution" value="True" />
          </constructor>
        </callHandler>
      </policy>

    </interception>

    <register type="Foo.Bar, Foo">
      <interceptor type="VirtualMethodInterceptor" />
      <policyInjection />
    </register>
  </container>
</unity>
But I get the error
Exception occurred while: Calling constructor Microsoft.Practices.Unity.InterceptionExtension.PolicyInjectionBehavior(Microsoft.Practices.Unity.InterceptionExtension.CurrentInterceptionRequest interceptionRequest, Microsoft.Practices.Unity.InterceptionExtension.InjectionPolicy[] policies, Microsoft.Practices.Unity.IUnityContainer container).
Exception is: ResolutionFailedException - Resolution of the dependency failed, type = "Microsoft.Practices.Unity.InterceptionExtension.ICallHandler", name = "6c14f8aa-f9a9-4894-b065-e991a270d90d".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The type Boolean does not have an accessible constructor.
I've tried things like changing the type of traceExecution to a string, but that didn't work either. Any help would be appreciated.
Thanks!
Jan 30, 2014 at 1:11 AM
The posted configuration is working for me. Are you sure that the correct configuration file is deployed? Perhaps an older version of the configuration file is being used that does not contain the constructor parameter?

Here's my code and config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
  </configSections>

  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">

    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>

    <alias alias="DetailedLogCallHandler" type="UnityCallHandlerConfig.DetailedLogCallHandler, UnityCallHandlerConfig" />
    
    <container>

      <extension type="Interception"/>

      <interception>
        <policy name="Bar">
          <matchingRule name="Bar" type="TagAttributeMatchingRule">
            <constructor>
              <param name="tagToMatch" value="TagOnBar" />
            </constructor>
          </matchingRule>
          <callHandler name="DetailedLogCallHandler1" type="DetailedLogCallHandler">
            <lifetime type="singleton"/>
            <constructor>
              <param name="traceExecution" value="true" />
            </constructor>
          </callHandler>
        </policy>

      </interception>

      <register type="UnityCallHandlerConfig.Bar, UnityCallHandlerConfig">
        <interceptor type="VirtualMethodInterceptor" />
        <policyInjection />
      </register>

    </container>

  </unity>

  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
  </startup>
</configuration>

I added a singleton lifetime for the callhandler so there is only one instance for the policy (usually you don't need a new instance for every call) but it is still running without that.
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using Microsoft.Practices.Unity.InterceptionExtension;
using System;

namespace UnityCallHandlerConfig
{
    [Tag("TagOnBar")]
    public class Bar
    {
        public virtual void Do()
        {
            Console.WriteLine("Just do it!");
        }
    }

    [ConfigurationElementType(typeof(CustomCallHandlerData))]
    public class DetailedLogCallHandler : ICallHandler
    {
        public DetailedLogCallHandler()
        {
            TraceExecution = false;
        }

        public DetailedLogCallHandler(bool traceExecution)
        {
            Console.WriteLine("ctr called with " + traceExecution);
            TraceExecution = traceExecution;
        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            Console.WriteLine("Begin Invoke with " + TraceExecution);
            IMethodReturn result = getNext()(input, getNext);
            Console.WriteLine("End Invoke");
            return result;
        }

        public bool TraceExecution { get; set; }

        public int Order { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var container = new UnityContainer().LoadConfiguration();
            var bar = container.Resolve<Bar>();
            bar.Do();
        }
    }
}

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Jan 30, 2014 at 3:00 PM
Hi,
Thanks for the response. Yea, something is definitely weird. I ran the code you executed Randy in a fresh new VS 2013 project and it works fine for me as well. I'm wondering my problem if this is a DLL reference issue since my "real" project references other third party DLLs that use Enterprise Library 4 and Unity 1. However I didn't think this was an issue because I
  • Strong named all references to anything prefixed with Microsoft.Practices in my config file with version and publickeytoken
  • Put the EntLib 6 and Unity 3 DLLs in the GAC
  • I verified all my DLL references in VS are to Unity 3 and Enterprise Library 6.
  • All other EL and Unity functionality runs fine in my Unit Tests and on a dev server, just this constructor issue does not work at all.
However, I just noticed some other clues. Even if I don't specify the constructor parameter injection in the configuration file and just have
<callHandler name="DetailedLogCallHandler" type="DetailedLogCallHandler" />
I get the same error. If I remove the constructor with the boolean parameter (bool traceExecution) it executes correctly.


I also noticed this at compile time in the VS output window
2>  No way to resolve conflict between "Microsoft.Practices.EnterpriseLibrary.Common, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" and "Microsoft.Practices.EnterpriseLibrary.Common, Version=4.1.0.0, Culture=neutral, PublicKeyToken=null". Choosing "Microsoft.Practices.EnterpriseLibrary.Common, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" arbitrarily.
2>  No way to resolve conflict between "Microsoft.Practices.Unity, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" and "Microsoft.Practices.Unity, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null". Choosing "Microsoft.Practices.Unity, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" arbitrarily.
Any suggestions would be appreciated.
Thanks!
Jan 30, 2014 at 11:43 PM
Hi,
Actually I don't think it's a problem with a reference to an old Unity/EL DLL. I took my original project and slowly stripped out everything bit by bit trying to isolate the problem and now I'm down to basically what's in your solution Randy. I'm at a bit of a loss to explain what is the cause of the problem. :(
Feb 3, 2014 at 3:53 PM
I finally figured out the cause of the problem, but I'm not sure what is the best way to resolve. The problem is that I was had multiple policies using the custom call handler and only the first one specified the boolean constructor parameter. I assumed Unity would use the default constructor (which I explicitly declared in the class as you can see above) if I did not provide any constructor parameter values in the policy configuration, so I assumed it was my policy configuration where I specified the boolean parameter that was wrong. In fact it was the other policies that did not declare the parameteer that were causing the problem since when I explicitly specified a bool parameter in all my policies the app worked. Thus how do I get Unity to use my default constructor by default when I do no specify any constructor parameter values?
Thanks
Feb 3, 2014 at 5:55 PM
I did test having multiple call handlers (one for each policy) since that's what your intent seemed to be and that does work properly. Just give each call handler a unique name (e.g. name="DetailedLogCallHandler1").

To use the default constructor you can use an empty constructor element:
<callHandler name="DetailedLogCallHandler1" type="DetailedLogCallHandler">
   <lifetime type="singleton"/>
   <constructor />
</callHandler>
~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Feb 3, 2014 at 7:34 PM
Edited Feb 3, 2014 at 7:36 PM
Specifying <constructor /> worked. I don't suppose a way to assume it should use the default constructor without having an explicit <constructor /> ? It's just to reduce config file size/complexity since this custom call handler is going to be used a lot. Thanks.
Feb 4, 2014 at 4:16 AM
One way would be to attribute the default constructor with an InjectionConstructorAttribute to indicate that it is the constructor you want to use:
        [InjectionConstructor]
        public DetailedLogCallHandler()
        {
            TraceExecution = false;
        }
If you do add configuration to use another constructor it will override the attribute.

Usually, it's preferable to not have your application depend on the container but since this is part of a framework and is itself a Unity call handler it already has a dependency on Unity so you are not introducing a dependency that is not already there.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to