惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Engineering at Meta
Engineering at Meta
月光博客
月光博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
Visual Studio Blog
大猫的无限游戏
大猫的无限游戏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
量子位
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
腾讯CDC
S
Securelist
Know Your Adversary
Know Your Adversary
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - 【当耐特】
V2EX - 技术
V2EX - 技术
J
Java Code Geeks
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Hugging Face - Blog
Hugging Face - Blog
Cisco Talos Blog
Cisco Talos Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
阮一峰的网络日志
阮一峰的网络日志
美团技术团队
W
WeLiveSecurity
S
SegmentFault 最新的问题
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
宝玉的分享
宝玉的分享
博客园 - Franky
S
Security Affairs
博客园 - 司徒正美
V
V2EX
K
Kaspersky official blog
T
Threatpost
NISL@THU
NISL@THU
博客园 - 叶小钗
Help Net Security
Help Net Security
PCI Perspectives
PCI Perspectives
IT之家
IT之家
小众软件
小众软件
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Last Week in AI
Last Week in AI
Jina AI
Jina AI
爱范儿
爱范儿
罗磊的独立博客
N
News and Events Feed by Topic
博客园 - 三生石上(FineUI控件)
有赞技术团队
有赞技术团队
P
Proofpoint News Feed
L
LINUX DO - 热门话题
Google Online Security Blog
Google Online Security Blog
雷峰网
雷峰网
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint

博客园 - 大西瓜3721

SVN分支/合并原理及最佳实践 Web.Config中Runtime节点-DLL版本冲突问题 工作问题 Vue资料 轻松实现WCF服务的构造函数依赖注入 WCF 依赖注入-- Attribute MVC视图分析 C#简单枚举和标志枚举的用法和区别 XDate Admin.NET框架资料 日志管理之log4net+Autofac 关于NopCommerce3.6版用户登录详解 AutoFac注册的动态实例 Named和Keyed NOP源码分析 六 NOP源码分析五---set的存储 NOP源码分析四 Nop源码分析三 NOP源码分析 一 NopCommerce的资料 IServiceCollection和IServiceProvider 控制反转——Autofac框架 精选10款C#/.NET开发必备类库 11个免费开源后台管理系统模板 H5连接蓝牙打印机打印小票 自定义控件 - 流式布局:TagFlowLayout MVC开源CMS nginx的安装&一个最简单的配置(windows和Centos) DNS解析
NOP源码分析 二
大西瓜3721 · 2026-03-15 · via 博客园 - 大西瓜3721

昨天研究到:

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

注册NopConfig、NopEngine/WebAppTypeFinder

-------------------------------------------接着往下-------------------------------------------------

var drTypes = typeFinder.FindClassesOfType<IDependencyRegistrar>();  这一句根据类名可知道,是根据给定类型(接口),获得类 就是获得IDependencyRegistrar类,其实就是一个依赖注入类。通过多态,最终调用的代码:return FindClassesOfType(assignTypeFrom, GetAssemblies(), onlyConcreteClasses);

其中获得集合代码:

复制代码

/// <summary>Gets the assemblies related to the current implementation.</summary>
        /// <returns>A list of assemblies that should be loaded by the Nop factory.</returns>
        public virtual IList<Assembly> GetAssemblies()
        {
            var addedAssemblyNames = new List<string>();
            var assemblies = new List<Assembly>();

            if (LoadAppDomainAssemblies)
                AddAssembliesInAppDomain(addedAssemblyNames, assemblies);
            AddConfiguredAssemblies(addedAssemblyNames, assemblies);

            return assemblies;
        }

复制代码

private bool ignoreReflectionErrors = true;
        private bool loadAppDomainAssemblies = true;
        private string assemblySkipLoadingPattern = "^System|^mscorlib|^Microsoft|^AjaxControlToolkit|^Antlr3|^Autofac|^AutoMapper|^Castle|^ComponentArt|^CppCodeProvider|^DotNetOpenAuth|^EntityFramework|^EPPlus|^FluentValidation|^ImageResizer|^itextsharp|^log4net|^MaxMind|^MbUnit|^MiniProfiler|^Mono.Math|^MvcContrib|^Newtonsoft|^NHibernate|^nunit|^Org.Mentalis|^PerlRegex|^QuickGraph|^Recaptcha|^Remotion|^RestSharp|^Rhino|^Telerik|^Iesi|^TestDriven|^TestFu|^UserAgentStringLibrary|^VJSharpCodeProvider|^WebActivator|^WebDev|^WebGrease";
        private string assemblyRestrictToLoadingPattern = ".*";

这是声明时默认设置, 执行

AddAssembliesInAppDomain(addedAssemblyNames, assemblies);代码如下:

复制代码

/// <summary>
        /// Iterates all assemblies in the AppDomain and if it's name matches the configured patterns add it to our list.迭代所有AppDomain的类库,
        /// </summary>
        /// <param name="addedAssemblyNames"></param>
        /// <param name="assemblies"></param>
        private void AddAssembliesInAppDomain(List<string> addedAssemblyNames, List<Assembly> assemblies)
        {
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (Matches(assembly.FullName))
                {
                    if (!addedAssemblyNames.Contains(assembly.FullName))
                    {
                        assemblies.Add(assembly);
                        addedAssemblyNames.Add(assembly.FullName);
                    }
                }
            }
        }

复制代码

其中Matches调用

复制代码

public virtual bool Matches(string assemblyFullName)
        {
            return !Matches(assemblyFullName, AssemblySkipLoadingPattern)
                   && Matches(assemblyFullName, AssemblyRestrictToLoadingPattern);
        }
最终调用如下:
protected virtual bool Matches(string assemblyFullName, string pattern)
        {
            return Regex.IsMatch(assemblyFullName, pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
        }

复制代码

可以看到不加载AssemblySkipLoadingPattern所有DLL,并且在AssemblyRestrictToLoadingPattern的匹配控制内。

继续往下(!addedAssemblyNames.Contains(assembly.FullName)) 不包含则添加assemblies.Add(assembly); 这是类库。addedAssemblyNames.Add(assembly.FullName); 这是名称。

感觉AddConfiguredAssemblies(addedAssemblyNames, assemblies);有点多余啊 ,记录一下。

调用代码如下: 这个方法最终就是返回assignTypeFrom所属类型的类的类型(非实例)的集合。

复制代码

public IEnumerable<Type> FindClassesOfType(Type assignTypeFrom, IEnumerable<Assembly> assemblies, bool onlyConcreteClasses = true)
        {
            var result = new List<Type>();
            try
            {
                foreach (var a in assemblies)
                {
                    Type[] types = null;
                    try
                    {
                        types = a.GetTypes();
                    }
                    catch
                    {
                        //Entity Framework 6 doesn't allow getting types (throws an exception)
                        if (!ignoreReflectionErrors)
                        {
                            throw;
                        }
                    }
                    if (types != null)
                    {
                        foreach (var t in types)
                        {
                            if (assignTypeFrom.IsAssignableFrom(t) || (assignTypeFrom.IsGenericTypeDefinition && DoesTypeImplementOpenGeneric(t, assignTypeFrom)))
                            {
                                if (!t.IsInterface)
                                {
                                    if (onlyConcreteClasses)
                                    {
                                        if (t.IsClass && !t.IsAbstract)
                                        {
                                            result.Add(t);
                                        }
                                    }
                                    else
                                    {
                                        result.Add(t);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (ReflectionTypeLoadException ex)
            {
                var msg = string.Empty;
                foreach (var e in ex.LoaderExceptions)
                    msg += e.Message + Environment.NewLine;

                var fail = new Exception(msg, ex);
                Debug.WriteLine(fail.Message, fail);

                throw fail;
            }
            return result;
        }

复制代码

回到NopEngine

foreach (var drType in drTypes)
                drInstances.Add((IDependencyRegistrar) Activator.CreateInstance(drType));

添加实例。

最后根据dependencyRegistrar.order进行排序,用dependencyRegistrar.Register(builder, typeFinder);方法进行依赖注入注册。

this._containerManager = new ContainerManager(container);

声明容器管理器 传入autofac的容器对象。

最后一句:

//set dependency resolver
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

以前深入研究过DependencyResolver,但现在几乎都忘了。只知道好像是MVC实现依赖的一个扩展点。这里我理解就是用Autofac接管MVC的控制反转。

参考http://www.cnblogs.com/miku/archive/2013/01/16/2862675.html 、http://www.cnblogs.com/hkncd/archive/2012/11/28/2792474.html 、http://book.2cto.com/201212/12051.html等。

回到Init。。。。方法最后一局,如果没有启动任务,则执行RunStartupTasks();代码如下:

复制代码

/// <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();
        }

复制代码

第一句Resolve的代码如下:

复制代码

public T Resolve<T>(string key = "", ILifetimeScope scope = null) where T : class
        {
            if (scope == null)
            {
                //no scope specified
                scope = Scope();
            }
            if (string.IsNullOrEmpty(key))
            {
                return scope.Resolve<T>();
            }
            return scope.ResolveKeyed<T>(key);
        }

复制代码

Scope(),作用域的代码如下:

复制代码

public ILifetimeScope Scope()
        {
            try
            {
                if (HttpContext.Current != null)
                    return AutofacDependencyResolver.Current.RequestLifetimeScope;

                //when such lifetime scope is returned, you should be sure that it'll be disposed once used (e.g. in schedule tasks)
                return Container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
            }
            catch (Exception)
            {
                //we can get an exception here if RequestLifetimeScope is already disposed
                //for example, requested in or after "Application_EndRequest" handler
                //but note that usually it should never happen

                //when such lifetime scope is returned, you should be sure that it'll be disposed once used (e.g. in schedule tasks)
                return Container.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
            }
        }

复制代码

这里不做郭拓探讨,因为我也糊涂(哭泣的脸) 其实就是默认返回Autofac当前请求的作用范围,然后返回需要的对象。

var startUpTaskTypes = typeFinder.FindClassesOfType<IStartupTask>();

找到所有启动类的集合。最后排序,调用startUpTask.Execute();方法。

终于完了,回到了Golbal.asax.cs文件的RegisterRoutes方法。

var routePublisher = EngineContext.Current.Resolve<IRoutePublisher>();  我们仅仅研究了Current,就执行了很多,初始化NOP引擎、初始化依赖注入Autofac、执行所有启动任务。

然后我们看Resolve方法。和上面的一样,返回路由发布者、注册路由。http://blog.csdn.net/francislaw/article/details/7429317  第四个参数是限制参数 比如id必须是数字等(这里没第四参数)

routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional },
                new[] { "Nop.Web.Controllers" }//第五个参数为命名空间,即该路由匹配在那个命名空间下有效
            );

Application_Start 方法

复制代码

protected void Application_Start()
        {
            //initialize engine context
            EngineContext.Initialize(false);

            bool databaseInstalled = DataSettingsHelper.DatabaseIsInstalled();
            if (databaseInstalled)
            {
                //remove all view engines
                ViewEngines.Engines.Clear();
                //except the themeable razor view engine we use
                ViewEngines.Engines.Add(new ThemeableRazorViewEngine());
            }

            //Add some functionality on top of the default ModelMetadataProvider
            ModelMetadataProviders.Current = new NopMetadataProvider();

            //Registering some regular mvc stuff
            AreaRegistration.RegisterAllAreas();
            RegisterRoutes(RouteTable.Routes);
            
            //fluent validation
            DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
            ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(new NopValidatorFactory()));

            //start scheduled tasks
            if (databaseInstalled)
            {
                TaskManager.Instance.Initialize();
                TaskManager.Instance.Start();
            }

            //log application start
            if (databaseInstalled)
            {
                try
                {
                    //log
                    var logger = EngineContext.Current.Resolve<ILogger>();
                    logger.Information("Application started", null, null);
                }
                catch (Exception)
                {
                    //don't throw new exception if occurs
                }
            }
        }

复制代码

第一句EngineContext.Initialize(false); 不用说了,就是初始化NopEngine.

第二句 bool databaseInstalled = DataSettingsHelper.DatabaseIsInstalled();  名字就猜到了是判断数据库是否生成。代码如下:

复制代码

namespace Nop.Core.Data
{
    public partial class DataSettingsHelper
    {
        private static bool? _databaseIsInstalled;
        public static bool DatabaseIsInstalled()
        {
            if (!_databaseIsInstalled.HasValue)
            {
                var manager = new DataSettingsManager();
                var settings = manager.LoadSettings();
                _databaseIsInstalled = settings != null && !String.IsNullOrEmpty(settings.DataConnectionString);
            }
            return _databaseIsInstalled.Value;
        }

        public static void ResetCache()
        {
            _databaseIsInstalled = null;
        }
    }
}

复制代码

通过manager加载配置,并通过判断配置连接字符串存在则返回true.   下面是加载代码:

复制代码

public virtual DataSettings LoadSettings(string filePath = null)
        {
            if (String.IsNullOrEmpty(filePath))
            {
                //use webHelper.MapPath instead of HostingEnvironment.MapPath which is not available in unit tests
                filePath = Path.Combine(MapPath("~/App_Data/"), filename);
            }
            if (File.Exists(filePath))
            {
                string text = File.ReadAllText(filePath);
                return ParseSettings(text);
            }
            
            return new DataSettings();
        }

复制代码

初始设置:

protected const char separator = ':';
        protected const string filename = "Settings.txt";

在App_Data文件夹下找到文件 内容是:

DataProvider: sqlserver
DataConnectionString: Data Source=.;Initial Catalog=NOPCDB;Integrated Security=False;Persist Security Info=False;User ID=sa;Password=123

刚开始肯定返回是 所以不会执行,但以后每次都执行。  所以暂且分析一下:

复制代码

if (databaseInstalled)
            {
                //remove all view engines
                ViewEngines.Engines.Clear();
                //except the themeable razor view engine we use
                ViewEngines.Engines.Add(new ThemeableRazorViewEngine());
            }

复制代码

清除所有view engines,添加ThemeableRazorViewEngine。我们分析下ThemeableRazorViewEngine。

这个视图引擎 以前分析过,但差不多也忘了,大体就是设置自己的视图引擎路径,一下是代码:

复制代码

public class ThemeableRazorViewEngine : ThemeableVirtualPathProviderViewEngine
    {
        public ThemeableRazorViewEngine()
        {
            AreaViewLocationFormats = new[]
                                          {
                                              //themes
                                              "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.cshtml",
                                              "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.cshtml",
                                              
                                              //default
                                              "~/Areas/{2}/Views/{1}/{0}.cshtml",
                                              "~/Areas/{2}/Views/Shared/{0}.cshtml",
                                          };

            AreaMasterLocationFormats = new[]
                                            {
                                                //themes
                                                "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.cshtml",
                                                "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.cshtml",


                                                //default
                                                "~/Areas/{2}/Views/{1}/{0}.cshtml",
                                                "~/Areas/{2}/Views/Shared/{0}.cshtml",
                                            };

            AreaPartialViewLocationFormats = new[]
                                                 {
                                                     //themes
                                                    "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.cshtml",
                                                    "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.cshtml",
                                                    
                                                    //default
                                                    "~/Areas/{2}/Views/{1}/{0}.cshtml",
                                                    "~/Areas/{2}/Views/Shared/{0}.cshtml"
                                                 };

            ViewLocationFormats = new[]
                                      {
                                            //themes
                                            "~/Themes/{2}/Views/{1}/{0}.cshtml", 
                                            "~/Themes/{2}/Views/Shared/{0}.cshtml",

                                            //default
                                            "~/Views/{1}/{0}.cshtml", 
                                            "~/Views/Shared/{0}.cshtml",

                                            //Admin
                                            "~/Administration/Views/{1}/{0}.cshtml",
                                            "~/Administration/Views/Shared/{0}.cshtml",
                                      };

            MasterLocationFormats = new[]
                                        {
                                            //themes
                                            "~/Themes/{2}/Views/{1}/{0}.cshtml", 
                                            "~/Themes/{2}/Views/Shared/{0}.cshtml", 

                                            //default
                                            "~/Views/{1}/{0}.cshtml", 
                                            "~/Views/Shared/{0}.cshtml"
                                        };

            PartialViewLocationFormats = new[]
                                             {
                                                 //themes
                                                "~/Themes/{2}/Views/{1}/{0}.cshtml",
                                                "~/Themes/{2}/Views/Shared/{0}.cshtml",

                                                //default
                                                "~/Views/{1}/{0}.cshtml", 
                                                "~/Views/Shared/{0}.cshtml", 

                                                //Admin
                                                "~/Administration/Views/{1}/{0}.cshtml",
                                                "~/Administration/Views/Shared/{0}.cshtml",
                                             };

            FileExtensions = new[] { "cshtml" };
        }

        protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
        {
            IEnumerable<string> fileExtensions = base.FileExtensions;
            return new RazorView(controllerContext, partialPath, null, false, fileExtensions);
            //return new RazorView(controllerContext, partialPath, layoutPath, runViewStartPages, fileExtensions, base.ViewPageActivator);
        }

        protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
        {
            IEnumerable<string> fileExtensions = base.FileExtensions;
            return new RazorView(controllerContext, viewPath, masterPath, true, fileExtensions);
        }
    }

复制代码

先放一下视图引擎,单独研究吧,也不是很难。