Validation Using VirtualMethodInterceptor

Topics: Policy Injection Application Block, Validation Application Block
Apr 11, 2011 at 7:02 PM

I am attempting to build a Windows Service that exposes public methods. I want to intercept the calls to these methods and do validations on input parameters before allowing execution of the method logic. I think I have set everything up correctly--code compiles without errors and the Windows Service comes up without any reported errors--however, method calls do not get intercepted and no validation seems to be performed.

I am using Enterprise Library 5.0 and Unity 2.0 and don't use any config files.

Here's how I setup the container in the Main() method of my Windows Service:

    partial class MyWindowsService : ServiceBase
    {
        public IUnityContainer iocContainer { get; set; }
        private static void Main()
        {
            using(IUnityContainer container=new UnityContainer())
            {
                container
                    .AddNewExtension<Interception>()
                    .RegisterType<MyWindowsService>
                    (
                        new ContainerControlledLifetimeManager(),
                        new Interceptor<VirtualMethodInterceptor>("MyMethodsInterceptor"),
                        new InterceptionBehavior<PolicyInjectionBehavior>()

                     )
                     .Configure<Interception>()
                     .AddPolicy("TestMethodValidation")
                     .AddMatchingRule<TagAttributeMatchingRule>("TestTag")
                     .AddCallHandler<ValidationCallHandler>("TestHandler");                     
                ServiceBase.Run(container.Resolve<MyWindowsService>());
            }
        }

Here's the definition for the method I'm hoping to intercept and validate:

 

        [Tag("TestTag")]
        public virtual bool MyServiceMethod
            (
                [ValidatorComposition(CompositionType.And)]
                [NotNullValidator]
                [StringLengthValidator(1,11)]
                string arg_1,
                [ValidatorComposition(CompositionType.And)]
                [NotNullValidator]
                [StringLengthValidator(1,11)]
                string arg_2,
                [StringLengthValidator(1,160)]
                string arg_3
            )
        {

                  //Some method logic; not relevant to interception
         }

In my test scenario, I invoke MyServiceMethod(null, null, null), and if I'm in debug mode, I see breakpoints set inside the method getting hit (and no validation exceptions thrown), which should not happen since validation should fail. I know this is not a multiple validation attribute issue because even if I took out the ValidatorComposition part and applied only one validator per argument, I still have the same problem.

Obviously, I'm missing something basic since I'm new to Entlib / Unity. Please help!

Apr 12, 2011 at 2:51 AM

It doesn't perform interception because you use the method of adding call handlers and matching rules supplying a name which are not registered.  This topic from the documentation explains the various ways on how you can register policy injection using the API.

Here's a sample on how you could get this to work:

container.AddNewExtension<Interception>()
                    .RegisterType<MyWindowsService>
                    (
                        new ContainerControlledLifetimeManager(),
                        new Interceptor<VirtualMethodInterceptor>("MyMethodsInterceptor"),
                        new InterceptionBehavior<PolicyInjectionBehavior()
                    )
                     .Configure<Interception>()
                     .AddPolicy("TestMethodValidation")
                     .AddMatchingRule(typeof(TagAttributeMatchingRule), new InjectionConstructor("TestTag"))
                     .AddCallHandler(typeof(ValidationCallHandler), new InjectionConstructor("RuleSet", SpecificationSource.Attributes));   

In this code, I followed the instructions in the Supply a type approach from the link I posted above. 

By the way, please post Unity-related questions in the Unity forum.

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Apr 12, 2011 at 10:33 AM

Sarah - while your comments are definitely steps in the right direction, your recommended changes did not produce the desired result--I am still unable to make Interception work. After in-depth study of Unity code and examination of the runtime UnityContainer, I see the following entries in UnityContainer.Registrations property:


Position         buildKey.Name                                                             buildKey.Type


 

[0]                 null                                                                              {Name = "IUnityContainer" FullName = "Microsoft.Practices.Unity.IUnityContainer"}


 

[1]                 Microsoft.Practices.Unity                                                {Name = "InjectionPolicy" FullName = "Microsoft.Practices.Unity.InterceptionExtension.InjectionPolicy"}

                    .InterceptionExtension

                    .AttributeDrivenPolicy,

                    Microsoft.Practices.Unity.Interception,

                    Version=2.0.414.0, Culture=neutral,

                    PublicKeyToken=31bf3856ad364e35

 


 

[2]                TestMethodValidation                                                     {Name = "InjectionPolicy" FullName = "Microsoft.Practices.Unity.InterceptionExtension.InjectionPolicy"}


 

[3]                null                                                                                 {Name="MyWindowsService" ....}


[4]                TestMethodValidation                                                     {Name = "RuleDrivenPolicy" FullName = "Microsoft.Practices.Unity.InterceptionExtension.RuleDrivenPolicy"}


[5]                d8ab9b45-df0d-4793-953c-2163266a671a                        {Name = "IMatchingRule" FullName = "Microsoft.Practices.Unity.InterceptionExtension.IMatchingRule"}


[6]                d3572ca3-c9a9-46d4-ada7-98da1f14dfb6                         {Name = "ICallHandler" FullName = "Microsoft.Practices.Unity.InterceptionExtension.ICallHandler"}


 

I don't understand why there should be two InjectionPolicies ([1] and [2]), when my intent is to have just one injection policy. Maybe I'm reading too much into it, but if you look at the internal variable UnityContainer.registeredNames, it does not have that extra entry. Is it possible that the first InjectionPolicy gets inserted by default, and is not letting the second one trigger?

Some more guidance please! Also, what is the significance of "RuleSet" in the InjectionConstructor passed into AddCallHandler()? It appears redundant, although skipping that parameter altogether will crash the service.

On the topic of Unity vs. EnterpriseLibrary forum, is there a way to migrate this thread to the Unity forum? I would hate for the readers of that forum to miss the context and discussion.

 

Apr 12, 2011 at 11:02 AM
Edited Apr 12, 2011 at 11:05 AM

The "RuleSet" is just the value of the ruleSet parameter of the constructor of the ValidationCallHandler.  The InjectionConstructor tells the container what constructor to use when creating the specified type.  Thus, in the case of the ValidationCallHandler, it tells the container to use the constructor of the ValidationCallHandler which accepts two parameters, the first of which is of string type and the other one which takes the enumeration SpecificationSource.

ValidationCallHandler(string ruleSet, SpecificationSource specificationSource)

As for the two InjectionPolicy registrations, they are two different things, the first one is the result of adding the Interception extension while the other one as adding a policy.  I'm not sure why it isn't working for you but if you want, I can send you a working copy and compare why it isn't working on your end.  Just send an email in entlib.support@avanade.com

On the matter of migrating this to the Unity forum, I don't think there's an approach which matches what you like but you can just post a link of this thread when you create a discussion on the Unity forum.

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Apr 14, 2011 at 8:32 AM
Edited Apr 14, 2011 at 11:01 PM

I found the problem: I need to mark MyWindowsService as public class. Once I did that, VirtualMethodInterceptor worked as advertised. Also, if you were to use TransparentProxyInterceptor, you do need to mark the class sealed *BUT* not inherit from MarshalByRefObject because MyWindowsService already inherits from ServiceBase class which in turn inherits from MarshalByRefObject.

Thank you for your help and support. Hopefully, this will be useful for somebody else.

Apr 15, 2011 at 1:51 AM

Glad it's working for you now.  However, you don't need to mark the class as sealed, it should work without that.  And you're right, it doesn't need to inherit from MarshalByRefObject not because ServiceBase inherits from that.  You only need your class to inherit from it when you're only using PolicyInjection rather than Unity.  The requirement for a class to be intercepted depends upon the interceptor you will use.

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com