Autofac是.net界一款轻量化的IOC组件,使用Autofac可以帮助完成代码中很多依赖注入工作。在以前文章中,介绍过Autofac的配置过程(http://www.cnblogs.com/Jnw-qianxi/p/3450344.html),在我以往的配置过程中,接口与接口的实现类的注册在一个静态方法RegisterAutofac中实现:
1 public static void RegisterAutofac() 2 { 3 ContainerBuilder builder = new ContainerBuilder(); 4 builder.RegisterControllers(Assembly.GetExecutingAssembly()); 5 6 #region IOC注册区域 7 8 9 //Admin 10 builder.RegisterType<AdminService>().As<IAdminService>().InstancePerHttpRequest(); 11 12 13 #endregion 14 // then 15 var container = builder.Build(); 16 DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 17 18 }
随着系统开发的进行,IOC注册区域中会不断添加新的注册,不同区域,不同模块的类型注册都会在这进行(数据仓储层,业务逻辑层,基础设施层等等不同层次的类型注册都要在此方法中进行),同时系统不同开发人员都需要维护该方法,这样带来
RegisterAutofac方法所在类的臃肿,且不符合类的职责单一原则。
为此我想到,能否根据注册类型,将IOC注册区域部分提取到不同的类中实现,将如这些类拥有一个共同的接口,不是就可以根据接口反射出获取这些类了吗?
首先,定义反射类。用于获取继承接口的类型
1 public class ContainerTypeFinder : ITypeFinder 2 { 3 4 public IList<Assembly> GetAssemblies() 5 { 6 //由于注册文件可能分布在不同类库,为此我们获取所有程序集,而不是当前程序集 7 return AppDomain.CurrentDomain.GetAssemblies(); 8 9 } 10 11 public IEnumerable<Type> FindClassesOfType(Type assignTypeFrom) 12 { 13 var list = new List<Type>(); 14 foreach (var item in GetAssemblies()) 15 { 16 var typesToRegister = item.GetTypes() 17 .Where(type => !String.IsNullOrEmpty(type.Namespace)) 18 .Where(type => type.GetInterface(assignTypeFrom.Name) == assignTypeFrom) 19 ; 20 if (typesToRegister.Count() > 0) 21 { 22 list.AddRange(typesToRegister); 23 } 24 } 25 return list; 26 } 27 }
然后,就是将IOC注册区域移除到类当中
1 public interface IDependencyRegistrar 2 { 3 void Register(ContainerBuilder builder); 4 5 int Order { get; } 6 } 7 8 9 public class DependencyRegistrar : IDependencyRegistrar 10 { 11 public void Register(ContainerBuilder builder) 12 { 13 builder.RegisterType<EfRepository<Core.Domain.Customer.Customer>>().As<IRepository<Core.Domain.Customer.Customer>>().InstancePerHttpRequest(); 14 } 15 16 public int Order 17 { 18 get { return 1; } 19 } 20 }
IDependencyRegistrar就是我们上面所说的接口,ContainerTypeFinder类当中的FindClassesOfType()方法会搜寻所有实现该接口的类。实现的注册工作在Register()方法中完成。
接着,封装一个方法完成所有的Autofac注册工作,同时便于在Global中调用:
1 public static void InitContainer() 2 { 3 //autofac 容器 4 ContainerBuilder builder = new ContainerBuilder(); 5 //注册所有控制器 6 builder.RegisterControllers(_typeFinder.GetAssemblies().ToArray()); 7 8 #region 反射 核心 9 //通过反射得到继承IDependencyRegistrar该接口的类成员 10 var types = _typeFinder.FindClassesOfType(typeof(IDependencyRegistrar)); 11 var drInstances = new List<IDependencyRegistrar>(); 12 //创建实例 13 foreach (var drType in types) 14 drInstances.Add((IDependencyRegistrar)Activator.CreateInstance(drType)); 15 //sort 16 drInstances = drInstances.AsQueryable().OrderBy(t => t.Order).ToList(); 17 //执行Register方法 18 foreach (var dependencyRegistrar in drInstances) 19 dependencyRegistrar.Register(builder); 20 #endregion 21 22 //then 23 var container = builder.Build(); 24 DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
最后在Global文件Application_Start()方法中调用上述方法
1 ContainerManager.InitContainer();