VirtualMethodInterceptor and VirtualMethodInvocation.Inputs = 0

Dec 5, 2008 at 9:08 PM
Hi,

I am using the VirtualMethodInterceptor to intercept various methods with custom call handlers.  When the call handler gets invoked I check the Inputs collection of the VirtualMethodInvocation object to get the parameters that are passed into the method but for some reason the Inputs collection always has a count of 0 when it should be filled with the parameters.  I tried using the TransparentProxyInterceptor just to see if that worked and Inputs collection was correctly populated with the method parameters.  Anyone have this problem before or is there something I'm missing when configuring the VirtualMethodInterceptor so it doesn't lose the method parameters?

Thanks,
Matt
Dec 5, 2008 at 9:43 PM
It should just work. Could you share a small but complete repro of the problem you're having?
Dec 5, 2008 at 10:12 PM
Edited Dec 5, 2008 at 10:14 PM

I setup the VirtualMethodInterceptor through the config against a type and then created a policy for the custom call handler to match on the desired method with a TagAttributeMatchingRule. I want the custom call handler to be invoked when the target method is called and cycle through the parameters to check their values.

Below is the policy for the handler:

<add name="CustomPolicy">
        <matchingRules>
          <add match="Custom" ignoreCase="false" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.MatchingRules.TagAttributeMatchingRule, Microsoft.Practices.EnterpriseLibrary.PolicyInjection"
            name="Tag Attribute Matching Rule" />
        </matchingRules>
        <handlers>
          <add SpecificationSource="Configuration" RuleSet="RuleSetA"
            order="0" type="CallHandlers.CustomCallHandler, CallHandlers"
            name="CustomCallHandler" />
        </handlers>
</add>

Below is the a sample of the method that should be intercepted:

        <Tag("Custom")> _
        Public Overridable Function DoSomething(ByVal employee As DataObjects.Employee) As String Implements Interfaces.IBusinessService.DoSomething

            Dim value As String = "Returned from Business Service"
            Return value

        End Function

Below is a small sample of my custom call handler, which will cycle through the parameters of the targeted method but for some reason the input.Inputs.Count is always 0 when using VirtualMethodInterceptor.

public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
            //Cycle through all parameters
            for (int index = 0; index < input.Inputs.Count; index++)
            {
                ...
            }

        return getNext().Invoke(input, getNext);
}

The call handler gets invoked correctly but the parameters do not carry over when using the VirtualMethodInterceptor but the parameters do carry over when using the TransparentProxyInterceptor.

Let me know if you need any more information.

Thanks,
Matt

Dec 6, 2008 at 12:24 AM
Thanks, I think that's all I'll need. I'll take a look at it on Monday and let you know.

In the meantime, have you tried using the Arguments collection instead of Inputs in your call handler?

-Chris

Dec 8, 2008 at 9:57 PM
I debugged throught the code to see if the Arguments collection is populated and it is correctly populated.  Are there any differences between the Arguments collection and the Inputs collection?  Also,  Any luck on reproducing the problem with the Inputs collection?

Thanks for the help,
Matt
Dec 8, 2008 at 10:03 PM
I've reproduced the issue, and it's a bug. The fundamental issue is this line in VirutalMethodInvocation.cs:

            this.inputs = new ParameterCollection(parameterValues, targetParameters,
                delegate(ParameterInfo param) { return param.IsIn; });

That chunk in italics is supposed to check if a parameter is an input. Unfortunately, it appears the compilers don't set the metadata on PropertyInfo correctly, so the value of IsIn is always false even if it is an input.

The "correct' code is apparently supposed to be !param.IsOut instead.

The workaround is to use the Arguments collection instead of the Inputs collection. I'll file a bug to get this fixed.

-Chris

Dec 8, 2008 at 10:04 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Dec 8, 2008 at 10:08 PM
The different between the two collections is that Arguments include everything passed to the method, including out and ref parameters. Inputs include only the input parameters.

Dec 8, 2008 at 10:11 PM
Ah ok, that makes sense.  Thanks alot for the help.

Matt