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