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

标签 asp.net-mvc mef n-tier-architecture

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

最佳答案

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

这是您在开始开发之前必须做出的设计决定。您可能稍后会更改,但这会消耗您更多的时间,并且您将不得不做很多更改。定义这个之后,一切都会变得容易得多。

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

如果您有 ex 的存储库。 ProductRepository 有一些方法,然后创建一个包含这些方法的接口(interface) IProductRepository,然后用导出属性标记 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);
    }
}

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

然后在您的 MVC Controller 上应用相同的原则,但现在您导入 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);
    }
}

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

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

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

正如您可能理解的那样,组合过程从 Controller 工厂开始:ProductController 导入 ProductService,ProductService 导入 ProductRepository。 MEF 组合容器遍历依赖关系图并满足这些导入。

关于asp.net-mvc - 使用 MEF 构建具有 n 层松散耦合的 MVC ASP.NET 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6118389/

相关文章:

c# - BAL在3层架构中的使用?如何从DAL调用方法到BAL

c# - 什么时候使用 Html.Action 而不是 Html.Partial

plugins - MEF 和版本控制

mef - Caliburn Micro:基于MEF的方案的插件相关问题

mef - 为什么 MEF 目录使用 IQueryable 而不是 IEnumerable?

c# - 为什么我们需要C#中的UI,业务和数据访问之间的接口(interface)

c# - Roles.GetRolesForUser 抛出异常对象引用未设置为对象的实例

c# - 在同一请求中呈现 View 和下载文件

javascript - 如何使用 Knockout 迭代 select 中的项目以显示范围值

c# - .NET 中的多层应用程序