我的NopCommerce之旅(4): 依赖注入(IOC/DI)
一、基础介绍
1 public CountryController(ICountryService countryService, 2 IStateProvinceService stateProvinceService, 3 ILocalizationService localizationService, 4 IWorkContext workContext, 5 ICacheManager cacheManager) 6 { 7 this._countryService = countryService; 8 this._stateProvinceService = stateProvinceService; 9 this._localizationService = localizationService; 10 this._workContext = workContext; 11 this._cacheManager = cacheManager; 12 }
显然,你并没有在controller调用前,new一个ICountryService的对象给controller做参数,你也不知道该在哪去写这个调用。没关系,这些都交给系统处理,你不必理会,这就是依赖注入。
二、承上启下
上一篇大致分析了应用启动,而NopCommerce完成注册依赖就在初始化上下文部分。通过代码跟踪,即可发现Nop.Core.Infrastructure.NopEngine.RegisterDependencies()。
1 //initialize engine context 初始化上下文 2 EngineContext.Initialize(false);
1 /// <summary> 2 /// Initializes a static instance of the Nop factory. 3 /// </summary> 4 /// <param name="forceRecreate">Creates a new factory instance even though the factory has been previously initialized.</param> 5 [MethodImpl(MethodImplOptions.Synchronized)] 6 public static IEngine Initialize(bool forceRecreate) 7 { 8 if (Singleton<IEngine>.Instance == null || forceRecreate) 9 { 10 Singleton<IEngine>.Instance = new NopEngine(); 11 12 var config = ConfigurationManager.GetSection("NopConfig") as NopConfig; 13 Singleton<IEngine>.Instance.Initialize(config); 14 } 15 return Singleton<IEngine>.Instance; 16 }
1 /// <summary> 2 /// Initialize components and plugins in the nop environment. 3 /// </summary> 4 /// <param name="config">Config</param> 5 public void Initialize(NopConfig config) 6 { 7 //register dependencies 8 RegisterDependencies(config); 9 10 //startup tasks 11 if (!config.IgnoreStartupTasks) 12 { 13 RunStartupTasks(); 14 } 15 16 }
1 /// <summary> 2 /// Register dependencies 3 /// </summary> 4 /// <param name="config">Config</param> 5 protected virtual void RegisterDependencies(NopConfig config) 6 { 7 var builder = new ContainerBuilder(); 8 var container = builder.Build(); 9 this._containerManager = new ContainerManager(container); 10 11 //we create new instance of ContainerBuilder 12 //because Build() or Update() method can only be called once on a ContainerBuilder. 13 14 //dependencies 15 var typeFinder = new WebAppTypeFinder(); 16 builder = new ContainerBuilder(); 17 builder.RegisterInstance(config).As<NopConfig>().SingleInstance(); 18 builder.RegisterInstance(this).As<IEngine>().SingleInstance(); 19 builder.RegisterInstance(typeFinder).As<ITypeFinder>().SingleInstance(); 20 builder.Update(container); 21 22 //register dependencies provided by other assemblies 23 builder = new ContainerBuilder(); 24 var drTypes = typeFinder.FindClassesOfType<IDependencyRegistrar>(); 25 var drInstances = new List<IDependencyRegistrar>(); 26 foreach (var drType in drTypes) 27 drInstances.Add((IDependencyRegistrar) Activator.CreateInstance(drType)); 28 //sort 29 drInstances = drInstances.AsQueryable().OrderBy(t => t.Order).ToList(); 30 foreach (var dependencyRegistrar in drInstances) 31 dependencyRegistrar.Register(builder, typeFinder, config);通过反射,按顺序注册依赖 32 builder.Update(container); 33 34 //set dependency resolver 35 DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 36 }
三、NopCommerce的结构分析
1.分析方法
在vs里Solution Explorer的查找栏输入DependencyRegistrar,即可看到所有实现DependencyRegistrar()方法的。
2.总结
2.1 Nop.Core定义了接口;
2.2 Plugins注册自己需要的类;
2.3 Nop.Admin和Nop.Web注册Controller所要使用的缓存类;
2.4 Nop.Web.Framework注册了NopCommerce的核心类。
四、代码分析
1.这里主要分析Nop.Web.Framework的DependencyRegistrar()
1.1.注册http上下文;
1.2.注册web helper、user agent helper;
1.3.注册mvc的controllers;
1.4.注册数据层类,如dbcontext,manager,repository,供持久化层的操作;
1.5.注册插件plugins;
1.6.注册缓存管理的相关类;
1.7.注册work context和store context;
1.8.注册业务层services,部分需注册缓存参数,可以看到WithParameter( ResolvedParameter.ForNamed< ICacheManager >("nop_cache_static" ));
1.9.注册用户事件。
2.代码如下
1 /// <summary> 2 /// Register services and interfaces 3 /// </summary> 4 /// <param name="builder">Container builder</param> 5 /// <param name="typeFinder">Type finder</param> 6 /// <param name="config">Config</param> 7 public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder, NopConfig config) 8 { 9 //HTTP context and other related stuff 10 builder.Register(c => 11 //register FakeHttpContext when HttpContext is not available 12 HttpContext.Current != null ? 13 (new HttpContextWrapper(HttpContext.Current) as HttpContextBase) : 14 (new FakeHttpContext("~/") as HttpContextBase)) 15 .As<HttpContextBase>() 16 .InstancePerLifetimeScope(); 17 builder.Register(c => c.Resolve<HttpContextBase>().Request) 18 .As<HttpRequestBase>() 19 .InstancePerLifetimeScope(); 20 builder.Register(c => c.Resolve<HttpContextBase>().Response) 21 .As<HttpResponseBase>() 22 .InstancePerLifetimeScope(); 23 builder.Register(c => c.Resolve<HttpContextBase>().Server) 24 .As<HttpServerUtilityBase>() 25 .InstancePerLifetimeScope(); 26 builder.Register(c => c.Resolve<HttpContextBase>().Session) 27 .As<HttpSessionStateBase>() 28 .InstancePerLifetimeScope(); 29 30 //web helper 31 builder.RegisterType<WebHelper>().As<IWebHelper>().InstancePerLifetimeScope(); 32 //user agent helper 33 builder.RegisterType<UserAgentHelper>().As<IUserAgentHelper>().InstancePerLifetimeScope(); 34 35 36 //controllers 37 builder.RegisterControllers(typeFinder.GetAssemblies().ToArray()); 38 39 //data layer 40 var dataSettingsManager = new DataSettingsManager(); 41 var dataProviderSettings = dataSettingsManager.LoadSettings(); 42 builder.Register(c => dataSettingsManager.LoadSettings()).As<DataSettings>(); 43 builder.Register(x => new EfDataProviderManager(x.Resolve<DataSettings>())).As<BaseDataProviderManager>().InstancePerDependency(); 44 45 46 builder.Register(x => x.Resolve<BaseDataProviderManager>().LoadDataProvider()).As<IDataProvider>().InstancePerDependency(); 47 48 if (dataProviderSettings != null && dataProviderSettings.IsValid()) 49 { 50 var efDataProviderManager = new EfDataProviderManager(dataSettingsManager.LoadSettings()); 51 var dataProvider = efDataProviderManager.LoadDataProvider(); 52 dataProvider.InitConnectionFactory(); 53 54 builder.Register<IDbContext>(c => new NopObjectContext(dataProviderSettings.DataConnectionString)).InstancePerLifetimeScope(); 55 } 56 else 57 { 58 builder.Register<IDbContext>(c => new NopObjectContext(dataSettingsManager.LoadSettings().DataConnectionString)).InstancePerLifetimeScope(); 59 } 60 61 62 builder.RegisterGeneric(typeof(EfRepository<>)).As(typeof(IRepository<>)).InstancePerLifetimeScope(); 63 64 //plugins 65 builder.RegisterType<PluginFinder>().As<IPluginFinder>().InstancePerLifetimeScope(); 66 builder.RegisterType<OfficialFeedManager>().As<IOfficialFeedManager>().InstancePerLifetimeScope(); 67 68 //cache managers 69 if (config.RedisCachingEnabled) 70 { 71 builder.RegisterType<RedisCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").InstancePerLifetimeScope(); 72 } 73 else 74 { 75 builder.RegisterType<MemoryCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").SingleInstance(); 76 } 77 builder.RegisterType<PerRequestCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_per_request").InstancePerLifetimeScope(); 78 79 if (config.RunOnAzureWebsites) 80 { 81 builder.RegisterType<AzureWebsitesMachineNameProvider>().As<IMachineNameProvider>().SingleInstance(); 82 } 83 else 84 { 85 builder.RegisterType<DefaultMachineNameProvider>().As<IMachineNameProvider>().SingleInstance(); 86 } 87 88 //work context 89 builder.RegisterType<WebWorkContext>().As<IWorkContext>().InstancePerLifetimeScope(); 90 //store context 91 builder.RegisterType<WebStoreContext>().As<IStoreContext>().InstancePerLifetimeScope(); 92 93 //services 94 builder.RegisterType<BackInStockSubscriptionService>().As<IBackInStockSubscriptionService>().InstancePerLifetimeScope(); 95 builder.RegisterType<CategoryService>().As<ICategoryService>().InstancePerLifetimeScope(); 96 builder.RegisterType<CompareProductsService>().As<ICompareProductsService>().InstancePerLifetimeScope(); 97 builder.RegisterType<RecentlyViewedProductsService>().As<IRecentlyViewedProductsService>().InstancePerLifetimeScope(); 98 builder.RegisterType<ManufacturerService>().As<IManufacturerService>().InstancePerLifetimeScope(); 99 builder.RegisterType<PriceFormatter>().As<IPriceFormatter>().InstancePerLifetimeScope(); 100 builder.RegisterType<ProductAttributeFormatter>().As<IProductAttributeFormatter>().InstancePerLifetimeScope(); 101 builder.RegisterType<ProductAttributeParser>().As<IProductAttributeParser>().InstancePerLifetimeScope(); 102 builder.RegisterType<ProductAttributeService>().As<IProductAttributeService>().InstancePerLifetimeScope(); 103 builder.RegisterType<ProductService>().As<IProductService>().InstancePerLifetimeScope(); 104 builder.RegisterType<CopyProductService>().As<ICopyProductService>().InstancePerLifetimeScope(); 105 builder.RegisterType<SpecificationAttributeService>().As<ISpecificationAttributeService>().InstancePerLifetimeScope(); 106 builder.RegisterType<ProductTemplateService>().As<IProductTemplateService>().InstancePerLifetimeScope(); 107 builder.RegisterType<CategoryTemplateService>().As<ICategoryTemplateService>().InstancePerLifetimeScope(); 108 builder.RegisterType<ManufacturerTemplateService>().As<IManufacturerTemplateService>().InstancePerLifetimeScope(); 109 builder.RegisterType<TopicTemplateService>().As<ITopicTemplateService>().InstancePerLifetimeScope(); 110 //use static cache (between HTTP requests) 111 builder.RegisterType<ProductTagService>().As<IProductTagService>() 112 .WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static")) 113 .InstancePerLifetimeScope(); 114 115 builder.RegisterType<AddressAttributeFormatter>().As<IAddressAttributeFormatter>().InstancePerLifetimeScope(); 116 builder.RegisterType<AddressAttributeParser>().As<IAddressAttributeParser>().InstancePerLifetimeScope(); 117 builder.RegisterType<AddressAttributeService>().As<IAddressAttributeService>().InstancePerLifetimeScope(); 118 builder.RegisterType<AddressService>().As<IAddressService>().InstancePerLifetimeScope(); 119 builder.RegisterType<AffiliateService>().As<IAffiliateService>().InstancePerLifetimeScope(); 120 builder.RegisterType<VendorService>().As<IVendorService>().InstancePerLifetimeScope(); 121 builder.RegisterType<SearchTermService>().As<ISearchTermService>().InstancePerLifetimeScope(); 122 builder.RegisterType<GenericAttributeService>().As<IGenericAttributeService>().InstancePerLifetimeScope(); 123 builder.RegisterType<FulltextService>().As<IFulltextService>().InstancePerLifetimeScope(); 124 builder.RegisterType<MaintenanceService>().As<IMaintenanceService>().InstancePerLifetimeScope(); 125 126 127 builder.RegisterType<CustomerAttributeParser>().As<ICustomerAttributeParser>().InstancePerLifetimeScope(); 128 builder.RegisterType<CustomerAttributeService>().As<ICustomerAttributeService>().InstancePerLifetimeScope(); 129 builder.RegisterType<CustomerService>().As<ICustomerService>().InstancePerLifetimeScope(); 130 builder.RegisterType<CustomerRegistrationService>().As<ICustomerRegistrationService>().InstancePerLifetimeScope(); 131 builder.RegisterType<CustomerReportService>().As<ICustomerReportService>().InstancePerLifetimeScope(); 132 133 //use static cache (between HTTP requests) 134 builder.RegisterType<PermissionService>().As<IPermissionService>() 135 .WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static")) 136 .InstancePerLifetimeScope(); 137 //use static cache (between HTTP requests) 138 builder.RegisterType<AclService>().As<IAclService>() 139 .WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static")) 140 .InstancePerLifetimeScope(); 141 //use static cache (between HTTP requests) 142 builder.RegisterType<PriceCalculationService>().As<IPriceCalculationService>() 143 .WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static")) 144 .InstancePerLifetimeScope(); 145 146 builder.RegisterType<GeoLookupService>().As<IGeoLookupService>().InstancePerLifetimeScope(); 147 builder.RegisterType<CountryService>().As<ICountryService>().InstancePerLifetimeScope(); 148 builder.RegisterType<CurrencyService>().As<ICurrencyService>().InstancePerLifetimeScope(); 149 builder.RegisterType<MeasureService>().As<IMeasureService>().InstancePerLifetimeScope(); 150 builder.RegisterType<StateProvinceService>().As<IStateProvinceService>().InstancePerLifetimeScope(); 151 152 builder.RegisterType<StoreService>().As<IStoreService>().InstancePerLifetimeScope(); 153 //use static cache (between HTTP requests) 154 builder.RegisterType<StoreMappingService>().As<IStoreMappingService>() 155 .WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static")) 156 .InstancePerLifetimeScope(); 157 158 builder.RegisterType<DiscountService>().As<IDiscountService>().InstancePerLifetimeScope(); 159 160 161 //use static cache (between HTTP requests) 162 builder.RegisterType<SettingService>().As<ISettingService>() 163 .WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static")) 164 .InstancePerLifetimeScope(); 165 builder.RegisterSource(new SettingsSource()); 166 167 //use static cache (between HTTP requests) 168 builder.RegisterType<LocalizationService>().As<ILocalizationService>() 169 .WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static")) 170 .InstancePerLifetimeScope(); 171 172 //use static cache (between HTTP requests) 173 builder.RegisterType<LocalizedEntityService>().As<ILocalizedEntityService>() 174 .WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static")) 175 .InstancePerLifetimeScope(); 176 builder.RegisterType<LanguageService>().As<ILanguageService>().InstancePerLifetimeScope(); 177 178 builder.RegisterType<DownloadService>().As<IDownloadService>().InstancePerLifetimeScope(); 179 //picture service 180 var useAzureBlobStorage = !String.IsNullOrEmpty(config.AzureBlobStorageConnectionString); 181 if (useAzureBlobStorage) 182 { 183 //Windows Azure BLOB 184 builder.RegisterType<AzurePictureService>().As<IPictureService>().InstancePerLifetimeScope(); 185 } 186 else 187 { 188 //standard file system 189 builder.RegisterType<PictureService>().As<IPictureService>().InstancePerLifetimeScope(); 190 } 191 192 builder.RegisterType<MessageTemplateService>().As<IMessageTemplateService>().InstancePerLifetimeScope(); 193 builder.RegisterType<QueuedEmailService>().As<IQueuedEmailService>().InstancePerLifetimeScope(); 194 builder.RegisterType<NewsLetterSubscriptionService>().As<INewsLetterSubscriptionService>().InstancePerLifetimeScope(); 195 builder.RegisterType<CampaignService>().As<ICampaignService>().InstancePerLifetimeScope(); 196 builder.RegisterType<EmailAccountService>().As<IEmailAccountService>().InstancePerLifetimeScope(); 197 builder.RegisterType<WorkflowMessageService>().As<IWorkflowMessageService>().InstancePerLifetimeScope(); 198 builder.RegisterType<MessageTokenProvider>().As<IMessageTokenProvider>().InstancePerLifetimeScope(); 199 builder.RegisterType<Tokenizer>().As<ITokenizer>().InstancePerLifetimeScope(); 200 builder.RegisterType<EmailSender>().As<IEmailSender>().InstancePerLifetimeScope(); 201 202 builder.RegisterType<CheckoutAttributeFormatter>().As<ICheckoutAttributeFormatter>().InstancePerLifetimeScope(); 203 builder.RegisterType<CheckoutAttributeParser>().As<ICheckoutAttributeParser>().InstancePerLifetimeScope(); 204 builder.RegisterType<CheckoutAttributeService>().As<ICheckoutAttributeService>().InstancePerLifetimeScope(); 205 builder.RegisterType<GiftCardService>().As<IGiftCardService>().InstancePerLifetimeScope(); 206 builder.RegisterType<OrderService>().As<IOrderService>().InstancePerLifetimeScope(); 207 builder.RegisterType<OrderReportService>().As<IOrderReportService>().InstancePerLifetimeScope(); 208 builder.RegisterType<OrderProcessingService>().As<IOrderProcessingService>().InstancePerLifetimeScope(); 209 builder.RegisterType<OrderTotalCalculationService>().As<IOrderTotalCalculationService>().InstancePerLifetimeScope(); 210 builder.RegisterType<ReturnRequestService>().As<IReturnRequestService>().InstancePerLifetimeScope(); 211 builder.RegisterType<RewardPointService>().As<IRewardPointService>().InstancePerLifetimeScope(); 212 builder.RegisterType<ShoppingCartService>().As<IShoppingCartService>().InstancePerLifetimeScope(); 213 214 builder.RegisterType<PaymentService>().As<IPaymentService>().InstancePerLifetimeScope(); 215 216 builder.RegisterType<EncryptionService>().As<IEncryptionService>().InstancePerLifetimeScope(); 217 builder.RegisterType<FormsAuthenticationService>().As<IAuthenticationService>().InstancePerLifetimeScope(); 218 219 220 //use static cache (between HTTP requests) 221 builder.RegisterType<UrlRecordService>().As<IUrlRecordService>() 222 .WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static")) 223 .InstancePerLifetimeScope(); 224 225 builder.RegisterType<ShipmentService>().As<IShipmentService>().InstancePerLifetimeScope(); 226 builder.RegisterType<ShippingService>().As<IShippingService>().InstancePerLifetimeScope(); 227 228 builder.RegisterType<TaxCategoryService>().As<ITaxCategoryService>().InstancePerLifetimeScope(); 229 builder.RegisterType<TaxService>().As<ITaxService>().InstancePerLifetimeScope(); 230 231 builder.RegisterType<DefaultLogger>().As<ILogger>().InstancePerLifetimeScope(); 232 233 //use static cache (between HTTP requests) 234 builder.RegisterType<CustomerActivityService>().As<ICustomerActivityService>() 235 .WithParameter(ResolvedParameter.ForNamed<ICacheManager>("nop_cache_static")) 236 .InstancePerLifetimeScope(); 237 238 bool databaseInstalled = DataSettingsHelper.DatabaseIsInstalled(); 239 if (!databaseInstalled) 240 { 241 //installation service 242 if (config.UseFastInstallationService) 243 { 244 builder.RegisterType<SqlFileInstallationService>().As<IInstallationService>().InstancePerLifetimeScope(); 245 } 246 else 247 { 248 builder.RegisterType<CodeFirstInstallationService>().As<IInstallationService>().InstancePerLifetimeScope(); 249 } 250 } 251 252 builder.RegisterType<ForumService>().As<IForumService>().InstancePerLifetimeScope(); 253 254 builder.RegisterType<PollService>().As<IPollService>().InstancePerLifetimeScope(); 255 builder.RegisterType<BlogService>().As<IBlogService>().InstancePerLifetimeScope(); 256 builder.RegisterType<WidgetService>().As<IWidgetService>().InstancePerLifetimeScope(); 257 builder.RegisterType<TopicService>().As<ITopicService>().InstancePerLifetimeScope(); 258 builder.RegisterType<NewsService>().As<INewsService>().InstancePerLifetimeScope(); 259 260 builder.RegisterType<DateTimeHelper>().As<IDateTimeHelper>().InstancePerLifetimeScope(); 261 builder.RegisterType<SitemapGenerator>().As<ISitemapGenerator>().InstancePerLifetimeScope(); 262 builder.RegisterType<PageHeadBuilder>().As<IPageHeadBuilder>().InstancePerLifetimeScope(); 263 264 builder.RegisterType<ScheduleTaskService>().As<IScheduleTaskService>().InstancePerLifetimeScope(); 265 266 builder.RegisterType<ExportManager>().As<IExportManager>().InstancePerLifetimeScope(); 267 builder.RegisterType<ImportManager>().As<IImportManager>().InstancePerLifetimeScope(); 268 builder.RegisterType<PdfService>().As<IPdfService>().InstancePerLifetimeScope(); 269 builder.RegisterType<ThemeProvider>().As<IThemeProvider>().InstancePerLifetimeScope(); 270 builder.RegisterType<ThemeContext>().As<IThemeContext>().InstancePerLifetimeScope(); 271 272 273 builder.RegisterType<ExternalAuthorizer>().As<IExternalAuthorizer>().InstancePerLifetimeScope(); 274 builder.RegisterType<OpenAuthenticationService>().As<IOpenAuthenticationService>().InstancePerLifetimeScope(); 275 276 277 builder.RegisterType<RoutePublisher>().As<IRoutePublisher>().SingleInstance(); 278 279 //Register event consumers 280 var consumers = typeFinder.FindClassesOfType(typeof(IConsumer<>)).ToList(); 281 foreach (var consumer in consumers) 282 { 283 builder.RegisterType(consumer) 284 .As(consumer.FindInterfaces((type, criteria) => 285 { 286 var isMatch = type.IsGenericType && ((Type)criteria).IsAssignableFrom(type.GetGenericTypeDefinition()); 287 return isMatch; 288 }, typeof(IConsumer<>))) 289 .InstancePerLifetimeScope(); 290 } 291 builder.RegisterType<EventPublisher>().As<IEventPublisher>().SingleInstance(); 292 builder.RegisterType<SubscriptionService>().As<ISubscriptionService>().SingleInstance(); 293 294 }