MEF IOC使用

IOC介绍

IOC:控制反转,DI:依赖注入。按我的理解应该是一个东西。作用目前我看到的主要是解除各个层之间的强耦合,实现接口分离。MEF优点:

1、net4 自带,无需安装扩展(引用System.ComponentModel.Composition.dll)。

2、0配置:这一点很重要,其实很早以前我就看到过IOC的介绍,但一直没搞明白怎么用(配置太多了),有什么用(虽然介绍了,但是看别人写的代码感觉比直接new还麻烦。),最开始还是在spring中看到的。

使用方法举例

1、DAL中使用接口隔离并导出实现类,注意:一个接口只能有一个实现类,接口代码如下:

    public interface IUserRepository
    {
        List<UserInfo> GetAllUsers();
    }

2、实现接口,并导出为IUserRepository,为了规范代码,防止BLL中出现 IUserRepository repository=new UserRepository();之类的代码,将类改为internal,而不是public。代码如下:

 [Export(typeof(IUserRepository))]
    internal class UserRepository : MEFDemo.DAL.IUserRepository
    {
        public List<UserInfo> GetAllUsers()
        {
            List<UserInfo> listUsers = new List<UserInfo>()
            {
                new Model.UserInfo(){UserName="奥巴马",Password="123456"},
                new Model.UserInfo(){UserName="*",Password="123456"}
            };
            return listUsers;
        }
    }

3、在BLL中使用,类上标记为Export,需要注入的属性标记为Import。(属性,Java中成为注解)

[Export(typeof(IUserService))]
    internal class UserSerVice : IUserService
    {
        [Import]
        protected IUserRepository UserRepository { get; set; }

        public List<Model.UserInfo> GetAllUsers()
        {

            return UserRepository.GetAllUsers();
        }

        public Model.UserInfo ValidateUser(string userName, string password)
        {

            return UserRepository.GetAllUsers().Where(m => m.UserName == userName && m.Password == password).FirstOrDefault();
        }


    }

4、最后这是最关键的一步:

 a、MVC,分两步,第一步实现IDependencyResolver接口,代码如下:

    public class MefDependencySolver : IDependencyResolver
    {
        private readonly ComposablePartCatalog _catalog;
        private const string HttpContextKey = "MefContainerKey";

        public MefDependencySolver(ComposablePartCatalog catalog)
        {
            _catalog = catalog;
        }

        public CompositionContainer Container
        {
            get
            {
                if (!HttpContext.Current.Items.Contains(HttpContextKey))
                {
                    HttpContext.Current.Items.Add(HttpContextKey, new CompositionContainer(_catalog));
                }
                CompositionContainer container = (CompositionContainer)HttpContext.Current.Items[HttpContextKey];
                HttpContext.Current.Application["Container"] = container;
                return container;
            }
        }

        #region IDependencyResolver Members

        public object GetService(Type serviceType)
        {
            string contractName = AttributedModelServices.GetContractName(serviceType);
            return Container.GetExportedValueOrDefault<object>(contractName);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return Container.GetExportedValues<object>(serviceType.FullName);
        }

        #endregion
    }

第二步,在Global类的Application_Start中注册,代码如下:

            DirectoryCatalog catalog = new DirectoryCatalog(AppDomain.CurrentDomain.SetupInformation.PrivateBinPath);
            MefDependencySolver solver = new MefDependencySolver(catalog);
            DependencyResolver.SetResolver(solver);

b、如果是在单元测试或者应用程序中使用,需要按以下代码来调用,注意 仅仅是最后一层需要手动的用注入容器构造服务层(最后一层)的对象实例

 [Export]
    [TestClass()]
    public class UserSerViceTests
    {

        public UserSerViceTests()
        {
            AggregateCatalog catalog = new AggregateCatalog();
            catalog.Catalogs.Add(new DirectoryCatalog(Directory.GetCurrentDirectory()));
            catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
            CompositionContainer container = new CompositionContainer(catalog);

            UserService = container.GetExportedValue<IUserService>();
        }
        protected IUserService UserService { get; set; }
        [TestMethod()]
        public void ValidateUserTest()
        {
            UserInfo user = UserService.ValidateUser("admin", "123456");
            Assert.IsNull(user);
        }

        [TestMethod()]
        public void GetAllUsersTest()
        {

            List<UserInfo> listUsers = UserService.GetAllUsers();
            Assert.IsFalse(listUsers.Count < 1);
        }
    }

 最后说明一点,MEF如果有一个地方注入失败,将导致所有的注入都不可用。查找错误的方法请参照微软官方文档。

本文代码来源于http://www.cnblogs.com/guomingfeng/archive/2013/05/19/mvc-overall-design.html,非常的深入浅出,以前总看得云里雾里的,现在基本上知道怎么用了,非常感谢作者的分享。有空我也转载一下作者这个系列的博文。

posted @ 2015-06-14 00:39  哆啦无梦  阅读(303)  评论(0编辑  收藏  举报