博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
IOC容器特性注入第一篇:程序集反射查找
阅读量:7196 次
发布时间:2019-06-29

本文共 12291 字,大约阅读时间需要 40 分钟。

学习kooboo的框架发现它的注入容器方法比较特别,同样是利用MVC的注入点,但它是查找网站下面bin所有的DLL利用反射查找特性找到对应的服务注入到容器。

这样的好处很简单:完全可以不用关心IOC容器是Ninject还是autofac 或者其它什么容器。 只要写上特性标记,再把对应的DLL拷贝到BIN下面,网站一启动就会自动注入到容器中。彻底进行解耦。

它的IOC注入步骤先后顺序:

1.程序集反射查找

2.IOC容器引擎初始化

3.利用特性注入IOC容器

4.MVC注入点注入

因为本人比较笨,理解东西比较差强人意,所以将以7篇文章分别介绍各个模块加强自己的理解:

源代码,我放在最后一篇,大家可以去下载。

我首先介绍下如何对网站BIN下面的DLL进行反射查找:

 kooboo的程序集反射查找类就是Nop的三个封装类,分别是:

1.接口(ITypeFinder):

public interface ITypeFinder {        IList
GetAssemblies(); IEnumerable
FindClassesOfType(Type assignTypeFrom, bool onlyConcreteClasses = true); IEnumerable
FindClassesOfType(Type assignTypeFrom, IEnumerable
assemblies, bool onlyConcreteClasses = true); IEnumerable
FindClassesOfType
(bool onlyConcreteClasses = true); IEnumerable
FindClassesOfType
(IEnumerable
assemblies, bool onlyConcreteClasses = true); IEnumerable
FindClassesOfType
(bool onlyConcreteClasses = true) where TAssemblyAttribute : Attribute; IEnumerable
FindAssembliesWithAttribute
(); IEnumerable
FindAssembliesWithAttribute
(IEnumerable
assemblies); IEnumerable
FindAssembliesWithAttribute
(DirectoryInfo assemblyPath); }

2.应用程序实现类(AppDomainTypeFinder):

public class AppDomainTypeFinder : ITypeFinder {        #region Private Fields        private bool loadAppDomainAssemblies = true;        private string assemblySkipLoadingPattern = "^System|^mscorlib|^Microsoft|^CppCodeProvider|^VJSharpCodeProvider|^WebDev|^Castle|^Iesi|^log4net|^NHibernate|^nunit|^TestDriven|^MbUnit|^Rhino|^QuickGraph|^TestFu|^Telerik|^ComponentArt|^MvcContrib|^AjaxControlToolkit|^Antlr3|^Remotion|^Recaptcha|^DotNetOpenAuth,";        private string assemblyRestrictToLoadingPattern = ".*";        private IList
assemblyNames = new List
(); #endregion #region Constructors ///
Creates a new instance of the AppDomainTypeFinder. public AppDomainTypeFinder() { } #endregion #region Properties ///
The app domain to look for types in. public virtual AppDomain App { get { return AppDomain.CurrentDomain; } } ///
Gets or sets wether app should iterate assemblies in the app domain when loading types. Loading patterns are applied when loading these assemblies. public bool LoadAppDomainAssemblies { get { return loadAppDomainAssemblies; } set { loadAppDomainAssemblies = value; } } ///
Gets or sets assemblies loaded a startup in addition to those loaded in the AppDomain. public IList
AssemblyNames { get { return assemblyNames; } set { assemblyNames = value; } } ///
Gets the pattern for dlls that we know don't need to be investigated. public string AssemblySkipLoadingPattern { get { return assemblySkipLoadingPattern; } set { assemblySkipLoadingPattern = value; } } ///
Gets or sets the pattern for dll that will be investigated. For ease of use this defaults to match all but to increase performance you might want to configure a pattern that includes assemblies and your own. ///
If you change this so that assemblies arn't investigated (e.g. by not including something like "^MTA|..." you may break core functionality.
public string AssemblyRestrictToLoadingPattern { get { return assemblyRestrictToLoadingPattern; } set { assemblyRestrictToLoadingPattern = value; } } #endregion #region Internal Attributed Assembly class private class AttributedAssembly { internal Assembly Assembly { get; set; } internal Type PluginAttributeType { get; set; } } #endregion #region ITypeFinder public IEnumerable
FindClassesOfType
(bool onlyConcreteClasses = true) { return FindClassesOfType(typeof(T), onlyConcreteClasses); } public IEnumerable
FindClassesOfType(Type assignTypeFrom, bool onlyConcreteClasses = true) { return FindClassesOfType(assignTypeFrom, GetAssemblies(), onlyConcreteClasses); } public IEnumerable
FindClassesOfType
(IEnumerable
assemblies, bool onlyConcreteClasses = true) { return FindClassesOfType(typeof(T), assemblies, onlyConcreteClasses); } public IEnumerable
FindClassesOfType(Type assignTypeFrom, IEnumerable
assemblies, bool onlyConcreteClasses = true) { var result = new List
(); try { foreach (var a in assemblies) { foreach (var t in a.GetTypes()) { 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; } public IEnumerable
FindClassesOfType
(bool onlyConcreteClasses = true) where TAssemblyAttribute : Attribute { var found = FindAssembliesWithAttribute
(); return FindClassesOfType
(found, onlyConcreteClasses); } public IEnumerable
FindAssembliesWithAttribute
() { return FindAssembliesWithAttribute
(GetAssemblies()); } ///
/// Caches attributed assembly information so they don't have to be re-read /// private readonly List
_attributedAssemblies = new List
(); ///
/// Caches the assembly attributes that have been searched for /// private readonly List
_assemblyAttributesSearched = new List
(); public IEnumerable
FindAssembliesWithAttribute
(IEnumerable
assemblies) { //check if we've already searched this assembly);) if (!_assemblyAttributesSearched.Contains(typeof(T))) { var foundAssemblies = (from assembly in assemblies let customAttributes = assembly.GetCustomAttributes(typeof(T), false) where customAttributes.Any() select assembly).ToList(); //now update the cache _assemblyAttributesSearched.Add(typeof(T)); foreach (var a in foundAssemblies) { _attributedAssemblies.Add(new AttributedAssembly { Assembly = a, PluginAttributeType = typeof(T) }); } } //We must do a ToList() here because it is required to be serializable when using other app domains. return _attributedAssemblies .Where(x => x.PluginAttributeType.Equals(typeof(T))) .Select(x => x.Assembly) .ToList(); } public IEnumerable
FindAssembliesWithAttribute
(DirectoryInfo assemblyPath) { var assemblies = (from f in Directory.GetFiles(assemblyPath.FullName, "*.dll") select Assembly.LoadFrom(f) into assembly let customAttributes = assembly.GetCustomAttributes(typeof(T), false) where customAttributes.Any() select assembly).ToList(); return FindAssembliesWithAttribute
(assemblies); } ///
Gets tne assemblies related to the current implementation. ///
A list of assemblies that should be loaded by the factory.
public virtual IList
GetAssemblies() { var addedAssemblyNames = new List
(); var assemblies = new List
(); if (LoadAppDomainAssemblies) AddAssembliesInAppDomain(addedAssemblyNames, assemblies); AddConfiguredAssemblies(addedAssemblyNames, assemblies); return assemblies; } #endregion ///
Iterates all assemblies in the AppDomain and if it's name matches the configured patterns add it to our list. ///
///
private void AddAssembliesInAppDomain(List
addedAssemblyNames, List
assemblies) { foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { if (Matches(assembly.FullName)) { if (!addedAssemblyNames.Contains(assembly.FullName)) { assemblies.Add(assembly); addedAssemblyNames.Add(assembly.FullName); } } } } ///
Adds specificly configured assemblies. protected virtual void AddConfiguredAssemblies(List
addedAssemblyNames, List
assemblies) { foreach (string assemblyName in AssemblyNames) { Assembly assembly = Assembly.Load(assemblyName); if (!addedAssemblyNames.Contains(assembly.FullName)) { assemblies.Add(assembly); addedAssemblyNames.Add(assembly.FullName); } } } ///
Check if a dll is one of the shipped dlls that we know don't need to be investigated. ///
The name of the assembly to check. ///
True if the assembly should be loaded into app.
public virtual bool Matches(string assemblyFullName) { return !Matches(assemblyFullName, AssemblySkipLoadingPattern) && Matches(assemblyFullName, AssemblyRestrictToLoadingPattern); } ///
Check if a dll is one of the shipped dlls that we know don't need to be investigated. ///
The assembly name to match. ///
The regular expression pattern to match against the assembly name. ///
True if the pattern matches the assembly name.
protected virtual bool Matches(string assemblyFullName, string pattern) { return Regex.IsMatch(assemblyFullName, pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled); } ///
Makes sure matching assemblies in the supplied folder are loaded in the app domain. ///
The physical path to a directory containing dlls to load in the app domain. protected virtual void LoadMatchingAssemblies(string directoryPath) { var loadedAssemblyNames = new List
(); foreach (Assembly a in GetAssemblies()) { loadedAssemblyNames.Add(a.FullName); } if (!Directory.Exists(directoryPath)) { return; } foreach (string dllPath in Directory.GetFiles(directoryPath, "*.dll")) { try { var an = AssemblyName.GetAssemblyName(dllPath); if (Matches(an.FullName) && !loadedAssemblyNames.Contains(an.FullName)) { App.Load(an); } //old loading stuff //Assembly a = Assembly.ReflectionOnlyLoadFrom(dllPath); //if (Matches(a.FullName) && !loadedAssemblyNames.Contains(a.FullName)) //{ // App.Load(a.FullName); //} } catch (BadImageFormatException ex) { Trace.TraceError(ex.ToString()); } } } protected virtual bool DoesTypeImplementOpenGeneric(Type type, Type openGeneric) { try { var genericTypeDefinition = openGeneric.GetGenericTypeDefinition(); foreach (var implementedInterface in type.FindInterfaces((objType, objCriteria) => true, null)) { if (!implementedInterface.IsGenericType) continue; var isMatch = genericTypeDefinition.IsAssignableFrom(implementedInterface.GetGenericTypeDefinition()); return isMatch; } return false; } catch { return false; } } }

3.web应用程序继承App作用域类(WebAppTypeFinder):

public class WebAppTypeFinder : AppDomainTypeFinder {        #region Fields        private bool _ensureBinFolderAssembliesLoaded = true;        private bool _binFolderAssembliesLoaded = false;        #endregion        #region Ctor        public WebAppTypeFinder() {            this._ensureBinFolderAssembliesLoaded = true;        }        #endregion        #region Properties        ///         /// 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.        ///         public bool EnsureBinFolderAssembliesLoaded {            get { return _ensureBinFolderAssembliesLoaded; }            set { _ensureBinFolderAssembliesLoaded = value; }        }        #endregion        #region Methods        ///         /// Gets a physical disk path of \Bin directory        ///         /// 
The physical path. E.g. "c:\inetpub\wwwroot\bin"
public virtual string GetBinDirectory() { if (HostingEnvironment.IsHosted) { //hosted return HttpRuntime.BinDirectory; } else { //not hosted. For example, run either in unit tests return AppDomain.CurrentDomain.BaseDirectory; } } public override IList
GetAssemblies() { if (this.EnsureBinFolderAssembliesLoaded && !_binFolderAssembliesLoaded) { _binFolderAssembliesLoaded = true; string binPath = GetBinDirectory(); //binPath = _webHelper.MapPath("~/bin"); LoadMatchingAssemblies(binPath); } return base.GetAssemblies(); } #endregion }
WebAppTypeFinder 这个类就可以对网站下面BIN文件夹所有的DLL文件进行反射查找程序集,可以根据类型 也可以跟特性查找,总之性能不错,大家可以拷贝代码 进行测试。

下一篇:

转载地址:http://hgvkm.baihongyu.com/

你可能感兴趣的文章
phpMyAdmin 错误 缺少 mysqli 扩展。请检查 PHP 配置
查看>>
Win7网上邻居提示未授予用户在此计算机上的请求登录类型解决办法
查看>>
golang包快速生成base64验证码
查看>>
Visual studio 下C++工程相关经验
查看>>
七、SSR(服务端渲染)
查看>>
django--app(六)
查看>>
洛谷P3379 【模板】最近公共祖先(LCA)
查看>>
获取一个表单字段中多条数据并转化为json格式
查看>>
c#中的变量,属性,字段
查看>>
JS实现延迟载入图片
查看>>
游戏开发中的人工智能
查看>>
Ubuntu 安装BCM 43142无线网卡驱动
查看>>
iOS 疑难杂症 — — UIButton 点击卡顿/延迟
查看>>
免费 官方的ASP.NET MVC电子书-Professional ASP.NET MVC 1.0
查看>>
PL/SQL DEVELOPER
查看>>
SqlServer2005通过出生日期算年龄函数
查看>>
hdu3496(二维背包)
查看>>
centos7安装部署mysql5.7服务器
查看>>
华为实习日记——第三天
查看>>
LinuxThread VS NPTL
查看>>