Error with Lightweight MVC CompositionProvider

Mar 15, 2012 at 8:33 PM
In my global.asax I load an extra assembly:
            CompositionProvider.AddAssembly(typeof(Xperit.Framework.StringExtensions).Assembly);

In that assembly there is only one part:

namespace Xperit.Framework
{
    public interface ILogger<T>
    {
        //Methods
    }
}

namespace Xperit.Framework.Parts
{
    [Export(typeof(ILogger<>))]
    public class Logger<T> : ILogger<T>
    {
         //Methods
    }
}

But this gives the following error:

[AmbiguousMatchException: Ambiguous match found.]
   System.RuntimeType.GetPropertyImpl(String name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) +10387715
   System.Type.GetProperty(String name, BindingFlags bindingAttr) +30
   System.Reflection.Context.Delegation.DelegatingType.GetPropertyImpl(String name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) +44
   System.Reflection.Context.Projection.ProjectingType.GetPropertyImpl(String name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) +66
   System.Reflection.Context.Custom.CustomType.GetPropertyImpl(String name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) +56
   System.Type.GetProperty(String name, BindingFlags bindingAttr) +30
   System.ComponentModel.Composition.Lightweight.Util.ReflectionContextAttributeContext.MapMemberOrDefault(MemberInfo member, Func`2 mapping) +599
   System.ComponentModel.Composition.Lightweight.Util.ReflectionContextAttributeContext.GetDeclaredAttributes(MemberInfo member) +183
   System.ComponentModel.Composition.Lightweight.Hosting.Providers.TypedParts.Discovery.<DiscoverPropertyExports>d__16.MoveNext() +377
   System.ComponentModel.Composition.Lightweight.Hosting.Providers.TypedParts.Discovery.<DiscoverExports>d__0.MoveNext() +449
   System.ComponentModel.Composition.Lightweight.Hosting.Providers.TypedParts.Discovery.TypeInspector.InspectTypeForPart(Type type, DiscoveredPart& part) +322
   System.ComponentModel.Composition.Lightweight.Hosting.Providers.TypedParts.TypedPartExportDescriptorProvider..ctor(IEnumerable`1 types, IAttributeContext attributeContext) +215
   System.ComponentModel.Composition.Lightweight.Hosting.ContainerConfiguration.CreateContainer() +609
   System.ComponentModel.Composition.Web.Mvc.CompositionProvider.SetConfiguration(ContainerConfiguration configuration) +214
   System.ComponentModel.Composition.Web.Mvc.CompositionProvider.PostStartDefaultInitialize() +191
   System.ComponentModel.Composition.Web.Mvc.RequestCompositionScopeModule.Init(HttpApplication context) +83
   System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +418
   System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +172
   System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +336
   System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +300

When I use this in my Global.asax it works fine:

            var configuration = new MvcContainerConfiguration()
                .WithPart(typeof(Xperit.Framework.Parts.Logger<>));
            CompositionProvider.SetConfiguration(configuration);

Any idea what the problem can be?

Regards, Jaap

Mar 15, 2012 at 9:48 PM

Thanks very much for the report. This is occurring because one of the other types in your assembly has two properties with the same name, for example a re-declaration of a property in a derived class that already appears in the base class. Some of the convention support does not handle this properly, causing the error you're getting.

By adding the part using the WithPart() method directly, you're avoiding both the type that is causing the issue, and the convention-based code applied by AddAssembly().

I've created an issue here to track this: http://mef.codeplex.com/workitem/14592.

Thanks again.

Nick

Mar 17, 2012 at 5:39 PM

I can confirm this situation indeed occurs one time in my assembly.

Jaap

Mar 26, 2012 at 6:18 PM

Thanks. You may be able to work around this by applying [PartNotDiscoverable] to the problematic class.

Nick

Mar 26, 2012 at 7:49 PM

But by convention only classes in a Parts namespace should be discovered, I thought?

And that offending class is not in a Parts namespace, so it should not be necessary to apply that attribute?

Jaap

Mar 26, 2012 at 8:11 PM

Only types in the Parts namespace are discovered using the default conventions. You can still apply attributes like [Export] to other types in the main web app assembly in order to have them discovered as parts. In this case MEF is looking for any explicitly [Export]ed properties.

It might make sense to restrict discovery to only the Parts namespace, as your intuition suggested - thoughts?

Mar 26, 2012 at 8:32 PM

Hm, ok. It also discovers classes with explicit [Export] attributes. That makes sense. Didn't thought of that. I think that is a good behavior.

I think you should just skip classes which have problems with ambiguous properties, so that it does not break the discovery process.

Jaap