开发者

Building MVC ASP.NET app with n-tier loose coupling using MEF

开发者 https://www.devze.com 2023-03-08 00:20 出处:网络
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

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 D开发者_如何转开发LLS. How can i connect them all together using 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号