zoukankan      html  css  js  c++  java
  • NOP源码分析 一

    新建Nop.Web项目(framework4.51),解决方案:NopCommerce.解决方案下创建解决方案文件夹:Presentation,拖拽Nop.Web到里面。

    源项目Global.asax.cs注册路由的代码:

    public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("favicon.ico");
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
                
                //register custom routes (plugins, etc)
                var routePublisher = EngineContext.Current.Resolve<IRoutePublisher>();
                routePublisher.RegisterRoutes(routes);
                
                routes.MapRoute(
                    "Default", // Route name
                    "{controller}/{action}/{id}", // URL with parameters
                    new { controller = "Home", action = "Index", id = UrlParameter.Optional },
                    new[] { "Nop.Web.Controllers" }
                );
            }

    新项目路由放到了App_Start/RouteConfig.cs下。注释掉以前的 黏贴以上代码。

    IgnoreRoute是忽略的路由URL。

    EngineContext在Nop.Core项目下,current方法:

    public static IEngine Current
            {
                get
                {
                    if (Singleton<IEngine>.Instance == null)
                    {
                        Initialize(false);
                    }
                    return Singleton<IEngine>.Instance;
                }
            }

    返回一个单例的NOP引擎。其中Initialize(false);方法应该是初始化引擎的。如下:

    [MethodImpl(MethodImplOptions.Synchronized)]
            public static IEngine Initialize(bool forceRecreate)
            {
                if (Singleton<IEngine>.Instance == null || forceRecreate)
                {
                    var config = ConfigurationManager.GetSection("NopConfig") as NopConfig;
                    Singleton<IEngine>.Instance = CreateEngineInstance(config);
                    Singleton<IEngine>.Instance.Initialize(config);
                }
                return Singleton<IEngine>.Instance;
            }

    其中[MethodImpl(MethodImplOptions.Synchronized)]是一个表示此方法一次只能有一个线程执行.

    比3.4版本少了debug(Debug.WriteLine("Constructing engine " + DateTime.Now);)代码。其中 nopconfig加载配置,代码如下:

    namespace Nop.Core.Configuration
    {
        /// <summary>
        /// Represents a NopConfig
        /// </summary>
        public partial class NopConfig : IConfigurationSectionHandler
        {
            /// <summary>
            /// Creates a configuration section handler.
            /// </summary>
            /// <param name="parent">Parent object.</param>
            /// <param name="configContext">Configuration context object.</param>
            /// <param name="section">Section XML node.</param>
            /// <returns>The created section handler object.</returns>
            public object Create(object parent, object configContext, XmlNode section)
            {
                var config = new NopConfig();
                var dynamicDiscoveryNode = section.SelectSingleNode("DynamicDiscovery");
                if (dynamicDiscoveryNode != null && dynamicDiscoveryNode.Attributes != null)
                {
                    var attribute = dynamicDiscoveryNode.Attributes["Enabled"];
                    if (attribute != null)
                        config.DynamicDiscovery = Convert.ToBoolean(attribute.Value);
                }
    
                var engineNode = section.SelectSingleNode("Engine");
                if (engineNode != null && engineNode.Attributes != null)
                {
                    var attribute = engineNode.Attributes["Type"];
                    if (attribute != null)
                        config.EngineType = attribute.Value;
                }
    
                var startupNode = section.SelectSingleNode("Startup");
                if (startupNode != null && startupNode.Attributes != null)
                {
                    var attribute = startupNode.Attributes["IgnoreStartupTasks"];
                    if (attribute != null)
                        config.IgnoreStartupTasks = Convert.ToBoolean(attribute.Value);
                }
    
                var themeNode = section.SelectSingleNode("Themes");
                if (themeNode != null && themeNode.Attributes != null)
                {
                    var attribute = themeNode.Attributes["basePath"];
                    if (attribute != null)
                        config.ThemeBasePath = attribute.Value;
                }
    
                var userAgentStringsNode = section.SelectSingleNode("UserAgentStrings");
                if (userAgentStringsNode != null && userAgentStringsNode.Attributes != null)
                {
                    var attribute = userAgentStringsNode.Attributes["databasePath"];
                    if (attribute != null)
                        config.UserAgentStringsPath = attribute.Value;
                }
    
                return config;
            }
            
            /// <summary>
            /// In addition to configured assemblies examine and load assemblies in the bin directory.
            /// </summary>
            public bool DynamicDiscovery { get; private set; }
    
            /// <summary>
            /// A custom <see cref="IEngine"/> to manage the application instead of the default.
            /// </summary>
            public string EngineType { get; private set; }
    
            /// <summary>
            /// Specifices where the themes will be stored (~/Themes/)
            /// </summary>
            public string ThemeBasePath { get; private set; }
    
            /// <summary>
            /// Indicates whether we should ignore startup tasks
            /// </summary>
            public bool IgnoreStartupTasks { get; private set; }
    
            /// <summary>
            /// Path to database with user agent strings
            /// </summary>
            public string UserAgentStringsPath { get; private set; }
        }
    }

    web.config

    <section name="NopConfig" type="Nop.Core.Configuration.NopConfig, Nop.Core" requirePermission="false" />
        <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
        <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
        <!-- image resizer -->
        <section name="resizer" type="ImageResizer.ResizerSection,ImageResizer" requirePermission="false" />
      </configSections>
      <NopConfig>
        <DynamicDiscovery Enabled="true" />
        <Engine Type="" />
        <Themes basePath="~/Themes/" />
        <!-- you can get the latest version of user agent strings at http://user-agent-string.info/ -->
        <UserAgentStrings databasePath="~/App_Data/uas_20140809-02.ini" />
      </NopConfig>

    注意加粗的配置内容。

    然后调用CreateEngineInstance方法

    /// <summary>
            /// Creates a factory instance and adds a http application injecting facility.
            /// </summary>
            /// <param name="config">Config</param>
            /// <returns>New engine instance</returns>
            protected static IEngine CreateEngineInstance(NopConfig config)
            {
                if (config != null && !string.IsNullOrEmpty(config.EngineType))
                {
                    var engineType = Type.GetType(config.EngineType);
                    if (engineType == null)
                        throw new ConfigurationErrorsException("The type '" + config.EngineType + "' could not be found. Please check the configuration at /configuration/nop/engine[@engineType] or check for missing assemblies.");
                    if (!typeof(IEngine).IsAssignableFrom(engineType))
                        throw new ConfigurationErrorsException("The type '" + engineType + "' doesn't implement 'Nop.Core.Infrastructure.IEngine' and cannot be configured in /configuration/nop/engine[@engineType] for that purpose.");
                    return Activator.CreateInstance(engineType) as IEngine;
                }
    
                return new NopEngine();
            }

    因为配置文件里<Engine Type="" />  所以!string.IsNullOrEmpty(config.EngineType)) 返回false,不运行内部代码,也就是说可以用自己写的引擎,而不是nopEngine,但这里直接返回NopEngine.

    而NopEngine的代码如下:        没有构造函数,也就是说NopEngine()  只是返回了一个IEngine,并没有做其他的事情。

    public class NopEngine : IEngine
        {
            #region Fields
    
            private ContainerManager _containerManager;
    
            #endregion
    
            #region Utilities
    
            /// <summary>
            /// Run startup tasks
            /// </summary>
            protected virtual void RunStartupTasks()
            {
                var typeFinder = _containerManager.Resolve<ITypeFinder>();
                var startUpTaskTypes = typeFinder.FindClassesOfType<IStartupTask>();
                var startUpTasks = new List<IStartupTask>();
                foreach (var startUpTaskType in startUpTaskTypes)
                    startUpTasks.Add((IStartupTask)Activator.CreateInstance(startUpTaskType));
                //sort
                startUpTasks = startUpTasks.AsQueryable().OrderBy(st => st.Order).ToList();
                foreach (var startUpTask in startUpTasks)
                    startUpTask.Execute();
            }
    
            /// <summary>
            /// Register dependencies
            /// </summary>
            /// <param name="config">Config</param>
            protected virtual void RegisterDependencies(NopConfig config)
            {
                var builder = new ContainerBuilder();
                var container = builder.Build();
    
                //we create new instance of ContainerBuilder
                //because Build() or Update() method can only be called once on a ContainerBuilder.
    
    
                //dependencies
                var typeFinder = new WebAppTypeFinder(config);
                builder = new ContainerBuilder();
                builder.RegisterInstance(config).As<NopConfig>().SingleInstance();
                builder.RegisterInstance(this).As<IEngine>().SingleInstance();
                builder.RegisterInstance(typeFinder).As<ITypeFinder>().SingleInstance();
                builder.Update(container);
    
                //register dependencies provided by other assemblies
                builder = new ContainerBuilder();
                var drTypes = typeFinder.FindClassesOfType<IDependencyRegistrar>();
                var drInstances = new List<IDependencyRegistrar>();
                foreach (var drType in drTypes)
                    drInstances.Add((IDependencyRegistrar) Activator.CreateInstance(drType));
                //sort
                drInstances = drInstances.AsQueryable().OrderBy(t => t.Order).ToList();
                foreach (var dependencyRegistrar in drInstances)
                    dependencyRegistrar.Register(builder, typeFinder);
                builder.Update(container);
    
    
                this._containerManager = new ContainerManager(container);
                
                //set dependency resolver
                DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
            }
    
            #endregion
    
            #region Methods
            
            /// <summary>
            /// Initialize components and plugins in the nop environment.
            /// </summary>
            /// <param name="config">Config</param>
            public void Initialize(NopConfig config)
            {
                //register dependencies
                RegisterDependencies(config);
    
                //startup tasks
                if (!config.IgnoreStartupTasks)
                {
                    RunStartupTasks();
                }
    
            }
    
            /// <summary>
            /// Resolve dependency
            /// </summary>
            /// <typeparam name="T">T</typeparam>
            /// <returns></returns>
            public T Resolve<T>() where T : class
            {
                return ContainerManager.Resolve<T>();
            }
    
            /// <summary>
            ///  Resolve dependency
            /// </summary>
            /// <param name="type">Type</param>
            /// <returns></returns>
            public object Resolve(Type type)
            {
                return ContainerManager.Resolve(type);
            }
            
            /// <summary>
            /// Resolve dependencies
            /// </summary>
            /// <typeparam name="T">T</typeparam>
            /// <returns></returns>
            public T[] ResolveAll<T>()
            {
                return ContainerManager.ResolveAll<T>();
            }
    
            #endregion
    
            #region Properties
    
            /// <summary>
            /// Container manager
            /// </summary>
            public ContainerManager ContainerManager
            {
                get { return _containerManager; }
            }
    
            #endregion
        }

    然后看Singleton<IEngine>.Instance = CreateEngineInstance(config); Singleton<IEngine>.Instance.Initialize(config); 这2句做了什么。

    单例Singleton定义如下:

    namespace Nop.Core.Infrastructure
    {
        /// <summary>
        /// A statically compiled "singleton" used to store objects throughout the 
        /// lifetime of the app domain. Not so much singleton in the pattern's 
        /// sense of the word as a standardized way to store single instances.
        /// </summary>
        /// <typeparam name="T">The type of object to store.</typeparam>
        /// <remarks>Access to the instance is not synchrnoized.</remarks>
        public class Singleton<T> : Singleton
        {
            static T instance;
    
            /// <summary>The singleton instance for the specified type T. Only one instance (at the time) of this object for each type of T.</summary>
            public static T Instance
            {
                get { return instance; }
                set
                {
                    instance = value;
                    AllSingletons[typeof(T)] = value;
                }
            }
        }
    
        /// <summary>
        /// Provides a singleton list for a certain type.
        /// </summary>
        /// <typeparam name="T">The type of list to store.</typeparam>
        public class SingletonList<T> : Singleton<IList<T>>
        {
            static SingletonList()
            {
                Singleton<IList<T>>.Instance = new List<T>();
            }
    
            /// <summary>The singleton instance for the specified type T. Only one instance (at the time) of this list for each type of T.</summary>
            public new static IList<T> Instance
            {
                get { return Singleton<IList<T>>.Instance; }
            }
        }
    
        /// <summary>
        /// Provides a singleton dictionary for a certain key and vlaue type.
        /// </summary>
        /// <typeparam name="TKey">The type of key.</typeparam>
        /// <typeparam name="TValue">The type of value.</typeparam>
        public class SingletonDictionary<TKey, TValue> : Singleton<IDictionary<TKey, TValue>>
        {
            static SingletonDictionary()
            {
                Singleton<Dictionary<TKey, TValue>>.Instance = new Dictionary<TKey, TValue>();
            }
    
            /// <summary>The singleton instance for the specified type T. Only one instance (at the time) of this dictionary for each type of T.</summary>
            public new static IDictionary<TKey, TValue> Instance
            {
                get { return Singleton<Dictionary<TKey, TValue>>.Instance; }
            }
        }
    
        /// <summary>
        /// Provides access to all "singletons" stored by <see cref="Singleton{T}"/>.
        /// </summary>
        public class Singleton
        {
            static Singleton()
            {
                allSingletons = new Dictionary<Type, object>();
            }
    
            static readonly IDictionary<Type, object> allSingletons;
    
            /// <summary>Dictionary of type to singleton instances.</summary>
            public static IDictionary<Type, object> AllSingletons
            {
                get { return allSingletons; }
            }
        }
    }

    其中赋值的代码如下:

    public static T Instance
            {
                get { return instance; }
                set
                {
                    instance = value;
                    AllSingletons[typeof(T)] = value;
                }
            }

    instance = value; 是对IEngine进行赋值(NopEngine).  AllSingletons[typeof(T)] = value; 的AllSingletons是一个只读的字典类型,是继承得到的 如下:Singleton<T>继承自Singleton

    public class Singleton
        {
            static Singleton()
            {
                allSingletons = new Dictionary<Type, object>();
            }
    
            static readonly IDictionary<Type, object> allSingletons;
    
            /// <summary>Dictionary of type to singleton instances.</summary>
            public static IDictionary<Type, object> AllSingletons
            {
                get { return allSingletons; }
            }
        }

    查了下 readonly:

    你不可以在程序中变更变量指向的对象,但是可以改变对象内部存储的内容。
    所以添加元素是没有问题的。
    当然还有Singleton<IEngine>.Instance.Initialize(config);调用NopEngine的Initialize方法:
    /// <summary>
            /// Initialize components and plugins in the nop environment.
            /// </summary>
            /// <param name="config">Config</param>
            public void Initialize(NopConfig config)
            {
                //register dependencies
                RegisterDependencies(config);
    
                //startup tasks
                if (!config.IgnoreStartupTasks)
                {
                    RunStartupTasks();
                }
    
            }

    RegisterDependencies(config);应该是注册依赖,代码如下:

    /// <summary>
            /// Register dependencies
            /// </summary>
            /// <param name="config">Config</param>
            protected virtual void RegisterDependencies(NopConfig config)
            {
                var builder = new ContainerBuilder();
                var container = builder.Build();
    
                //we create new instance of ContainerBuilder
                //because Build() or Update() method can only be called once on a ContainerBuilder.
    
    
                //dependencies
                var typeFinder = new WebAppTypeFinder(config);
                builder = new ContainerBuilder();
                builder.RegisterInstance(config).As<NopConfig>().SingleInstance();
                builder.RegisterInstance(this).As<IEngine>().SingleInstance();
                builder.RegisterInstance(typeFinder).As<ITypeFinder>().SingleInstance();
                builder.Update(container);
    
                //register dependencies provided by other assemblies
                builder = new ContainerBuilder();
                var drTypes = typeFinder.FindClassesOfType<IDependencyRegistrar>();
                var drInstances = new List<IDependencyRegistrar>();
                foreach (var drType in drTypes)
                    drInstances.Add((IDependencyRegistrar) Activator.CreateInstance(drType));
                //sort
                drInstances = drInstances.AsQueryable().OrderBy(t => t.Order).ToList();
                foreach (var dependencyRegistrar in drInstances)
                    dependencyRegistrar.Register(builder, typeFinder);
                builder.Update(container);
    
    
                this._containerManager = new ContainerManager(container);
                
                //set dependency resolver
                DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
            }

    ContainerBuilder是Autofac的类。终于到依赖注入Autofac

    参考:http://www.cnblogs.com/liping13599168/archive/2011/07/16/2108209.html

    从名字也能判断出:ContainerBuilder是Autofac的一个构建容器。

    var container = builder.Build(); 直接构建一个容器。

    然后看var typeFinder = new WebAppTypeFinder(config);  类的代码如下:

    namespace Nop.Core.Infrastructure
    {
        /// <summary>
        /// Provides information about types in the current web application. 
        /// Optionally this class can look at all assemblies in the bin folder.
        /// </summary>
        public class WebAppTypeFinder : AppDomainTypeFinder
        {
            #region Fields
    
            private bool _ensureBinFolderAssembliesLoaded = true;
            private bool _binFolderAssembliesLoaded;
    
            #endregion
    
            #region Ctor
    
            public WebAppTypeFinder(NopConfig config)
            {
                this._ensureBinFolderAssembliesLoaded = config.DynamicDiscovery;
            }
    
            #endregion
    
            #region Properties
    
            /// <summary>
            /// Gets or sets wether assemblies in the bin folder of the web application should be specificly checked for beeing loaded on application load. This is need in situations where plugins need to be loaded in the AppDomain after the application been reloaded.
            /// </summary>
            public bool EnsureBinFolderAssembliesLoaded
            {
                get { return _ensureBinFolderAssembliesLoaded; }
                set { _ensureBinFolderAssembliesLoaded = value; }
            }
            
            #endregion
    
            #region Methods
    
            /// <summary>
            /// Gets a physical disk path of Bin directory
            /// </summary>
            /// <returns>The physical path. E.g. "c:inetpubwwwrootin"</returns>
            public virtual string GetBinDirectory()
            {
                if (HostingEnvironment.IsHosted)
                {
                    //hosted
                    return HttpRuntime.BinDirectory;
                }
    
                //not hosted. For example, run either in unit tests
                return AppDomain.CurrentDomain.BaseDirectory;
            }
    
            public override IList<Assembly> GetAssemblies()
            {
                if (this.EnsureBinFolderAssembliesLoaded && !_binFolderAssembliesLoaded)
                {
                    _binFolderAssembliesLoaded = true;
                    string binPath = GetBinDirectory();
                    //binPath = _webHelper.MapPath("~/bin");
                    LoadMatchingAssemblies(binPath);
                }
    
                return base.GetAssemblies();
            }
    
            #endregion
        }
    }

    构造如下:

    public WebAppTypeFinder(NopConfig config)
            {
                this._ensureBinFolderAssembliesLoaded = config.DynamicDiscovery;
            }

    <DynamicDiscovery Enabled="true" />

    设置ensureBinFolderAssembliesLoaded 为true.

    多次 new ContainerBuilder()的原因是:新建一个实例,是因为Build/Update一个实例只能用一次

    builder.RegisterInstance(config).As<NopConfig>().SingleInstance();
                builder.RegisterInstance(this).As<IEngine>().SingleInstance();
                builder.RegisterInstance(typeFinder).As<ITypeFinder>().SingleInstance();
                builder.Update(container);

    注册NopConfig、NopEngine/WebAppTypeFinder

  • 相关阅读:
    域渗透基础(二)
    域渗透基础(一)
    域环境搭建
    java基础(五)-----new一个对象的具体过程
    数据结构(八)-----散列表
    数据结构(七)-----跳表
    数据结构(六)-----队列
    数据结构(五)-----栈
    数据结构(四)-----链表
    数据结构(三)-----数组
  • 原文地址:https://www.cnblogs.com/runit/p/4164959.html
Copyright © 2011-2022 走看看