昨天研究到:
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); } }
先放一下视图引擎,单独研究吧,也不是很难。
原文:https://www.cnblogs.com/runit/p/4166500.html