Resolving Open Generics with RegistrationBuilder

Jan 20, 2013 at 10:53 PM
Edited Jan 20, 2013 at 10:55 PM

My open generic works fine when exported with an attribute, such as

 

 

[Export(typeof(IRepository

<>))]  

 

public class ExampleRepository<T> : IRepository<T> whereT : class

 

 However, I haven't been able to work out how to export this with RegistrationBuilder. Neither of these work

 

builder.ForTypesDerivedFrom(typeof(IRepository<>)).ExportInterfaces();

builder.ForTypesDerivedFrom(typeof(IRepository<>)).Export(eb => eb.AsContractType(typeof(IRepository

 <>)));

Has anyone worked out how to export open generics from RegistrationBuilder?

Is it impossible?

 

 

 

 

 

Coordinator
Jan 22, 2013 at 9:56 PM

Hi Kathleen,

Here is a response from Kevin on the MEF team.

Yes it is possible to export generics using RegistrationBuilder.

There is a bug in Desktop MEF that we didn’t fix. We did fix it in Oob MEF.

The work around is to use code like this, the bold is what she needs to add the rest is to make it a complete sample:

using System;

using System.Collections.Generic;

using System.ComponentModel.Composition;

using System.ComponentModel.Composition.Hosting;

using System.ComponentModel.Composition.Registration;

using System.Linq;

using System.Reflection;

using System.Text;

using System.Threading.Tasks;

namespace ConsoleApplication26

{

public interface IRepository<T>

{

IEnumerable<T> GetItems();

}

public class ExampleRepository<T> : IRepository<T> where T : class

{

public IEnumerable<T> GetItems()

{

return new List<T>();

}

}

[Export]

public class Importer

{

[ImportMany]

public IEnumerable<string> Items;

}

class Program

{

private static bool IsGenericDescendentOf(TypeInfo openType, TypeInfo baseType)

{

if (openType.BaseType == null)

{

return false;

}

if (openType.BaseType == baseType.AsType())

{

return true;

}

foreach (Type type in openType.ImplementedInterfaces)

{

if (type.IsConstructedGenericType && (type.GetGenericTypeDefinition() == baseType.AsType()))

{

return true;

}

}

return IsGenericDescendentOf(IntrospectionExtensions.GetTypeInfo(openType.BaseType), baseType);

}

private static bool IsDescendentOf(Type type, Type baseType)

{

if (((type == baseType) || (type == typeof(object))) || (type == null))

{

return false;

}

TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(type);

TypeInfo info2 = IntrospectionExtensions.GetTypeInfo(baseType);

if (typeInfo.IsGenericTypeDefinition)

{

return IsGenericDescendentOf(typeInfo, info2);

}

return info2.IsAssignableFrom(typeInfo);

}

static void Main(string[] args)

{

var reg = new RegistrationBuilder();

reg.ForTypesMatching((t) =>

{

return IsDescendentOf(t, typeof(IRepository<>));

}).Export((eb) => eb.AsContractType(typeof(IRepository<>)));

var cat = new TypeCatalog( new Type[] { typeof(ExampleRepository<>), typeof(Importer) }, reg );

var container = new CompositionContainer(cat);

var importer = container.GetExportedValue<Importer>();

if (importer.Items == null)

{

Console.WriteLine("Failed");

}

}

}

}

hth

cheers

-alok

From: KathleenDollard [email removed]
Sent: Sunday, January 20, 2013 2:53 PM
To: Alok Shriram
Subject: Resolving Open Generics with RegistrationBuilder [MEF:430218]

From: KathleenDollard

My open generic works fine when exported with an attribute, such as

[Export(typeof(IRepository

However, I haven't been able to work out how to export this with RegistrationBuilder. Neither of these work

builder.ForTypesDerivedFrom(typeof(IRepository

<>)).ExportInterfaces();

builder.ForTypesDerivedFrom(typeof(IRepository<>)).Export(eb => eb.AsContractType(typeof(IRepository

<>)));



Has anyone worked out how to export open generics from RegistrationBuilder?

Is it impossible?

<>))]

public class ExampleRepository<T> : IRepository<T> whereT : class

Nov 21, 2013 at 5:58 AM
We are using MEF2 RegistrationBuilder.ForTypesMatching as provided as a solution above for exporting the types from a class library. I have attached the sample code below. This is working fine before updating the system with the Microsoft update KB2840642v2. But is not exporting any parts after updated the system with the update KB2840642v2. One thing we noticed is that it is not working when I put this code in Global.asax.cs. But the code is working fine on a console application. The same issue is there on .net 4.5 and .net 4.5.1. Tested the same result on Visual Studio 2012 and Visual Studio 2013.

Looking for a fix or workaround for this.
  using HandlerModule;
  using System;
  using System.ComponentModel.Composition;
  using System.ComponentModel.Composition.Hosting;
  using System.ComponentModel.Composition.Registration;
  using System.Reflection;
  using System.Web.Hosting;

  namespace WebApplication1
  {
public class Global : System.Web.HttpApplication
{
    private const string TaskServices = "HandlerModule.dll";

    protected void Application_Start(object sender, EventArgs e)
    {

        var reg = new RegistrationBuilder();

        string path = HostingEnvironment.MapPath("~/bin");

        AggregateCatalog mAggrCatalog = new AggregateCatalog();

        mAggrCatalog.Catalogs.Add(new DirectoryCatalog(path, TaskServices, reg));


        reg.ForTypesMatching(t => IsDescendentOf(t, typeof(IRequestHandler<,>)))
                    .Export(builder => builder.AsContractType(typeof(IRequestHandler<,>)));


        //context.ForTypesMatching(t => t.GetInterface(typeof(IRequestHandler<,>).Name) != null)
        //            .ExportInterfaces());


        var container = new CompositionContainer(mAggrCatalog, CompositionOptions.DisableSilentRejection);

        container.ComposeExportedValue(mAggrCatalog);
    }

    private static bool IsGenericDescendentOf(TypeInfo openType, TypeInfo baseType)
    {
        if (openType.BaseType == null)
        {
            return false;
        }
        if (openType.BaseType == baseType.AsType())
        {
            return true;
        }
        foreach (Type type in openType.ImplementedInterfaces)
        {
            if (type.IsConstructedGenericType && (type.GetGenericTypeDefinition() == baseType.AsType()))
            {
                return true;
            }
        }
        return IsGenericDescendentOf(IntrospectionExtensions.GetTypeInfo(openType.BaseType), baseType);
    }

    private static bool IsDescendentOf(Type type, Type baseType)
    {
        if (((type == baseType) || (type == typeof(object))) || (type == null))
        {
            return false;
        }
        TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(type);
        TypeInfo info2 = IntrospectionExtensions.GetTypeInfo(baseType);
        if (typeInfo.IsGenericTypeDefinition)
        {
            return IsGenericDescendentOf(typeInfo, info2);
        }
        return info2.IsAssignableFrom(typeInfo);
    }
   }
  }

The classes I'm exporting are on the HandlerModule class library project. Code below

namespace HandlerModule
{
public interface IRequestHandler<TRequest, TResponse>
{
    TResponse Handle(TRequest request);
}
}


namespace HandlerModule
{
public class GetOrderRequestHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse>
    where TRequest: class
    where TResponse: class
{

    public GetOrderRequestHandler()
    {
    }

    public TResponse Handle(TRequest pRequest)
    {
            return "MyREsponse" as TResponse;
    }
}
}