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,非常的深入浅出,以前总看得云里雾里的,现在基本上知道怎么用了,非常感谢作者的分享。有空我也转载一下作者这个系列的博文。