2013-04-09 96 views
1

我在Mef周圍纏繞頭腦,以及導入和導出如何工作。我的項目結構如下。mvc 4 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的控制器,並用導出屬性和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,對於通用庫和inherents標有屬性導出類。

[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錯誤。

回答

1

MVC中的默認控制器工廠嘗試使用無參數構造函數創建控制器。如果你想改變這種行爲,那麼你需要創建自己的定製控制器工廠。

一個的ControllerFactory的Here is an example使用控制器上的

我使用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(); 
    } 
} 

}

+0

感謝您的回覆。我使用上面的代碼創建了控制器工廠(我稱之爲MefControllerFactory),將以下行添加到我的global.asax文件中。 ControllerBuilder.Current.SetControllerFactory(typeof運算(MefControllerFactory));它在我加載站點時引發此錯誤:嘗試創建IControllerFactory'MefMVCApp.MefControllerFactory'時發生錯誤。確保控制器工廠具有公共無參數構造函數。] – 2013-04-10 00:04:39

+0

它具有公共無參數構造函數嗎? – pollirrata 2013-04-10 03:52:27

+0

感謝您的幫助。控制器工廠是我失蹤的一塊。我修改了你給我的代碼,現在讓它工作。 – 2013-04-10 18:23:40

1

謝謝pollirrata指着我在正確的方向。

我不得不改變一些東西才能使它工作。

1.)我在我的MefMVCFramework.Common項目中添加了一個名爲INameMetadata的接口。

public interface INameMetadata 
{ 
    string Name { get; } 
} 

2.)修改我的控制器上的My 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)我創建了一個名爲MefConfig類主MVC應用程序和移動它到App_Start Dir。

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

    }