Error when doing policies on SharePoint WebPart : Ambiguous match found

Topics: Policy Injection Application Block
Jun 13, 2007 at 2:52 PM
Edited Jun 13, 2007 at 2:53 PM
Hi all,

I'm trying to use the PIAB to force all standard methods in WebParts (Render CreateChildControls etc.)
to be exception-handled so that no one web part will be able to bring down the page.

this works great for standard .net web parts, which I make inherit from my own webpart base class

However, SharePoint 2007 has some useful base-classes of its own, (ContentByQueryWebPart for instance)
so I make a my own base class inheriting from this one, containing the logic for hooking up Policy injection.

however, when I try to wrap a class inheriting from ContentByQueryWebPart using interface wrapping
I get the following exception:

AmbiguousMatchException: Ambiguous match found.
at System.RuntimeType.GetPropertyImpl(String name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
at System.Type.GetProperty(String name)
at Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Utilities.ReflectionHelper.GetPropertyFromMethod(MethodBase method)
at Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Utilities.ReflectionHelper.GetAllAttributesTAttribute(MemberInfo member, Boolean inherits)
at Microsoft.Practices.EnterpriseLibrary.PolicyInjection.AttributeDrivenPolicy.DoesMatch(MethodBase member)
at Microsoft.Practices.EnterpriseLibrary.PolicyInjection.AttributeDrivenPolicy.b__11(MethodInfo method)
at System.Array.FindIndexT(T[] array, Int32 startIndex, Int32 count, Predicate`1 match)
at System.Array.FindIndexT(T[] array, Predicate`1 match)
at Microsoft.Practices.EnterpriseLibrary.PolicyInjection.AttributeDrivenPolicy.DoesApplyTo(Type t)
at Microsoft.Practices.EnterpriseLibrary.PolicyInjection.PolicySet.CalculatePoliciesForType(Type t)
at Microsoft.Practices.EnterpriseLibrary.PolicyInjection.PolicySet.GetPoliciesFor(Type t)
at Microsoft.Practices.EnterpriseLibrary.PolicyInjection.PolicyInjector.WrapTInterface(Object instance)
at Microsoft.Practices.EnterpriseLibrary.PolicyInjection.PolicyInjection.WrapTInterface(Object instance)


Is this a bug in the PIAB?
is it possible to go around this?
Am i doing anything wrong?


ps. As I said this works like a charm when I inherit directly from System.Web.UI.WebControls.WebParts.WebPart,
but if I change that inheritance to go to Microsoft.SharePoint.WebPartPages.WebPart, it breaks
so it would seem there is something fundamentally wrong here, not just my shoddy coding.

Also I am using the strong named 3.1 release

Yours
Andreas
Jun 13, 2007 at 4:27 PM
I don't know for sure, but I think it may be a "bug" in reflection.

When I do searches on reflection ambiguous match found I notice a number of posts discussing that Reflection does a case-insensitive search to find properties and perhaps you have two properties in your hierarchy that have the same name in different cases.

I say this because the error happens in this statement:

return declaringType.GetProperty(name);

which searches for a property given a string representation of the name.

It sounds like it is coming up with two properties with the same name but in probably different cases.

Here is the whole method with the last statement giving the error:

public static PropertyInfo GetPropertyFromMethod(MethodBase method)
{
    PropertyInfo info = null;
    if (!method.IsSpecialName)
    {
        return info;
    }
    Type declaringType = method.DeclaringType;
    if ((declaringType == null) || (!method.Name.StartsWith("get_", StringComparison.InvariantCulture) && !method.Name.StartsWith("set_", StringComparison.InvariantCulture)))
    {
        return info;
    }
    string name = method.Name.Substring(4);
    return declaringType.GetProperty(name);
}

I would do a quick check for properties of the same name that would cause an ambiguous match if looked at without be case sensitive.

Regards,

Dave

________________________________

David Hayden
Microsoft MVP C#
Jun 14, 2007 at 7:57 AM
OK,
so I debugged this error into the EntLib code to figure out what the erroneous property was,
and it turns out that there is a problem with the Height property defined in
Microsoft.SharePoint.WebPartPages.WebPart.
As I have no particular need of doing any AOP on this property, I thought that it would be OK to modify the
EntLib method in question to the following (in reflectionHelper.cs, line 31:

/// <summary>
/// Given a MethodBase for a property's get or set method,
/// return the corresponding property info.
/// </summary>
/// <param name="method">MethodBase for the property's get or set method.</param>
/// <returns>PropertyInfo for the property, or null if method is not part of a property.</returns>
public static PropertyInfo GetPropertyFromMethod(MethodBase method)
{
PropertyInfo property = null;
if (method.IsSpecialName)
{
Type containingType = method.DeclaringType;
if (containingType != null)
{
if (method.Name.StartsWith("get_", StringComparison.InvariantCulture) ||
method.Name.StartsWith("set_", StringComparison.InvariantCulture))
{
try
{
string propertyName = method.Name.Substring(4);
property = containingType.GetProperty(propertyName);

}
catch (Exception )
{
return null;
}
}
}
}
return property;
}

so doing a try/catch around the GetProperty call. as the method is expected to return null when it cannot
find anything useful, I return null in the catch.

This seems to fix the problem.

Now my problem is twofold:

1) I cannot change the SharePoint source to clean up this mess in the WebPart class
2) I cannot change the EntLib source and still use the configuration tool as we need signed dlls in the GAC

is there any chance of this small change being put into a signed dll and sent to me (by the powers that be that have the signing key) or can I strong name the assemblies using our key and get the config tool to recognize my modified strongnamed EntLib?

Yours
Andreas

Jun 15, 2007 at 12:04 AM

andreakn wrote:
OK,
so I debugged this error into the EntLib code to figure out what the erroneous property was,
and it turns out that there is a problem with the Height property defined in
Microsoft.SharePoint.WebPartPages.WebPart.
code removed

This seems to fix the problem.

Now my problem is twofold:

1) I cannot change the SharePoint source to clean up this mess in the WebPart class
2) I cannot change the EntLib source and still use the configuration tool as we need signed dlls in the GAC

is there any chance of this small change being put into a signed dll and sent to me (by the powers that be that have the signing key) or can I strong name the assemblies using our key and get the config tool to recognize my modified strongnamed EntLib?

Yours
Andreas




I don't think you'll get a MS signed version of the assembly with your change, but you should be able to use the configuration tools with assemblies signed with your key. How to use the config tool depends on how you create your signed version (either versioning all the assemblies for blocks and tools or just the PIAB assemblies linked to the core assemblies signed by MS) and which version of the tool you use (stand alone or IDE integrated). If you sign all the assemblies you can use the standalone config console that you built and you can create your own "configuration set" for the integrated editor (just clone the registry key for the configuration set that gets created when you install the source code under HKCU\Software\Microsoft\Practices\EnterpriseLibrary\ConfigurationEditor and change the paths to match the location of your version of the assemblies), while if you sign just the PIAB you should be able to overwrite the standard signed binaries with yours and it should work.

HTH,
Fernando
Jun 20, 2007 at 9:33 PM
Andreas,

Could you post whatever you can about the problem you found with the WebPart Height property? I'm getting this same exception with one of my custom classes and I can't see any ambiguous properties, functions, or routines in there.

Thanks so much!
Jason
Jun 22, 2007 at 7:54 PM
I found my issue. I had two properties with the same name but one of them took an argument while the other one didn't. The code didn't differentiate between the two and the AmbiguousMatchException happened as a result.