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

    昨天研究到:

    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.htmlhttp://www.cnblogs.com/hkncd/archive/2012/11/28/2792474.htmlhttp://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);
            }
        }

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

  • 相关阅读:
    Linux 开机启动 php socket
    Linux 判断进程是否运行
    应用容器公共免费部署平台
    dos2unix 批量转化文件
    django中多个app放入同一文件夹apps
    django无法同步mysql数据库 Error:1064
    cos migration工具webhook推送
    腾讯云 COS 对象存储使用
    docker nginx 运行后无法访问
    makefile中 = := += 的区别
  • 原文地址:https://www.cnblogs.com/runit/p/4166500.html
Copyright © 2011-2022 走看看