使用 MEF 构建具有 n 层松散耦合的 MVC ASP.NET 应用程序

Posted

技术标签:

【中文标题】使用 MEF 构建具有 n 层松散耦合的 MVC ASP.NET 应用程序【英文标题】:Building MVC ASP.NET app with n-tier loose coupling using MEF 【发布时间】:2011-09-01 09:09:52 【问题描述】:

我有 MVC 项目。模型、控制器和视图都有自己的项目,因此有 3 个 dll。我还有一个 IFACADE、IBUSINESS 和 IDATALAYER 接口(dll),在 FACADE、BUSINESS 和 DATACCESS DLLS 中有具体实现。 如何使用 MEF 将它们连接在一起?

【问题讨论】:

【参考方案1】:

我的建议是在您的系统中定义第一个可扩展点,在什么层或您希望允许第三方开发人员扩展或完全替换的组件。您必须定义可扩展性的起点和终点。

这是您在开始开发之前必须做出的设计决定。您可能稍后可以更改,但它会花费您更多的时间,并且您必须进行很多更改。在您定义它之后,一切都会变得容易得多。

尝试定义契约(接口),因为 MEF 中的契约取代了典型应用程序的紧密耦合。 MEF 在运行时使用协定来匹配 Import 和 Export 组件。

如果您有 ex 的存储库。 ProductRepository 有一些方法,然后创建一个包含这些方法的接口 IProductRepository,然后用 export 属性标记 ProductRepository,如下所示:

public interface IProductRepository

    IEnumerable<Product> GetProducts(Expression<Func<Product, bool>> query);


[Export(typeof(IProductRepository))]
public class ProductRepository : IProductRepository

    public IEnumerable<Product> GetProducts(Expression<Func<Product, bool>> query)
    
        throw new NotImplementedException();
    

为了争论,假设您有这样的产品服务:

public interface IProductService

    IEnumerable<Product> GetLatestProducts(int items);


[Export(typeof(IProductService))]
public class ProductService : IProductService

    private IProductRepository _repository;


    [ImportingConstructor]
    public ProductService(IProductRepository repository)
    
        this._repository = repository;
    

    public IEnumerable<Product> GetLatestProducts(int items)
    
        return _repository.GetProducts(p => p.DateCreated == DateTime.Today).OrderByDescending(p => p.DateCreated).Take(items);
    

通过使用 Export 属性标记您的存储库,您可以让您的服务通过 MEF 导入相同的存储库。如您所见,我们将工作委托给 MEF CompositionContainer 以向 ProductService 提供 ProductRepository 的实例……我们通过构造函数注入使用依赖注入来注入此实例。

然后在您的 MVC 控制器上应用相同的原则,但现在您导入的是 ProductService 而不是 ProductRepository ......像这样:

[Export(typeof(IController))]
[ExportMetadata("Name","Product")]
public class ProductController : Controller

    private IProductService _service;

    [ImportingConstructor]
    public ProductController(IProductService service)
    
        _service = service;
    

    public ActionResult LatestProducts()
    
        var model = _service.GetLatestProducts(3);
        return View(model);
    

通过导出控制器,您可以随时将控制器放置在同一个程序集中或单独的程序集中。如您所见,我向控制器添加了另一个属性 [ExportMetadata("Name","Product")]。这用于在查询组合容器时决定哪个控制器退出组合容器。

现在您接下来需要做的是从某个目录创建匹配器 => 组合容器:TypeCalog、DirectoryCatalog、AssemblyCatalog 或 AggregateCatalog。您告诉目录加载程序集的位置。你可以在codeplex阅读更多内容

现在您需要一种方法来让您的控制器脱离 CompositionContainer。在 MVC 中可以执行此操作的地方是 ControllerFactory。您必须创建一个自定义 ControllerFactory(通过继承 DefaultControllerFactory 或实现 IControllerFactory 接口)。然后在控制器工厂中查询组合容器并找到请求的控制器。

你大概可以理解,组合的过程是从控制器工厂开始的:ProductController导入ProductService,ProductService导入ProductRepository。 MEF 组合容器遍历依赖关系图并满足这些导入。

【讨论】:

感谢 f 的回答。您是否有可以共享的示例应用程序。提前致谢 订阅这个博客,在接下来的几天里我打算发布类似的东西 - phalanx.spartansoft.org/author/m-shaqiri

以上是关于使用 MEF 构建具有 n 层松散耦合的 MVC ASP.NET 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

SpringMVC简介

Azure网络设置

.Net框架搭建之2SQL Server MEF依赖注入 MVC Repository框架

.Net框架搭建之2SQL Server MEF依赖注入 MVC Repository框架

管理通过使用“设计器”属性产生的松散耦合的程序集引用

SpringMVC ------JstlView