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

发布于 2024-11-09 09:41:56 字数 151 浏览 2 评论 0原文

我有 MVC 项目。模型、控制器和View 都有一个自己的项目,因此有 3 个 dll。我还有 IFACADE、IBUSINESS 和 IFACADE。 IDATALAYER 接口(dll)在外观、业务和应用程序中具有具体实现。数据访问 DLL。 我如何使用 MEF 将它们连接在一起?

I have MVC project. the model, controller & View are all have a project of there own hence 3 dlls. I also have a IFACADE, IBUSINESS & IDATALAYER interfaces(dlls) with concrete implementaion in a FACADE, BUSINESS & DATACCESS DLLS.
How can i connect them all together using MEF?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦在深巷 2024-11-16 09:41:56

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

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

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

如果您有 ex 的存储库。 ProductRepository 有一些方法,然后创建一个包含这些方法的接口 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);
    }
}

通过使用 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 组合容器遍历依赖关系图并满足这些导入。

What I would suggest is to define first extensibility points in your system, at what layer or what components you want to allow third party developers to extend or entirely replace. You have to define where the extensibility starts and where it ends.

This is a design decision that you have to take before starting development. You can probably change later, but it will consume you more time and you'll have to do a lot of changes.After you define this, then everything becomes much easier.

Try to define contracts (interfaces) because a contract in MEF replaces the tight coupling of a typical application. MEF uses a contract to match Import and Export components at runtime.

If you have a repository for ex. ProductRepository that has some methods, then create an interface IProductRepository that contains those methods, then mark ProductRepository with export attribute like this:

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

For the sake of argument let’s say that you have a service for products like this:

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

By marking your repository with Export attribute, you enable your services to import the same repository via MEF. As you can see, we delegate work to the MEF CompositionContainer to provide ProductService with an instance of ProductRepository ... we inject this instance by using Dependency Injection via constructor injection.

Then on your MVC controllers you apply the same principle, but now you import ProductService and not ProductRepository ... something like this:

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

By exporting your controllers, you can place your controllers whenever you want, in the same assembly or in a separate assembly. As you can see I've added another attribute to the controller, [ExportMetadata("Name","Product")]. This is used to decide which controller to get out of composition container when querying it.

Now what you need to do next is to create your match maker => composition container from some catalog: TypeCalog, DirectoryCatalog, AssemblyCatalog or AggregateCatalog. You tell to the catalog where to load assemblies. You can read more in codeplex

Now you need a way to somehow get your controllers out of CompositionContainer. The place where you can do this in MVC is ControllerFactory. You have to create a custom ControllerFactory (by inheriting DefaultControllerFactory or implement IControllerFactory interface). Then inside controller factory you query the composition container and you find the requested controller.

As you can probably understand, the process of composition starts from controller factory: the ProductController imports ProductService and ProductService imports ProductRepository. MEF composition container walks through the dependency graph and satisfies those imports.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文