阅读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是个优秀的开源的电商项目,应该都不会陌生,不管有没有项目中用到,但不妨碍我们去阅读学习他们优秀的地方。

一起先了解下项目结构 阅读nopcommerce startup源码_第1张图片

  • 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 ///  /// Add services to the application and configure service provider ///  /// Collection of service descriptors public IServiceProvider ConfigureServices(IServiceCollection services) { return services.ConfigureApplicationServices(_configuration, _hostingEnvironment); } ///  /// Configure the application HTTP request pipeline ///  /// Builder for configuring an application's request pipeline 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(); //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().SingleInstance(); //register type finder containerBuilder.RegisterInstance(typeFinder).As().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(); //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();
            var startupConfigurations = typeFinder.FindClassesOfType(); //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();

            //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().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() 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
    {
        ///  /// Register services and interfaces ///  /// Container builder /// Type finder public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder) { //file provider builder.RegisterType().As().InstancePerLifetimeScope(); //data layer //repositories //services builder.RegisterType().As().InstancePerLifetimeScope(); builder.RegisterType().As().InstancePerLifetimeScope(); } ///  /// Gets order of this dependency registrar implementation ///  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(); ViewBag.result = this.productService.GetProductById(1); ViewBag.result2 = productAttributeService.GetProductAttributeById(1); return View(); } 

然后运行查看效果

阅读nopcommerce startup源码_第2张图片

解析成功,展示的只是本分代码,实例代码上传到github上,喜欢的可以clone下来,自己调试调试,稍微调整下,放心用在自己的项目中,因为nop已经比较成熟了。

你可能感兴趣的:(阅读nopcommerce startup源码)