<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Ninject.Web.Common,Ninject.MVC3源碼分析

            Ninject是一款.Net平臺下的開源依賴注入框架.按照官方說法,它快如閃電、超級輕量,且充分利用了.Net的最新語法,使用Lambda表達式代替Xml文件完成類型綁定.Ninject結構精巧,功能強大,越來越受到各類開發者的關注,其開源社區非常活躍,眾多開發者為它開發了各種各樣的擴展應用.其中有一款名叫Ninject.Web.Common,是所有將Ninject應用于Web項目的基框架,而Ninject.MVC3則是將Ninject應用于Asp.Net Mvc中的框架.這兩者是本文分析的主角.

            書寫本文時,Ninject的版本號為3.0.1,Ninject.Web.Common的版本號為3.0.0.3.,Ninject.MVC3的版本號為3.0.0.6.

            OnePerRequestHttpModule是與對象生命周期有關的類,表示在同一次請求內同一類型會解析出相同的實例.這個是Web程序特有的生命周期,能在部分應用中節約資源,提高性能.此類實現了IHttpModule接口,如下:

       

      public void Init(HttpApplication application)
      {
          application.EndRequest += (o, e) => this.DeactivateInstancesForCurrentHttpRequest();
      }
      
      public void DeactivateInstancesForCurrentHttpRequest()
      {
          if (this.ReleaseScopeAtRequestEnd)
          {
              var context = HttpContext.Current;
              this.MapKernels(kernel => kernel.Components.Get<ICache>().Clear(context));
          }
      }

       

            可以看到,在WebApplication生命周期的最后,其會將所有在請求過程中生成的且緩存于HttpContext.Current的對象手動清空.還可以看到,其實這個類只涉及到OnePerRequest生命周期的部分實現,即清空部分.對象的分配部分則內置于Ninject框架中.

            IBootstrapper接口的實現類為Bootstrapper,如下所示:

       

      private static IKernel kernelInstance;
      
      public void Initialize(Func<IKernel> createKernelCallback)
      {
          kernelInstance = createKernelCallback();
      
          kernelInstance.Components.GetAll<INinjectHttpApplicationPlugin>().Map(c => c.Start());
          kernelInstance.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
          kernelInstance.Inject(this);
      }
      
      public void ShutDown()
      {
          if (kernelInstance != null)
          {
              kernelInstance.Components.GetAll<INinjectHttpApplicationPlugin>().Map(c => c.Stop());
              kernelInstance.Dispose();
              kernelInstance = null;
          }
      }

      public void InitializeHttpApplication(HttpApplication httpApplication)
      {
          kernelInstance.Inject(httpApplication);
      }

       

            Bootstrapper的中文意思是啟動加載器,即管理程序啟動時所需資源.IOC核心最終是保存在此對象的靜態字段kernelInstance中.Initialize方法接受一個Func<IKernel>類型的委托,即通過它獲取IOC核心.然后從中獲取所有實現了INinjectHttpApplicationPlugin接口的類并立刻調用此接口Start方法.可以從名字猜出,這是一個簡易的插件系統,在系統啟動前首先啟動所有插件.第二句先放一下.第三句則是將自己重新注入.只有由從IOC中獲取的對象才能被注入,而Inject方法專門用于不是由IOC生成的對象,可以讓其標記了[Inject]的且為空的屬性重新獲得對象注入.可以看到在默認情況下這一句不會產生實際效果.

            InitializeHttpApplication則是將HttpApplication對象重注入.HttpApplication對象是由Asp.Net自動生成的.如果在實際使用的子類中進行了屬性注入,則需要通過重注入的方式為屬性獲取合適的值.

            ShutDown方法在系統關閉時被調用,用于插件的逐個卸載.

            分析完這兩個類我們再來分析Ninject.Web.Common的核心類:NinjectHttpApplication

      private readonly OnePerRequestHttpModule onePerRequestHttpModule;
      
      private readonly IBootstrapper bootstrapper;
      
      protected NinjectHttpApplication()
      {
          this.onePerRequestHttpModule = new OnePerRequestHttpModule();
          this.onePerRequestHttpModule.Init(this);
          this.bootstrapper = new Bootstrapper();
      }
      
      public void Application_Start()
      {
          lock (this)
          {
              this.bootstrapper.Initialize(this.CreateKernel);
              this.onePerRequestHttpModule.ReleaseScopeAtRequestEnd = this.bootstrapper.Kernel.Settings.Get("ReleaseScopeAtRequestEnd", true);
              this.OnApplicationStarted();
          }
      }
      
      public void Application_End()
      {
          this.bootstrapper.ShutDown();
          this.OnApplicationStopped();
      }
      
      protected abstract IKernel CreateKernel();
      
      protected virtual void OnApplicationStarted() { }
      
      protected virtual void OnApplicationStopped() { }

      public override void Init()
      {
          base.Init();
          this.bootstrapper.InitializeHttpApplication(this);
      }

           在此對象構造函數中,構造了上面所述的兩個對象,并手動調用了OnePerRequestHttpModule對象的Init方法完成了此IHttpModule的掛載.然后在Application_Start()方法中調用了IBootstrapper對象的Initialize方法完成了插件的掛載.并設置了OnePerRequestHttpModule對象是否開啟資源清理.最后調用OnApplicationStarted方法.Application_End()則完成插件的卸載和OnApplicationStopped()方法.

            可以看到,此對象改變了傳統HttpApplication對象的一般處理過程.按照其設計意圖,應用程序開啟時執行的方法由默認的Application_Start方法轉移動OnApplicationStarted(),而應用程序終止時執行的方法則由Application_End方法轉移到OnApplicationStopped方法中.

            此對象實際是一個抽象對象,包含唯一一個抽象方法CreateKernel,方法最終將被用戶重寫,用于提供IOC核心.

            在Init方法中調用Bootstrapper對象的InitializeHttpApplication方法完成對自身的重注入.Init方法與Application_Start方法不同.Init方法將在每個HttpApplication對象構造完成并加載了所有IHttpModule之后被調用,而Application_Start方法則是在應用程序啟動時被調用,在整個應用程序中Init方法會被調用多次,而Application_Start方法只會被調用一次.如果HttpApplication對象池有剩余對象,則會取出一個來處理請求,這時不會觸發Init方法,否則則會建立新的HttpApplication對象來處理新的請求,這時則會調用Init方法.

            至此,Ninject.Web.Common的主體工程已分析完畢.但其仍提供了兩個額外的HttoModule.這也是最容易讓人引起困惑的地方.

            NinjectHttpModule類提供了一種功能,即通過類型綁定而不是Web.Config來配置IHttpModule,如下:

       

      private IList<IHttpModule> httpModules;
      
      public void Init(HttpApplication context)
      {
          this.httpModules = new Bootstrapper().Kernel.GetAll<IHttpModule>().ToList();
          foreach (var httpModule in this.httpModules)
          {
              httpModule.Init(context);
          }            
      }
      
      public void Dispose()
      {
          foreach (var httpModule in this.httpModules)
          {
              httpModule.Dispose();
          }
      
          this.httpModules.Clear();
      }

       

            代碼比較簡單,即在Init處獲取所有已綁定的實現了IHttpModule接口的對象并循環調用它們的Init方法,在Dispose方法處循環調用它們各自的Dispose方法.

            HttpApplicationInitializationHttpModule對象如下:

      private readonly Func<IKernel> lazyKernel;
      
      public HttpApplicationInitializationHttpModule(Func<IKernel> lazyKernel)
      {
          this.lazyKernel = lazyKernel;
      }
      
      public void Init(HttpApplication context)
      {
          this.lazyKernel().Inject(context);
      }

            這個更簡單,就是將HttpApplication對象重新注入,只不過實現為了IHttpModule接口.還記得Bootstrapper對象的Initialize方法嗎?在那里將IHttpModule與HttpApplicationInitializationHttpModule進行了綁定.

            在Ninject.Web.Common官網上展示了使用這個框架的兩種方式,一種是繼承,一種是動態注入.現在問題來了:

            1.如何使用HttpApplicationInitializationHttpModule對象?可以看到,其沒有無參構造函數,如果直接配置于Web.Config,Asp.Net則會因為無法構造此對象而報錯.此對象需配合NinjectHttpModule對象使用.

            2.如果使用繼承方式使用,同時在Web.Config中配置了NinjectHttpModule,則HttpApplication對象將被注入兩次.一次在Bootstrapper對象的InitializeHttpApplication方法中,一次在HttpApplicationInitializationHttpModule對象的Init方法中.一開始我百思不得其解,后來看到一篇官方的反饋我才恍然大悟.原來HttpApplicationInitializationHttpModule并不應該用于使用繼承方式中,而是用于動態注入方式中的.

            3.同上,如果使用繼承方式使用,同時在Web.Config中配置了NinjectHttpModule,則程序會報錯,因為是HttpApplicationInitializationHttpModule對象是由IOC核心構造的,其需要知道Func<IKernel>類型的實際類型.

            最后,我們來看一看官方推薦的動態注入使用方式

      [assembly: WebActivator.PreApplicationStartMethod(typeof(WebApplication1.App_Start.NinjectWebCommon), "Start")]
      [assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(WebApplication1.App_Start.NinjectWebCommon), "Stop")]
      public static class NinjectWebCommon 
      {
          private static readonly Bootstrapper bootstrapper = new Bootstrapper();
      
          /// <summary>
          /// Starts the application
          /// </summary>
          public static void Start() 
          {
              DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
              DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
              bootstrapper.Initialize(CreateKernel);
          }
      
          public static void Stop()
          {
              bootstrapper.ShutDown();
          }
              
          private static IKernel CreateKernel()
          {
              var kernel = new StandardKernel();
              kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
              kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
                  
              RegisterServices(kernel);
              return kernel;
          }
      
          private static void RegisterServices(IKernel kernel) { }        
      }

            它充分使用Asp.Net 4.0的新技術,并使用了WebActivator框架,在Web程序啟動前動態調用Start函數,在關閉前調用Stop函數.在Start函數中,動態注冊了OnePerRequestHttpModuleNinjectHttpModule.而對于CreateKernel函數,首先新建了IOC核心,然后綁定了Func<IKernel>類型與IHttpModule類型.可以看到,由于在Bootstrapper對象的Initialize方法里已綁定過一次,這里重復綁定了.然后調用RegisterServices方法獲取應用程序的各類具體類型綁定,最后將IOC核心返回以保存至Bootstrapper的靜態變量kernelInstance中.

       

            Ninject.MVC3的代碼則比較簡單

            MvcModule類繼承自GlobalKernelRegistrationModule<OnePerRequestHttpModule>類.GlobalKernelRegistrationModule<T>類繼承自NinjectModule類.完成了各種類型綁定.GlobalKernelRegistrationModule<T>類與GlobalKernelRegistration類配合使用的,實現了一種反向綁定.一般的正向綁定,即某一個IOC核心綁定了多個接口到類的映射,而反向綁定則是記錄某個接口在哪些IOC核心里進行了綁定.這個功能我暫時沒有看到在哪里進行了使用,不過應該是有所目的的.

            MvcModule類定義如下:

      public override void Load()
      {
          base.Load();
          this.Kernel.Components.Add<INinjectHttpApplicationPlugin, NinjectMvcHttpApplicationPlugin>();
          this.Kernel.Bind<IDependencyResolver>().To<NinjectDependencyResolver>();
          this.Kernel.Bind<IFilterProvider>().To<NinjectFilterAttributeFilterProvider>();
          this.Kernel.Bind<IFilterProvider>().To<NinjectFilterProvider>();
          this.Kernel.Bind<RouteCollection>().ToConstant(RouteTable.Routes);
          this.Kernel.Bind<HttpContext>().ToMethod(ctx => HttpContext.Current).InTransientScope();
          this.Kernel.Bind<HttpContextBase>().ToMethod(ctx => new HttpContextWrapper(HttpContext.Current)).InTransientScope();
          this.Kernel.Bind<ModelValidatorProvider>().To<NinjectDataAnnotationsModelValidatorProvider>();
          //this.Kernel.Bind<IModelBinderProvider>().To<NinjectModelBinderProvider>();
          //this.Kernel.Bind<IModelBinder>().To<NinjectModelBinder>();
      }

            那這個Load函數是何時執行的呢?這就要談到Ninject的加載策略了.核心對象StandardKernel與其基類KernelBase的構造函數如下

      public class StandardKernel : KernelBase
      {
          public StandardKernel(params INinjectModule[] modules) : base(modules)
          {
          }
      }
      
      public abstract class KernelBase : BindingRoot, IKernel
      {
          protected KernelBase()
              : this(new ComponentContainer(), new NinjectSettings(), new INinjectModule[0])
          {}
          
          protected KernelBase(IComponentContainer components, INinjectSettings settings, params INinjectModule[] modules)
          {
              if (this.Settings.LoadExtensions)
              {
                  this.Load(this.Settings.ExtensionSearchPatterns);
              }
          }
      }

            可以看到,在KernelBase的構造函數中,有一個LoadExtensions的判斷,默認在NinjectSettings類中,意思是加載本地擴展

       

      public class NinjectSettings : INinjectSettings
      {
          public bool LoadExtensions
          {
              get { return Get("LoadExtensions", true); }
              set { Set("LoadExtensions", value); }
          }
          
          public string[] ExtensionSearchPatterns
          {
              get { return Get("ExtensionSearchPatterns", new [] { "Ninject.Extensions.*.dll", "Ninject.Web*.dll" }); }
              set { Set("ExtensionSearchPatterns", value); }
          }
      }

       

            可以猜測,默認會去Bin目錄下搜索所有以Ninject.Extensions或Ninject.Web開頭的程序集.

            具體的加載過程則比較簡單

      public void Load(IEnumerable<string> filePatterns)
      {
          var moduleLoader = this.Components.Get<IModuleLoader>();
          moduleLoader.LoadModules(filePatterns);
      }

            加載管理器接口IModuleLoader的實現類為ModuleLoader

      public void LoadModules(IEnumerable<string> patterns)
      {
          var plugins = Kernel.Components.GetAll<IModuleLoaderPlugin>();
      
          var fileGroups = patterns
              .SelectMany(pattern => GetFilesMatchingPattern(pattern))
              .GroupBy(filename => Path.GetExtension(filename).ToLowerInvariant());
      
          foreach (var fileGroup in fileGroups)
          {
              string extension = fileGroup.Key;
              IModuleLoaderPlugin plugin = plugins.Where(p => p.SupportedExtensions.Contains(extension)).FirstOrDefault();
      
              if (plugin != null)
                  plugin.LoadModules(fileGroup);
          }
      }

            第一句獲取所有的加載分析器.程序自帶了加載以dll為擴展名的文件型加載分析器,實現類為CompiledModuleLoaderPlugin.第二句獲取傳入的程序集全路徑.第三句則是循環文件,為每一個文件獲取一個加載分析器并進行操作.

      public class CompiledModuleLoaderPlugin : NinjectComponent, IModuleLoaderPlugin
      {
          public void LoadModules(IEnumerable<string> filenames)
          {
              var assembliesWithModules = this.assemblyNameRetriever.GetAssemblyNames(filenames, asm => asm.HasNinjectModules());
              this.Kernel.Load(assembliesWithModules.Select(asm => Assembly.Load(asm)));
          }
      }

            這里將實際功能委托給AssemblyNameRetriever類完成.

      public class AssemblyNameRetriever : NinjectComponent, IAssemblyNameRetriever
      {
          public IEnumerable<AssemblyName> GetAssemblyNames(IEnumerable<string> filenames, Predicate<Assembly> filter)
          {
              var assemblyCheckerType = typeof(AssemblyChecker);
              var temporaryDomain = CreateTemporaryAppDomain();
              try
              {
                  var checker = (AssemblyChecker)temporaryDomain.CreateInstanceAndUnwrap(
                      assemblyCheckerType.Assembly.FullName,
                      assemblyCheckerType.FullName ?? string.Empty);
      
                  return checker.GetAssemblyNames(filenames.ToArray(), filter);
              }
          }
      }

            這里創建了一個臨時應用程序域,然后在其中創建AssemblyChecker對象,最終通過它來完成最后的任務

      private class AssemblyChecker : MarshalByRefObject
      {
          public IEnumerable<AssemblyName> GetAssemblyNames(IEnumerable<string> filenames, Predicate<Assembly> filter)
          {
              var result = new List<AssemblyName>();
              foreach (var filename in filenames)
              {
                  Assembly assembly = Assembly.Load(filename);
      
                  if (filter(assembly))
                  {
                      result.Add(assembly.GetName(false));
                  }
              }
      
              return result;
          }
      }

            這里在臨時應用程序域中創建程序集后,使用了一個判斷來決定是否在此程序集中搜索,是由之前傳入的,定義在ExtensionsForAssembly類中.

      internal static class ExtensionsForAssembly
      {
          public static bool HasNinjectModules(this Assembly assembly)
          {
              return assembly.GetExportedTypes().Any(IsLoadableModule);
          }
          
          public static IEnumerable<INinjectModule> GetNinjectModules(this Assembly assembly)
          {
              return assembly.GetExportedTypes()
                      .Where(IsLoadableModule)
                      .Select(type => Activator.CreateInstance(type) as INinjectModule);
          }
      
          private static bool IsLoadableModule(Type type)
          {
              return typeof(INinjectModule).IsAssignableFrom(type)
                  && !type.IsAbstract
                  && !type.IsInterface
                  && type.GetConstructor(Type.EmptyTypes) != null;
          }
      }

            可以看到,這里就是說,在某一程序集中是否有實現了INinjectModule接口的類,且不是接口,不是抽象類,且還擁有無參構建函數.

            獲取到程序集名后,由KernelBase完全加載

      public void Load(IEnumerable<Assembly> assemblies)
      {
          this.Load(assemblies.SelectMany(asm => asm.GetNinjectModules()));
      }
      
      public void Load(IEnumerable<INinjectModule> m)
      {
          Ensure.ArgumentNotNull(m, "modules");
      
          m = m.ToList();
          foreach (INinjectModule module in m)
          {
              module.OnLoad(this);
      
              this.modules.Add(module.Name, module);
          }
      }

       

            NinjectDependencyResolver類則實現了接口IDependencyResolver,其本質是一個配置器模式,即讓Asp.Net MVC從IOC核心的獲取資源.定義如下:

      private readonly IResolutionRoot resolutionRoot;
      
      public object GetService(Type serviceType)
      {
          var request = this.resolutionRoot.CreateRequest(serviceType, null, new Parameter[0], true, true);
          return this.resolutionRoot.Resolve(request).SingleOrDefault();
      }
      
      public IEnumerable<object> GetServices(Type serviceType)
      {
          return this.resolutionRoot.GetAll(serviceType).ToList();
      }

            NinjectMvcHttpApplicationPlugin類則是利用Ninject.Web.Common的插件機制,完成IOC與Asp.Net MVC的對接,其關鍵代碼如下:

      public void Start()
      {
          ModelValidatorProviders.Providers.Remove(ModelValidatorProviders.Providers.OfType<DataAnnotationsModelValidatorProvider>().Single());
          DependencyResolver.SetResolver(this.CreateDependencyResolver());
          RemoveDefaultAttributeFilterProvider();
      }
      
      protected IDependencyResolver CreateDependencyResolver()
      {
          return this.kernel.Get<IDependencyResolver>();
      }

            在CreateDependencyResolver方法中從IOC核心中獲取IOC實例,在KernelBase對象的構造函數中完成了IKernel接口與IKernel實例的隱式綁定.如下

      this.Bind<IKernel>().ToConstant(this).InTransientScope();
      this.Bind<IResolutionRoot>().ToConstant(this).InTransientScope();

            回到NinjectMvcHttpApplicationPlugin類,最后在其Start方法的第二行將獲取到的IOC實例作為參數傳入DependencyResolver對象SetResolver方法,完成與Asp.Net MVC的對接.

            至此,Ninject.MVC3的工作已全部完成!

       

            參考的文章

            Ninject官網

            Ninject.Web.Common官網

            Ninject.MVC3官網

            How to inject dependencies in an HttpModule with a NinjectHttpApplication (no nuget)?

            RC2, issue with HttpApplicationInitializationHttpModule Injection

            IOC框架Ninject實踐總結

            Ninject 學習例子代碼(一)

            Ninject 學習例子代碼(二)

            ASP.NET MVC3 讓依賴注入來的更簡單(新補充了Ninject示例)

            ASP.NET MVC3 + Ninject.Mvc3 依賴注入原來可以這么簡單

            ASP.NET MVC 3 Service Location, Part

       

       

       

       

      posted @ 2013-01-28 22:56  永遠的阿哲  閱讀(1260)  評論(2)    收藏  舉報
      主站蜘蛛池模板: 国产精品成| 曰韩无码av一区二区免费| 综合色一色综合久久网| 国产精品任我爽爆在线播放6080| 久久精品国产亚洲av麻| 国产影片AV级毛片特别刺激| 香河县| 国产精品美女一区二三区| 男女扒开双腿猛进入爽爽免费看| AV最新高清无码专区| 亚洲精品久久久久午夜福禁果tⅴ| 2018天天拍拍天天爽视频| 无线日本视频精品| 久9re热视频这里只有精品免费| 夜夜春久久天堂亚洲精品| 大地资源中文在线观看西瓜| 97久久精品人人做人人爽| 亚洲乱码国产乱码精品精| 久久亚洲国产成人亚| 国产午夜亚洲精品福利| 白嫩人妻精品一二三四区| 最近中文国语字幕在线播放| 国产成年码av片在线观看| 国产成人精品永久免费视频| 国产成人一区二区三区视频免费| 成人午夜大片免费看爽爽爽 | 国产亚洲精品午夜福利| 国产激情国产精品久久源| 国产精品无码素人福利不卡| 亚洲婷婷综合色高清在线| 日韩一区二区三区水蜜桃| 亚洲熟妇色xxxxx亚洲| 中文字幕无码av不卡一区| 虎白女粉嫩尤物福利视频| 亚洲综合无码一区二区三区不卡| 日本久久久久亚洲中字幕| 亚洲精品美女一区二区| 丰城市| 这里只有精品免费视频| 久久亚洲中文字幕伊人久久大| 色二av手机版在线|