Jak zintegrować MEF z ASP.NET MVC 4 i ASP.NET Web API

Jak zintegrować Managed Extensibility Framework (MEF) z ASP.NET MVC 4 i ASP.NET Web API w tym samym projekcie?

Rozważ przykładową aplikację z kontrolerem MVC HomeController i kontrolerem Web API ContactController. Obie mają właściwość typu IContactRepository, którą rozwiązują na MEF. Problem polega na tym, jak podłączyć MEF do MVC i Web API, aby instancje były tworzone przez MEF.

HomeController:

/// <summary>
/// Home controller. Instruct MEF to create one instance of this class per importer,
/// since this is what MVC expects.
/// </summary>
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeController : Controller
{
    [Import]
    private IContactRepository _contactRepository = null;

    public ActionResult Index()
    {
        return View(_contactRepository.GetAllContacts());
    }
}

ContactController:

/// <summary>
/// Contact API controller. Instruct MEF to create one instance of this class per importer,
/// since this is what Web API expects.
/// </summary>
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ContactController : ApiController
{
    [Import]
    private IContactRepository _contactRepo = null;

    public Contact[] Get()
    {
        return _contactRepo.GetAllContacts();
    }
}

IContactRepository i ContactRepository:

public interface IContactRepository
{
    Contact[] GetAllContacts();
}

[Export(typeof(IContactRepository))]
public class ContactRepository : IContactRepository
{
    public Contact[] GetAllContacts()
    {
        return new Contact[] {
            new Contact { Id = 1, Name = "Glenn Beck"},
            new Contact { Id = 2, Name = "Bill O'Riley"}
        };
    }
}

Kontakt:

public class Contact
{
    public int Id { get; set; }
    public string Name { get; set; }
}
Author: raistlin0788, 2012-11-26

6 answers

Rozwiązaniem jest wdrożenie systemu.Www.Mvc.System niezależny i .Www.Http.Zależności.Niezależnycyresolver i zarejestrować swoją implementację z ASP.NET MVC i ASP.NET Web API, odpowiednio, w Twojej metodzie Application_Start.

W tym przykładzie utworzymy klasę MefConfig, która implementuje metodę RegisterMef, która zostanie wywołana z Application_Start w celu zainstalowania naszego resolvera zależności. Klasa MefDependencyResolver implementuje zarówno System.Web.Mvc.IDependencyResolver, jak i System.Web.Http.Dependencies.IDependencyResolver i jako taka obsługuje zależności obowiązki rozdzielczości zarówno dla MVC, jak i Web API.

Application_Start, Umieść to w swoim globalnym.asax.cs:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        [...]
        MefConfig.RegisterMef();
    }
}

MefDependencyResolver i mefconfig:

/// <summary>
/// Resolve dependencies for MVC / Web API using MEF.
/// </summary>
public class MefDependencyResolver : System.Web.Http.Dependencies.IDependencyResolver, System.Web.Mvc.IDependencyResolver
{
    private readonly CompositionContainer _container;

    public MefDependencyResolver(CompositionContainer container)
    {
        _container = container;
    }

    public IDependencyScope BeginScope()
    {
        return this;
    }

    /// <summary>
    /// Called to request a service implementation.
    /// 
    /// Here we call upon MEF to instantiate implementations of dependencies.
    /// </summary>
    /// <param name="serviceType">Type of service requested.</param>
    /// <returns>Service implementation or null.</returns>
    public object GetService(Type serviceType)
    {
        if (serviceType == null)
            throw new ArgumentNullException("serviceType");

        var name = AttributedModelServices.GetContractName(serviceType);
        var export = _container.GetExportedValueOrDefault<object>(name);
        return export;
    }

    /// <summary>
    /// Called to request service implementations.
    /// 
    /// Here we call upon MEF to instantiate implementations of dependencies.
    /// </summary>
    /// <param name="serviceType">Type of service requested.</param>
    /// <returns>Service implementations.</returns>
    public IEnumerable<object> GetServices(Type serviceType)
    {
        if (serviceType == null)
            throw new ArgumentNullException("serviceType");

        var exports = _container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
        return exports;
    }

    public void Dispose()
    {
    }
}

public static class MefConfig
{
    public static void RegisterMef()
    {
        var asmCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
        var container = new CompositionContainer(asmCatalog);
        var resolver = new MefDependencyResolver(container);
        // Install MEF dependency resolver for MVC
        DependencyResolver.SetResolver(resolver);
        // Install MEF dependency resolver for Web API
        System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = resolver;
    }
}
 28
Author: aknuds1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-26 14:17:57

Możesz spojrzeć na to http://kennytordeur.blogspot.be/2012/08/mef-in-aspnet-mvc-4-and-webapi.html . wyjaśnia jak używać MEF w Asp.net projekt MVC 4 / Web Api. Istnieje również pakiet Nuget oparty na tym kodzie. W ten sposób można go przetestować bardzo łatwo i szybko.

 1
Author: Kenny Tordeur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-12 18:04:01

@Aknuds1 odpowiedz jest najlepsza jak do tej pory za integrowanie MEF z DependencyResolver. Udało mi się go dość łatwo rozszerzyć, aby w mef2 wykorzystać kompozycję opartą na konwencji. Klasa MefConfig jest wszystkim, co potrzebne do zmiany, a następnie nie przez wiele.

/// <summary>
///     Responsible for configuring MEF for the application.
/// </summary>
public static class MefConfig
{
    /// <summary>
    ///     Registers MEF conventions and exports.
    /// </summary>
    public static void RegisterMef()
    {
        // Register MVC/API conventions
        var registrationBuilder = new RegistrationBuilder();
        registrationBuilder.ForTypesDerivedFrom<Controller>().SetCreationPolicy(CreationPolicy.NonShared).Export();
        registrationBuilder.ForTypesDerivedFrom<ApiController>().SetCreationPolicy(CreationPolicy.NonShared).Export();
        var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly(), registrationBuilder);
        var aggregateCatalog = new AggregateCatalog(assemblyCatalog);
        var container = new CompositionContainer(aggregateCatalog);
        var resolver = new MefDependencyResolver(container);
        // Install MEF dependency resolver for MVC
        DependencyResolver.SetResolver(resolver);
        // Install MEF dependency resolver for Web API
        GlobalConfiguration.Configuration.DependencyResolver = resolver;
    }
}
 1
Author: Robb Vandaveer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-11 20:17:11

Rozwiązanie pana Kenny 'ego Torduera działało dla mnie, podczas gdy rzekoma poprawna odpowiedź Nie (Nie udało się rozwiązać instancji kontrolera, chociaż wszystkie zależne części są w catelogu, dostałem błąd "type does not have a default constructor error")!

Poprawka: oba podejścia działają właściwie, byłem głupi przez elementarny błąd w rejestrze części konwencji. Moje szczere przeprosiny dla autora prawidłowej odpowiedzi.

 0
Author: binjiezhao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-18 16:27:50

Jest to prostsze podejście, którego używam w moim projekcie MVC4.

public static class MefConfig
{
     public static CompositionContainer MefContainer = null;

     public static void Initialise()
     {
          AggregateCatalog cat = new AggregateCatalog();
          cat.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
          MefContainer = new CompositionContainer(cat);
      }
}

public class MefFilterAttribute : ActionFilterAttribute
{
   public override void OnActionExecuting(ActionExecutingContext filterContext)
   {
      MefConfig.MefContainer.ComposeParts(filterContext.Controller);
   }        
}

W Application_Start Uruchom MefConfig.Initialise () oraz w FilterConfig.RegisterGlobalFilters (GlobalFilterCollection filters) umieszcza filtry.Add (nowe filtry.MefFilterAttribute ());

 0
Author: Stuntbeaver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-13 15:58:01

Podążałem za odpowiedzią @akanuds1, ale musiałem też zmienić kontroler na ten:

public class MefControllerFactory : DefaultControllerFactory
{
    private readonly CompositionContainer compositionContainer;

    public MefControllerFactory(CompositionContainer compositionContainer)
    {
        this.compositionContainer = compositionContainer;
    }

    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
    {
        var export = compositionContainer.GetExports(controllerType, null, null).SingleOrDefault();

        IController result;

        if (null != export)
        {
            result = export.Value as IController;
        }
        else
        {
            result = base.GetControllerInstance(requestContext, controllerType);
            compositionContainer.ComposeParts(result);
        }

        return result;
    }
}
Glogal.asax.cs
protected void Application_Start()
{
    ...
    var container = MefConfig.Register();
    ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));
}
 0
Author: BrunoLM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-18 02:31:07