閱讀nopcommerce startup源碼


創建一個asp.net core項目,可以到到startup類有兩個方法
 // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) 
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) 

ConfigureServices方法:注冊服務到容器中,在整個應用中都可以使用。推薦:自定義方法以Add開頭 Configure方法:為應用配置請求管道.推薦:自定義方法以Use開頭

這里並會深入的探討依賴注入和IApplicationBuilder、IServiceCollection這些核心對象,這篇文章主要目的是快速的了解startup類和如何利用一些開源的項目(nopcommerce)去使用它。

nopcommerce是個優秀的開源的電商項目,應該都不會陌生,不管有沒有項目中用到,但不妨礙我們去閱讀學習他們優秀的地方。

一起先了解下項目結構 

  • Nop.Core 核心層 :包含領域模型、和基礎設施層(緩存、倉儲接口、依賴注入、對象映射mapper等)、一些其他工具里的封裝
  • Nop.Data 數據層:orm與數據庫的一些操作,倉儲實現類,領域和表的映射等
  • Nop.Services 應用服務層:業務服務操作
  • Plugins 插件:nop 是插件式開發 ,擴展起來很是方便
  • Nop.Web 表現層:ui交互
  • Nop.Web.Framework:對asp.netcore mvc 進行一些擴展和封裝

在回到今天的主角startup類 我進入Nop.Web項目 打開startup類

 public class Startup { #region Fields private readonly IConfiguration _configuration; private readonly IHostingEnvironment _hostingEnvironment; #endregion #region Ctor public Startup(IConfiguration configuration, IHostingEnvironment hostingEnvironment) { _configuration = configuration; _hostingEnvironment = hostingEnvironment; } #endregion /// <summary> /// Add services to the application and configure service provider /// </summary> /// <param name="services">Collection of service descriptors</param> public IServiceProvider ConfigureServices(IServiceCollection services) { return services.ConfigureApplicationServices(_configuration, _hostingEnvironment); } /// <summary> /// Configure the application HTTP request pipeline /// </summary> /// <param name="application">Builder for configuring an application's request pipeline</param> public void Configure(IApplicationBuilder application) { application.ConfigureRequestPipeline(); } } 

是不是很簡潔,可以發現nop對IServiceCollection、IApplicationBuilder進行擴展了兩個方法類 分別ServiceCollectionExtensions、ApplicationBuilderExtensions,下面我們分別快速的瀏覽這兩個類的源碼

我們F12進入ConfigureApplicationServices的實現方式一步一步的查看

 var engine = EngineContext.Create(); //創建NopEngine var serviceProvider = engine.ConfigureServices(services, configuration); 
  //find startup configurations provided by other assemblies var typeFinder = new WebAppTypeFinder(); //反射工具類 var startupConfigurations = typeFinder.FindClassesOfType<INopStartup>(); //create and sort instances of startup configurations var instances = startupConfigurations .Select(startup => (INopStartup)Activator.CreateInstance(startup)) .OrderBy(startup => startup.Order); ////configure services foreach (var instance in instances) instance.ConfigureServices(services, configuration); ////register mapper configurations //AddAutoMapper(services, typeFinder); //register dependencies RegisterDependencies(services, typeFinder); 
protected virtual IServiceProvider RegisterDependencies(IServiceCollection services, ITypeFinder typeFinder) { var containerBuilder = new ContainerBuilder(); //Autofac //register engine containerBuilder.RegisterInstance(this).As<IEngine>().SingleInstance(); //register type finder containerBuilder.RegisterInstance(typeFinder).As<ITypeFinder>().SingleInstance(); //populate Autofac container builder with the set of registered service descriptors containerBuilder.Populate(services); //find dependency registrars provided by other assemblies var dependencyRegistrars = typeFinder.FindClassesOfType<IDependencyRegistrar>(); //create and sort instances of dependency registrars var instances = dependencyRegistrars .Select(dependencyRegistrar => (IDependencyRegistrar)Activator.CreateInstance(dependencyRegistrar)) .OrderBy(dependencyRegistrar => dependencyRegistrar.Order); //register all provided dependencies foreach (var dependencyRegistrar in instances) dependencyRegistrar.Register(containerBuilder, typeFinder); //create service provider _serviceProvider = new AutofacServiceProvider(containerBuilder.Build()); return _serviceProvider; } 

F12進入ConfigureRequestPipeline

  EngineContext.Current.ConfigureRequestPipeline(application); 
 public void ConfigureRequestPipeline(IApplicationBuilder application) { //find startup configurations provided by other assemblies var typeFinder = Resolve<ITypeFinder>(); var startupConfigurations = typeFinder.FindClassesOfType<INopStartup>(); //create and sort instances of startup configurations var instances = startupConfigurations .Select(startup => (INopStartup)Activator.CreateInstance(startup)) .OrderBy(startup => startup.Order); //configure request pipeline foreach (var instance in instances) instance.Configure(application); } 

到此這兩個文件的源碼已經過完了,覺得很核心的幾個對象

  • EngineContext: NopEngine的實例上下文 作用 獲取創建和獲取NopEngine的實例上下文的實例(涉及到的設計模式單例)
  • IEngine、NopEngine: nop引擎還是很體貼的,里面封裝了使用的方法如ioc 解析方法Resolve
  • INopStartup :在應用程序啟動時配置服務和中間件 當時我看過源碼,有幾處還是很巧妙的,下面我整理下,多個為什么,帶着問題去看,印象更深刻,也達到了參考nop源碼學習startup類的目的。
  1. 接口INopStartup作用? INopStartup有兩個方法ConfigureServices,Configure 跟Startup方法作用都是一樣的,nop把它抽離成接口的好處,可以很方便通過反射把實現INopStartup的類查找出來,然后掉用ConfigureServices,Configure方法
 //find startup configurations provided by other assemblies
            var typeFinder = new WebAppTypeFinder(); var startupConfigurations = typeFinder.FindClassesOfType<INopStartup>(); //create and sort instances of startup configurations var instances = startupConfigurations  .Select(startup => (INopStartup)Activator.CreateInstance(startup))  .OrderBy(startup => startup.Order); ////configure services foreach (var instance in instances) instance.ConfigureServices(services, configuration); //configure request pipeline foreach (var instance in instances) instance.Configure(application); 
  1. nop使用Autofac作為注入框架,它是如何實現的
     var containerBuilder = new ContainerBuilder(); //register engine containerBuilder.RegisterInstance(this).As<IEngine>().SingleInstance(); //create service provider _serviceProvider = new AutofacServiceProvider(containerBuilder.Build()); return _serviceProvider; 
  1. 接口IEngine的作用? 配置startup 服務和請求管道、autofac注冊和解析
IServiceProvider ConfigureServices(IServiceCollection services, IConfiguration configuration); void ConfigureRequestPipeline(IApplicationBuilder application); T Resolve<T>() where T : class; 
  1. 如何使用注入的服務?

1.我們在Nop.Services項目中添加ProductService和ProductAttributeService兩個業務服務

    public class ProductService : IProductService { public string GetProductById(int productId) { return "獲取產品"; } } public class ProductAttributeService: IProductAttributeService { public string GetProductAttributeById(int productAttributeId) { return "獲取產品屬性"; } } 

2.我們實現IDependencyRegistrar依賴注冊接口

 public class DependencyRegistrar : IDependencyRegistrar { /// <summary> /// Register services and interfaces /// </summary> /// <param name="builder">Container builder</param> /// <param name="typeFinder">Type finder</param> public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder) { //file provider builder.RegisterType<NopFileProvider>().As<INopFileProvider>().InstancePerLifetimeScope(); //data layer //repositories //services builder.RegisterType<ProductAttributeService>().As<IProductAttributeService>().InstancePerLifetimeScope(); builder.RegisterType<ProductService>().As<IProductService>().InstancePerLifetimeScope(); } /// <summary> /// Gets order of this dependency registrar implementation /// </summary> public int Order => 0; } 

3.然后在homecontroller中測試,第一種構造函數注入,第二種直接使用IEngine的實例解析

       #region fileds private readonly IProductService productService; #endregion public HomeController(IProductService productService) { this.productService = productService; } public IActionResult Index() { //利用EngineContex進行解析 var productAttributeService = EngineContext.Current.Resolve<IProductAttributeService>(); ViewBag.result = this.productService.GetProductById(1); ViewBag.result2 = productAttributeService.GetProductAttributeById(1); return View(); } 

然后運行查看效果

解析成功,展示的只是本分代碼,實例代碼上傳到github上,喜歡的可以clone下來,自己調試調試,稍微調整下,放心用在自己的項目中,因為nop已經比較成熟了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM