4.1: PolicyInjectorFactory and PolicyInjector?

Topics: Policy Injection Application Block
Oct 29, 2008 at 3:42 PM
How can I migrate following code to 4.1? Is it possible?

public class PolicyInjectionInstanceProvider : IInstanceProvider
    {
        private Type serviceContractType { get; set; }
        private static readonly PolicyInjectorFactory fac = new PolicyInjectorFactory();
        private static PolicyInjector injector;
        private readonly object _sync = new object();

        public PolicyInjectionInstanceProvider(Type type)
        {
            if (type != null && !type.IsInterface)
            {
                throw new ArgumentException("Specified Type must be an interface");
            }

            serviceContractType = type;
        }

        #region IInstanceProvider Members

        public object GetInstance(System.ServiceModel.InstanceContext instanceContext, System.ServiceModel.Channels.Message message)
        {
            Type type = instanceContext.Host.Description.ServiceType;

            if (serviceContractType != null)
            {
                return injector.Create(type, serviceContractType);
            }
            else
            {
                if (!type.IsMarshalByRef)
                {
                    throw new ArgumentException("Type Must inherit MarshalByRefObject if no ServiceInterface is Specified");
                }
                return injector.Create(type);
            }
        }

        public object GetInstance(System.ServiceModel.InstanceContext instanceContext)
        {
            return GetInstance(instanceContext, null);
        }

        public void ReleaseInstance(System.ServiceModel.InstanceContext instanceContext, object instance)
        {
            IDisposable disposable = instance as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }

        #endregion
    }
Oct 30, 2008 at 12:22 AM
There's something missing in the code sample - where do you set the injector?

The easiest thing to do is to just remove the reference to the PolicyInjectorFactory and PolicyInjector and call the PolicyInjection.Create static method instead, possibly passing in a custom IConfigurationSource if you want to use something other than the default appdomain config file.


Oct 30, 2008 at 8:10 AM
injector = fac.Create();

No, Create method is generic
Oct 30, 2008 at 9:38 AM
Crap, you're right. I can't believe I left the non-generic overloads off the PolicyInjection class.

Ok, so it's still possible to port, it'll just take a few more changes is all. The best bet is to go throught the Unity container instead. The PolicyInjection facade is now just a wrapper around an appropriately configured container anyway.

So, remove the factory and PolicyInjector from your member variables, and add this instead:
 private static readonly IUnityContainer container;
Add a static constructor to initialize the container:
        static PolicyInjectionInstanceProvider()
        {
            // Create container
            container = new UnityContainer()
                .AddNewExtension<Interception>();
                
            // Read PIAB config and apply it to the container
            IConfigurationSource configSource = ConfigurationSourceFactory.Create();
            PolicyInjectionSettings settings = (PolicyInjectionSettings)configSource.GetSection(PolicyInjectionSettings.SectionName);
            if(settings != null)
            {
                settings.ConfigureContainer(container, configSource);
            }
        }
And then change GetInstance to this:
        public object GetInstance(System.ServiceModel.InstanceContext instanceContext, System.ServiceModel.Channels.Message message)
        {
            Type type = instanceContext.Host.Description.ServiceType;
            if (serviceContractType != null)
            {
                lock(_sync)
                {
                    container.Configure<Injection>()
                        .ConfigureInterceptorFor(serviceContractType, new TransparentProxyInterceptor());
                    container.RegisterType(serviceContractType, type);
                    return container.Resolve(serviceContractType);
                }
            }
            else
            {
                if (!type.IsMarshalByRef)
                {
                    throw new ArgumentException("Type Must inherit MarshalByRefObject if no ServiceInterface is Specified");
                }
                lock(_sync)
                {
                    container.Configure<Injection>()
                        .ConfigureInterceptorFor(type, new TransparentProxyInterceptor());
                    return container.Resolve(type);
                }
            }
        }

That should do it. This also has the advantage of setting you up to use the container for other stuff too. All you'd need to do is add a step to configure the container as well in that static constructor. In fact, I'd recommend you do that - that way you can avoid the repeated configuration of  the Interceptor and the type mappings; just do them once in config.

Hope this helps,

-Chris

Oct 30, 2008 at 2:49 PM
Thanks. You really helped me!

I cannot find class Injection... I used reflector and wrote following code
container.Configure<Interception>()
                        .SetDefaultInterceptorFor(serviceContractType, injector);
Oct 30, 2008 at 7:12 PM
Whoops, that was a typo. It should have been Interception, as you figured out.

That's what I get for writing code without a compiler at 2:00 am.
Oct 31, 2008 at 6:35 PM
I am wondering, if I am building up my own unity container and want to layer PIAB into it during resolution, that is supported in 4.1

What is the best approach for doing this instead of using an interceptor?  Can the PIAB resolve a type from unity and apply its' policies for you?

I have been digging all around for a day and cannot find anything on this outside of leveraging interception on the Unity container and wiring it up manually like you do here...
Oct 31, 2008 at 9:50 PM
Found an answer to my question over on the unity site.  Will try this out and see if it works, hopefully tighter configuration integration is in the future.
http://www.codeplex.com/unity/Thread/View.aspx?ThreadId=38040
Nov 26, 2008 at 12:38 PM
> Crap, you're right. I can't believe I left the non-generic overloads off the PolicyInjection class.

Does that mean that we can expect this overload to find its way to the next release? That would be very helpful - we've had this exact issue as well


Jan 10, 2009 at 3:18 AM
The original poster's code looks to be from this helpful (but now obsolete with 4.1) MSDN Magazine Article

For me, this question is really about how to get EntLib 4.1 PIAB working happily at the service boundary for WCF services. I'm a bit surprised this wasn't included in the 4.1 release, as we do have "WCF 
integration helper" stuff in other parts of EntLib (e.g. ExceptionShielding and Logging).

Chris, another thanks for your code above and I'm working it into my system (a WCF service) now. 

A few quick questions/comments:
  1. FreddieM et al, Should we be using SetDefaultInterceptorFor() or just SetInterceptorFor() when configuring the interception extension?
  2. Should this configuration really happen in the (often frequently called) GetInstance() method? or should configuration happen once for the service type and just use Resolve() in GetInstance()?
  3. ctavares, did you need to pick the TransparentProxyInterceptor for this example?
  4. The PolicyInjection facade is a clean abstraction that also would guarantee proper setup of the container. I presume in the code sample by Chris he's put in configuration that similar to what the facade does anyway? I agree with andlju here and would like to see this facade extended in a upcoming release to help ease scenarios like this one. Using the solution above, if the Unity configuration requirements for PIAB changes in a future release, the above code may break, whereas if the code was instead used the facade, it could insulate this class from those changes.
  5. What would be grand is to have a single dll bundled with EntLib that combined the WCF instanceprovider (which is the code above), corresponding custom WCF behavior and attribute enabling easy integration of PIAB to WCF. 
Update: I see the one of the original authors of the article above has blogged about PIAB 4.1->WCF here
Feb 4, 2009 at 8:18 AM
at ruifavas request,  
 public class PolicyInjectionInstanceProvider : IInstanceProvider
 {
     private Type serviceContractType { get; set; }        
     private readonly object _sync = new object();
     private static readonly IUnityContainer container;
     private static readonly TransparentProxyInterceptor injector = new TransparentProxyInterceptor();

     static PolicyInjectionInstanceProvider()
     {
         container = new UnityContainer()
             .AddNewExtension<Interception>();

         IConfigurationSource configSource = ConfigurationSourceFactory.Create();
         PolicyInjectionSettings settings = (PolicyInjectionSettings)configSource.GetSection(PolicyInjectionSettings.SectionName);
         if (settings != null)
         {
             settings.ConfigureContainer(container, configSource);
         }
     }

     public PolicyInjectionInstanceProvider(Type type)
     {
         if (type != null && !type.IsInterface)
         {
             throw new ArgumentException("Specified Type must be an interface");
         }

         serviceContractType = type;
     }

     public object GetInstance(System.ServiceModel.InstanceContext instanceContext, System.ServiceModel.Channels.Message message)
     {
         Type type = instanceContext.Host.Description.ServiceType;
         if (serviceContractType != null)
         {
             lock (_sync)
             {
                 container.Configure<Interception>()
                     .SetDefaultInterceptorFor(serviceContractType, injector);
                 container.RegisterType(serviceContractType, type);
                 return container.Resolve(serviceContractType);
             }
         }
         else
         {
             if (!type.IsMarshalByRef)
             {
                 throw new ArgumentException("Type Must inherit MarshalByRefObject if no ServiceInterface is Specified");
             }
             lock (_sync)
             {
                 container.Configure<Interception>()
                     .SetDefaultInterceptorFor(type, injector);
                 return container.Resolve(type);
             }
         }
     }

     public object GetInstance(System.ServiceModel.InstanceContext instanceContext)
     {
         return GetInstance(instanceContext, null);
     }

     public void ReleaseInstance(System.ServiceModel.InstanceContext instanceContext, object instance)
     {
         IDisposable disposable = instance as IDisposable;
         if (disposable != null)
         {
             disposable.Dispose();
         }
     }
 }