首页 文章

如何将MEF与ASP.NET MVC 4和ASP.NET Web API集成

提问于
浏览
28

如何在同一个项目中将Managed Extensibility Framework(MEF)与ASP.NET MVC 4和ASP.NET Web API集成?

考虑一个示例应用程序,其中包含MVC控制器 HomeController 和Web API控制器 ContactController . 两者都具有 IContactRepository 类型的属性,它们依赖于MEF来解析 . 问题是如何将MEF插入MVC和Web API,以便通过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 and 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"}
        };
    }
}

Contact:

public class Contact
{
    public int Id { get; set; }
    public string Name { get; set; }
}

6 回答

  • 0

    解决方案是实现System.Web.Mvc.IDependencyResolverSystem.Web.Http.Dependencies.IDependencyResolver,并在 Application_Start 方法中分别使用ASP.NET MVC和ASP.NET Web API注册实现 .

    在这个例子中,我们将创建一个类 MefConfig ,它实现了一个从 Application_Start 调用的方法 RegisterMef ,以便安装我们的依赖项解析器 . 类 MefDependencyResolver 实现 System.Web.Mvc.IDependencyResolverSystem.Web.Http.Dependencies.IDependencyResolver ,因此,处理MVC和Web API的依赖项解析任务 .

    Application_Start, Put This in Your Global.asax.cs:

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

    MefDependencyResolver and 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;
        }
    }
    
  • 1

    你可以看一下这个http://kennytordeur.blogspot.be/2012/08/mef-in-aspnet-mvc-4-and-webapi.html . 它解释了如何在Asp.net MVC 4 / Web Api项目中使用MEF . 基于此代码也存在Nuget package . 这样您就可以非常轻松快速地进行测试 .

  • 1

    @ aknuds1答案是我迄今为止看到的将MEF集成到DependencyResolver中的最佳答案 . 我能够相当容易地扩展它以在MEF2中使用基于约定的组合 . MefConfig类是改变所需的所有内容,而不是更多 .

    /// <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;
        }
    }
    
  • 0

    Kenny Torduer先生的解决方案对我有用,而假设的正确答案却没有(虽然所有相关部分都在catelog中,但我无法解析控制器实例,但我得到了“类型没有默认构造函数”错误)!

    Correction :两种方法实际上都有效,我在公约部分注册表中的一个基本错误是愚蠢的 . 我真诚地向作者提供了正确的答案 .

  • 28

    这是我在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);
       }        
    }
    

    在Application_Start中运行MefConfig.Initialise()并在FilterConfig.RegisterGlobalFilters(GlobalFilterCollection过滤器)中输入filters.Add(new Filters.MefFilterAttribute());

  • 0

    我关注@ akanuds1的答案,但我还必须将ControllerFactory更改为:

    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));
    }
    

相关问题