【问题标题】:mvc 4 mef import/export confusionmvc 4 mef 导入/导出混淆
【发布时间】:2013-04-09 18:31:49
【问题描述】:

我很难理解 Mef 以及导入和导出的工作原理。我的项目结构如下。

Projects:
MefMVPApp (Main MVC 4 app)
MefMVCFramework.Common(Interfaces shared between the projects)
MefMVCDemo.Plugins.OrderStatus (pluggable area.)
MefMVCDemo.Plugins.Data (Repository for OrderStatus)
OrderStatus.Models(domain models shared between the projects)

主 Mvc 应用程序的目标是通过 mef 托管可插入区域。

OrderStatus 区域有一个名为 OrderStatusController 的控制器,并用 Export Attribute 和 ImportingConstructor 装饰。

[Export(typeof(IController))]
        [ExportMetadata("controllerName", "OrderStatus")]
        [PartCreationPolicy(CreationPolicy.NonShared)] 
        public class OrderStatusController : Controller
        {
            private readonly IRepository<OrderStatusApp.OrderStatusResponse>_repository ;
            [ImportingConstructor]
            public OrderStatusController(IRepository<OrderStatusApp.OrderStatusResponse> oRepository)
            {
                _repository = oRepository;
            }
            public ActionResult Index()
            {
                var model = _repository.GetAll();
                return View();
            } 
    }

IRepository 是 MefMVCFramework.Common 程序集中的一个类,将用于通用 CRUD 操作。

public interface IRepository<T> where T : class
            {
               IEnumerable<T> GetAll();
               T GetById(int id);
               void Add(T entity);
               int SaveOrUpdate(T entity);
                bool Delete(T entity);
                bool Delete(int id); 
            }

MefMVCDemo.Plugins.Data 程序集包含一个名为 OrderManagementRepository 的类,它是通用存储库的固有属性,并标有导出属性。

[Export(typeof(IRepository<OrderStatusApp.OrderStatusResponse>))]
            [PartCreationPolicy(CreationPolicy.NonShared)] 
                public class OrderManagementRepository  : IRepository<OrderStatusApp.OrderStatusResponse>
                {
                    private readonly JsonServiceClient _client;

                    public OrderManagementRepository()
                    {
                        _client = new JsonServiceClient("http://localhost:52266");
                    }
                    public IEnumerable<OrderStatusApp.OrderStatusResponse> GetAll()
                    {

                        throw new NotImplementedException("Can not get all");
                    }
                    public OrderStatusApp.OrderStatusResponse GetById(int id)
                    {
                        throw new NotImplementedException();
                    }
                    public void Add(OrderStatusApp.OrderStatusResponse entity)
                    {
                        throw new NotImplementedException();
                    }
                    public int SaveOrUpdate(OrderStatusApp.OrderStatusResponse entity)
                    {
                        throw new NotImplementedException();
                    }
                    public bool Delete(OrderStatusApp.OrderStatusResponse entity)
                    {
                        throw new NotImplementedException();
                    }
                    public bool Delete(int id)
                    {
                        throw new NotImplementedException();
                    }
                } 

使用 Mefx 工具,我可以看到我的零件并且没有拒绝。

mefx /dir:C:\
Source.PreBranch.Keep\Prototypes\Projects\MefDemoApp\mefMVC4App\bin /parts
MefMVCDemo.Plugins.Data.OrderManagementRepository
mefMVCDemo.Plugins.OrderStatus.Controllers.OrderStatusController
MefMVCDemo.Plugins.OrderStatus.Verbs.OrderStatusVerb

我可以看到我的导入。

mefx /dir:C:\
Source.PreBranch.Keep\Prototypes\Projects\MefDemoApp\mefMVC4App\bin /imports
MefMVCFramework.Common.IRepository(OrderStatus.Models.OrderStatusApp+OrderStatus
Response)
MefMVCFramework.Common.IRepository(OrderStatus.Models.OrderStatusApp+OrderStatus
Response)

现在,当使用 /orderstatus uri 浏览我的主 mvc 站点时,我收到以下错误: 没有为此对象定义无参数构造函数。

向 OrderStatusController 添加一个不带重载的默认构造函数似乎不起作用。

我想问题是我做错了什么?为什么我在构造函数中的接口最终都是空的,为什么会出现关于“没有为此对象定义无参数构造函数”的 mvc 错误。

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-4 mef


    【解决方案1】:

    MVC 中的默认控制器工厂尝试使用无参数构造函数创建控制器。如果你想改变这种行为,那么你需要创建自己的自定义控制器工厂。

    Here is an example 的 ControllerFactory 在控制器上使用导入/导出

    我正在使用 MEF 将一些部件导入我的应用程序,但我的控制器没有导入/导出,所以我创建了以下控制器工厂

    public class ControllerFactory : IControllerFactory
    {
        private readonly CompositionContainer _container;
        private IControllerFactory _innerFactory;
    
    /// <summary>
    /// Constructor used to create the factory
    /// </summary>
    /// <param name="container">MEF Container that will be used for importing</param>
    public ControllerFactory(CompositionContainer container)
    {
        _container = container;
        _innerFactory = new DefaultControllerFactory();
    }
    
    /// <summary>
    /// Method used for create the controller based on the provided name. It calls the
    /// constructor of the controller passing the MEF container
    /// </summary>
    /// <param name="requestContext">Context of the request</param>
    /// <param name="controllerName">Name of the controller provided in the route</param>
    /// <returns>The controller instance</returns>
    public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        Type controllerType = FindControllerByName(controllerName);
    
        var args = new object[] { this._container };
        var controller = (IController)Activator.CreateInstance(controllerType, args);
    
        return controller;
    }
    
    /// <summary>
    /// This methods looks into the current Assembly for the Controller type
    /// </summary>
    /// <param name="name">The controller name provided in the route</param>
    /// <returns>The controller type</returns>
    private static Type FindControllerByName(string name){
        var a = Assembly.GetAssembly(typeof(ControllerFactory));
        var types = a.GetTypes();
        Type type = types.Where(t => t.Name == String.Format("{0}Controller", name)).FirstOrDefault();              
    
        return type;
    }
    
    
    public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        return System.Web.SessionState.SessionStateBehavior.Default;
    }
    
    public void ReleaseController(IController controller)
    {
        var disposableController = controller as IDisposable;
        if (disposableController != null)
        {
            disposableController.Dispose();
        }
    }
    

    }

    【讨论】:

    • 感谢您的回复。我使用上面的代码创建了控制器工厂(我称之为 MefControllerFactory),将以下行添加到我的 global.asax 文件中。 ControllerBuilder.Current.SetControllerFactory(typeof(MefControllerFactory));当我加载站点时,它会引发此错误:尝试创建 IControllerFactory 'MefMVCApp.MefControllerFactory' 时发生错误。确保控制器工厂有一个公共的无参数构造函数。]
    • 是否有公共的无参数构造函数?
    • 感谢您的帮助。控制器工厂是我缺少的部分。我稍微修改了你给我的代码,现在它可以工作了。
    【解决方案2】:

    感谢 pollirrata 为我指明了正确的方向。

    我必须改变一些东西才能让它工作。

    1.) 我在 MefMVCFramework.Common 项目中添加了一个名为 INameMetadata 的接口。

    public interface INameMetadata
    {
        string Name { get; }
    }
    

    2.) 将我的控制器导出上的 ExportMetadata 标记修改为 Name、OrderStatus。

     [Export(typeof(IController))]
    [ExportMetadata("Name", "OrderStatus")]
    [PartCreationPolicy(CreationPolicy.NonShared)] 
    public class OrderStatusController : Controller
    {
        private IRepository<OrderStatusApp.OrderStatusResponse> _repository;
    
        [ImportingConstructor]
        public OrderStatusController(IRepository<OrderStatusApp.OrderStatusResponse> oRepository)
        {
            _repository = oRepository;
    
        }
    
        public ActionResult Index()
        {
            var model = _repository.GetById(47985);
            return View(model);
        } 
    }
    

    3.) 创建 MefControllerFactory(基于 pollirrata 发布但修改为查找元数据的内容)

     public class MefControllerFactory : IControllerFactory
    {
        private string _pluginPath;
        private readonly DirectoryCatalog _catalog;
        private readonly CompositionContainer _container;
        private DefaultControllerFactory _defaultControllerFactory;
    
        public MefControllerFactory(string pluginPath)
        {
            _pluginPath = pluginPath;
            _catalog = new DirectoryCatalog(pluginPath);
            _container = new CompositionContainer(_catalog);
            _defaultControllerFactory = new DefaultControllerFactory();
        }
    
        public MefControllerFactory(CompositionContainer compositionContainer)
        {
    
            _container = compositionContainer;
            _defaultControllerFactory = new DefaultControllerFactory();
        }
        #region IControllerFactory Members
        public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            //IController controller = null;
            var controller = _container.GetExports<IController,INameMetadata>()
                .Where(e=>e.Metadata.Name.Equals(controllerName))
                .Select(e=>e.Value).FirstOrDefault();
    
            if (controller == null)
            {
                throw new HttpException(404, "Not found");
            }
    
            return controller;
    
        }
        public void ReleaseController(IController controller)
        {
           var disposable = controller as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }
        #endregion
    
    
        public SessionStateBehavior GetControllerSessionBehavior(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            return SessionStateBehavior.Default;
        }
    }
    

    4.) 我在 Main MVC 应用程序中创建了一个名为 MefConfig 的类,并将其移至 App_Start 目录。

    public static class MefConfig
    {
        public static void RegisterMef()
        {
            //var builder = new RegistrationBuilder();
            //builder.ForTypesDerivedFrom<IRepository<OrderStatusApp.OrderStatusResponse>>().Export<IRepository<IRepository<OrderStatusApp.OrderStatusResponse>>>();
    
            var directoryCatalog = new DirectoryCatalog(HostingEnvironment.MapPath("~/bin"), "*.dll");
    
            var container = new CompositionContainer(directoryCatalog, true);
            ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));
    
            //Working
            //ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(HostingEnvironment.MapPath("~/bin")));
    
            // Install MEF dependency resolver for MVC
            var resolver = new MefDependencyResolver(container);
            DependencyResolver.SetResolver(resolver);
            // Install MEF dependency resolver for Web API
            GlobalConfiguration.Configuration.DependencyResolver = resolver;
            var d = container.GetExportedValues<IRepository<OrderStatusApp.OrderStatusResponse>>();
            //Mefx.
            try
            {
                //var ci = new CompositionInfo(aggregateCatalog, container);
                var ci = new CompositionInfo(directoryCatalog, container);
                var partDef = ci.GetPartDefinitionInfo(typeof(IRepository<OrderStatusApp.OrderStatusResponse>));
    
                //var possibleCauses = partDef.FindPossibleRootCauses();
                var stringWriter = new StringWriter();
                CompositionInfoTextFormatter.Write(ci, stringWriter);
                var compStatString = stringWriter.ToString();
            }
            catch
            {
    
            }
            MvcApplication.ActionVerbs = container.GetExports<IActionVerb, IActionVerbMetadata>();
        }
    }
    

    5.) 从 global.asax 加载 Mefconfig。

     protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            //Register Mef 
            MefConfig.RegisterMef();
    
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-17
      • 1970-01-01
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-06
      相关资源
      最近更新 更多