Search code examples
c#dependency-injectionenterprise-library

ICallHandler, is an interface and cannot be constructed


At code below I got the error: ICallHandler, is an interface and cannot be constructed when resolving the object

            var attributePolicy = new AttributeDrivenPolicy();
            var rulePolicy = new RuleDrivenPolicy("LoggingFlyGoreJumpSleepMethodPolicy", new IMatchingRule[] { new MemberNameMatchingRule(new string[] { "Fly", "Gore", "Jump", "Sleep" }), new AssemblyMatchingRule("Domain") }, new string[] { "LoggingCallHandler", "CounterCallHandler" });
            var interceptor = new InterfaceInterceptor();
            var policies = new InjectionPolicy[] { attributePolicy, rulePolicy };
            var request = new CurrentInterceptionRequest(interceptor, typeof(IMosquito), mosquito.GetType());
            var behaviour = new PolicyInjectionBehavior(request, policies, _container); // *(1) we need a container just to resolve the LoggingCallHandler and CounterCallHandler
            var proxyMosquito = Intercept.ThroughProxy<IMosquito>(mosquito, interceptor, new IInterceptionBehavior[] { behaviour });
            proxyMosquito.Eat();
            proxyMosquito.Sleep();
            proxyMosquito.Suck();

I can't get working the RuleDrivenPolicy but if I remove the RuleDrivenPolicy as code below, it runs

    var attributePolicy = new AttributeDrivenPolicy();
    var interceptor = new InterfaceInterceptor();
    var policies = new InjectionPolicy[] { attributePolicy };
    var request = new CurrentInterceptionRequest(interceptor, typeof(IMosquito), mosquito.GetType());
    var behaviour = new PolicyInjectionBehavior(request, policies, null); // *(2) container removed
    var proxyMosquito = Intercept.ThroughProxy<IMosquito>(mosquito, interceptor, new IInterceptionBehavior[] { behaviour });
    proxyMosquito.Eat();
    proxyMosquito.Sleep();
    proxyMosquito.Suck();

outputing...

Mosquito Eating...
Mosquito Sleeping...
LoggingCallHandler Invoking Suck at 12:36:29
Mosquito Sucking...

However, I want the policy rule to be applied. If the policy rule is applied, the ouptut should be like as if I won't be using the Intercept.ThroughProxy<> method

Look the different output of code below, where I use the container to resolve the object instead of getting the object resolved through Intercept.ThroughProxy<> method..

 var proxyMosquito = _container.Resolve<IMosquito>();
    proxyMosquito.Eat();
    proxyMosquito.Sleep();
    proxyMosquito.Suck();

The ouput is then..

Mosquito Eating...
LoggingCallHandler Invoking Sleep at 12:43:07
Mosquito Sleeping...
LoggingCallHandler Invoking Suck at 12:43:08
Mosquito Sucking...

The container has the following registrations..

+ IUnityContainer '[default]' Container
+ IMatchingRule -> MemberNameMatchingRule 'Member Name Matching Rule-LoggingFlyGoreJumpSleepMethodPolicy' Transient
+ IMatchingRule -> AssemblyMatchingRule 'Assembly Matching Rule-LoggingFlyGoreJumpSleepMethodPolicy' Transient
+ ICallHandler -> LoggingCallHandler 'LoggingCallHandler-LoggingFlyGoreJumpSleepMethodPolicy' ContainerControlled
+ ICallHandler -> CounterCallHandler 'CounterCallHandler-LoggingFlyGoreJumpSleepMethodPolicy' ContainerControlled
+ InjectionPolicy -> RuleDrivenPolicy 'LoggingFlyGoreJumpSleepMethodPolicy' Transient
+ InjectionPolicy 'Microsoft.Practices.Unity.InterceptionExtension.AttributeDrivenPolicy, Microsoft.Practices.Unity.Interception, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' ContainerControlled
+ IServiceLocator '[default]' ExternallyControlled
+ IMosquito -> Mosquito '[default]' Transient
+ ExceptionManager '[default]' Transient
+ Database '[default]' Transient
+ ValidatorFactory '[default]' ContainerControlled

Here below the basics of the implementation

 public class Mosquito : IMosquito
    {

        public void Bit()
        {
            Console.WriteLine("Mosquito Biting...");
        }

        public void Eat()
        {
            Console.WriteLine("Mosquito Eating...");
        }

        public void Sleep()
        {
            Console.WriteLine("Mosquito Sleeping...");
        }

        [LoggingCallHandler(1)]
        public void Suck()
        {
            Console.WriteLine("Mosquito Sucking...");
        }
    }

    public interface IMosquito : IAnimal
    {
        void Suck();
    }

    public interface IAnimal
    {
        void Eat();
        void Sleep();
    }

    [ConfigurationElementType(typeof(CustomCallHandlerData))]
    public class LoggingCallHandler : ICallHandler
    {
        public LoggingCallHandler(NameValueCollection attributes)
        {

        }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            if (getNext == null) throw new ArgumentNullException("getNext");

            Console.WriteLine("LoggingCallHandler Invoking {0} at {1}", input.MethodBase.Name, DateTime.Now.ToLongTimeString());
            return getNext()(input, getNext);
        }

        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }

        public int Order { get; set; }
    }

    public class LoggingCallHandlerAttribute : HandlerAttribute
    {
        private readonly int _order;

        public LoggingCallHandlerAttribute(int order)
        {
            _order = order;
        }

        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new LoggingCallHandler(new NameValueCollection()) { Order = _order };
        }
    }

 <?xml version="1.0" encoding="utf-8" ?>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
  <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />
  <container>
    <extension type="Interception" />
    <register type="Domain.IMosquito, Domain" mapTo="Domain.Mosquito, Domain">
      <interceptor type="InterfaceInterceptor" />
      <policyInjection />
    </register>
  </container>
</unity>


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="policyInjection" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Configuration.PolicyInjectionSettings, Microsoft.Practices.EnterpriseLibrary.PolicyInjection" requirePermission="true" />
  </configSections>
  <policyInjection>
    <policies>
      <add name ="LoggingFlyGoreJumpSleepMethodPolicy">
        <matchingRules>
          <add name="Member Name Matching Rule" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.MatchingRules.MemberNameMatchingRule, Microsoft.Practices.EnterpriseLibrary.PolicyInjection">
            <matches>
              <add match="Fly" />
              <add match="Gore" />
              <add match="Jump" />
              <add match="Sleep" />
            </matches>
          </add>
          <add name="Assembly Matching Rule" match="Domain" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.MatchingRules.AssemblyMatchingRule, Microsoft.Practices.EnterpriseLibrary.PolicyInjection"/>
        </matchingRules>
        <handlers>
          <add name="LoggingCallHandler" order="1" type="IoCnAOP.LoggingCallHandler, IoCnAOP" />
        </handlers>
      </add>
    </policies>
  </policyInjection>
</configuration>

Solution

  • I'm not 100% sure what your exact situation is since the container registration code is not shown and I'm not sure where the configuration code comes in.

    However, it looks like the issue is in how the call handlers are registered. The name of the call handler (not the class name) is what is passed in to the RuleDrivenPolicy. You are passing in "LoggingCallHandler" but the container's registration is for "LoggingCallHandler-LoggingFlyGoreJumpSleepMethodPolicy".

    If you align the naming then it should work.

    var interceptor = new InterfaceInterceptor();
    
    var rulePolicy = new RuleDrivenPolicy("LoggingFlyGoreJumpSleepMethodPolicy",
        new IMatchingRule[] { new MemberNameMatchingRule(new string[] { "Fly", "Gore", "Jump", "Sleep" }) },
        new string[] { "LoggingCallHandler-LoggingFlyGoreJumpSleepMethodPolicy" });
    
    var policies = new InjectionPolicy[] { rulePolicy };
    var request = new CurrentInterceptionRequest(interceptor, typeof(IMosquito), mosquito.GetType());
    var behaviour = new PolicyInjectionBehavior(request, policies, container); 
    var proxyMosquito = Intercept.ThroughProxy<IMosquito>(mosquito, interceptor, new IInterceptionBehavior[] { behaviour });
    proxyMosquito.Eat();
    proxyMosquito.Sleep();
    proxyMosquito.Suck();
    

    This will show:

    Mosquito Eating...
    LoggingCallHandler Invoking Sleep at 11:39:35 AM
    Mosquito Sleeping...
    Mosquito Sucking...

    Showing that Sleep was intercepted since that was the only method we called that we had set a matching rule for.

    Also, I was using programmatic configuration and I had to add a default constructor to LoggingCallHandler and tell Unity to use that constructor (since Unity does not know how to resolve NameValueCollection without a registration). You might not have that issue if using configuration.