Can I inject code (Policy Injection) before executeReader or executeScalar?

Topics: Data Access Application Block, General discussion, Policy Injection Application Block
Sep 17, 2012 at 10:59 PM

Marcos Lima asked

I would like to inject a code before ExecuteReader, ExecuteScalar. This code is going to set the Context_Info(http://msdn.microsoft.com/pt-br/library/ms187768.aspx) with the Context.User.Identity, if available. How can I get started on this? (I know about interception, policy injection, and so on... but I don't know how to intercept methods inside entlib)

Sep 18, 2012 at 12:05 AM
Edited Sep 18, 2012 at 1:57 AM

In general you cannot intercept an arbitrary object (Enterprise Library or otherwise) -- it all depends on what object and how it is managed by Enterprise Library.  See Unity Interception Techniques for a full discussion of interception.

In terms of intercepting the Database class it seems promising since it does have virtual methods.  I don't think policy injection is going to work work though since we will have to use the VirtualMethodInterceptor.

So, we can create an IInterceptionBehavior that does what we want:

    public class ConsoleCallBehavior : IInterceptionBehavior
    {
        MatchingRuleSet matchingRuleset;

        public ConsoleCallBehavior(MatchingRuleSet matchingRuleset)
        {
            this.matchingRuleset = matchingRuleset;
        }

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

        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            bool shouldRun = matchingRuleset.Matches(input.MethodBase);

            if (shouldRun)
            {
                Console.WriteLine("Before " + input.MethodBase.Name + ".");
            }

            IMethodReturn result = getNext()(input, getNext);
            
            if (shouldRun)
            {
                Console.WriteLine("After!");
            }

            return result;  
        }

        public bool WillExecute
        {
            get { return true; }
        }
    }

Since the behavior is being applied to all virtual methods on the Database object and not via Policy Injection I added a MemberNameMatchingRule (but the behavior also supports multiple rules via a MatchingRuleset) check.

Then we register that behavior with the UnityContainer and set that container as the service locator:

    IUnityContainer container = new UnityContainer();

    // Load default configuration
    var coreExtension = new EnterpriseLibraryCoreExtension(ConfigurationSourceFactory.Create());
    container.AddExtension(coreExtension);

    MatchingRuleSet ruleSet = new MatchingRuleSet() { 
        new MemberNameMatchingRule(
            new string[] {"ExecuteReader", "ExecuteScalar"} )
    };

    container.RegisterType<ConsoleCallBehavior>(new InjectionConstructor(ruleSet));

    // What connection string to use
    var injectionConstructor = new InjectionConstructor(
        new object[] { ConfigurationManager.ConnectionStrings["Logging"].ConnectionString }
    );

    // Use the appropriate database type here instead of SqlDatabase
    container.RegisterType<Database, SqlDatabase>("Logging", injectionConstructor,
        new InterceptionBehavior<ConsoleCallBehavior>(),
        new Interceptor<VirtualMethodInterceptor>());

    IServiceLocator locator = new UnityServiceLocator(container);
    EnterpriseLibraryContainer.Current = locator;

    var db = EnterpriseLibraryContainer.Current.GetInstance<Database>("Logging");

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Sep 18, 2012 at 4:00 AM

I'm not sure that Context_Info will work since you will probably have different sessions in the behavior and the executexxx method.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Oct 10, 2012 at 4:53 AM

Thanks Randy! This is what i've been looking for.