美文网首页
阅读nopcommerce startup源码

阅读nopcommerce startup源码

作者: dotNET知音 | 来源:发表于2019-07-31 09:05 被阅读0次
    创建一个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);
            }
    

    ok,到此这两个文件的源码已经过完了,我们几个类比较陌生,我们一一介绍下

    • 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比较成熟。

    微信公众号:dotNET知音

    相关文章

      网友评论

          本文标题:阅读nopcommerce startup源码

          本文链接:https://www.haomeiwen.com/subject/fnforctx.html