在我们的领域驱动设计(DDD)开发中,我们经常需要IOC框架使得我的框架依赖翻转,依赖抽象,避免直接new依赖于我们的具体实现。这些使得我们的框架整个项目结构不变,很方便的改变具体实现,使得项目提供可测试性,模块之间实现高内聚低耦合,减少我们的后期维护成本。IOC框架一般基于容器,在容器中存储着各个抽象和具体实现的依赖关系,当我们需要发出请求的时候,IOC框架会在当前容器中找到我们所需要的具体实现返回给我们,当然这里还有DI注入(属性,方法,构造),在我们的使用者(客户端)不需要了解具体实现,如何初始化,如何流转等具体,只需明白我们的契约接口暴露给我们的服务,IOC框架是解决抽象和具体直接的创建问题。其他资料可以参见Inversion of Control Containers and the Dependency Injection pattern。

当然Unity框架中为我们提供了RegisterInstance,RegisterType方法我们可以在代码中注册到容器,比如NLayerApp中就在IoCFactory中注册一大堆抽象-具体关联。但是在我们的实际实践中一般会选择另一种方式xml配置配置,因为这样我们会得到更大的灵活性,需求变化只要抽象接口不变,我们也只需要在xml配置文件中修改一行配置加入我们的具体实现,加入我们的程序集,就可以适应需求变化,这更满足oo设计“开闭原则”。

   在这里个人实践利用抽象(接口)定义Attribute制定具体ConfigFile(配置文件),Container(容器),Name(名称)解决IOC植入,减少我们多次去读取配置文件。Unity为我们提供了在Web.config,App.config中配置注入信息,或者注册外部配置,但是很多时候我们更希望,在我们的 不同模块下,应用不同的IOC配置信息,这些可以减少维护的关联少些,清晰,同时文件夹的出现便于我们的配置信息的管理。

Attribute实现:

  1. UnityInjectionAttributeView Code
  2. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
  3. public class UnityInjectionAttribute : Attribute
  4. {
  5. public UnityInjectionAttribute(string Container)
  6. {
  7. this.Container = Container;
  8. }
  9. public string Container
  10. {
  11. get;
  12. set;
  13. }
  14. public string ConfigFile
  15. {
  16. get;
  17. set;
  18. }
  19. public string Name
  20. {
  21. get;
  22. set;
  23. }
  24. public Microsoft.Practices.Unity.Configuration.UnityConfigurationSection GetUnityConfigurationSection()
  25. {
  26. if (!string.IsNullOrEmpty(this.ConfigFile))
  27. {
  28. var fileMap = new System.Configuration.ExeConfigurationFileMap { ExeConfigFilename = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, this.ConfigFile) };
  29. System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, System.Configuration.ConfigurationUserLevel.None);
  30. return configuration == null ? null : configuration.GetSection(Microsoft.Practices.Unity.Configuration.UnityConfigurationSection.SectionName) as Microsoft.Practices.Unity.Configuration.UnityConfigurationSection;
  31. }
  32. return System.Configuration.ConfigurationManager.GetSection(Microsoft.Practices.Unity.Configuration.UnityConfigurationSection.SectionName) as Microsoft.Practices.Unity.Configuration.UnityConfigurationSection;
  33. }
  34. }
  35. 复制代码

在这里我们GetUnityConfigurationSection根据ConfigFile获取UnityConfigurationSection ,ConfigFile为空则当前应用配置文件,不空则为路径。在这里我们为了性能,减少过多的IOC操作,读取配置文件,我们可以更具具体需要加入对配置文件UnityConfigurationSection的缓存(ConfigFile作为key,UnityConfigurationSection为value )。

同时提供操作辅助方法:ELUnityUtility

  1. View Code
  2. public static class ELUnityUtility
  3. {
  4. public static T Resolve<T>() where T : class
  5. {
  6. return Resolve(typeof(T)) as T;
  7. }
  8. public static object Resolve(this Type type)
  9. {
  10. var attrs = type.GetCustomAttributes(typeof(Utils.UnityInjectionAttribute), true) as Utils.UnityInjectionAttribute[];
  11. if (attrs != null && attrs.Length > 0)
  12. {
  13. var attr = attrs[0];
  14. var unitySection = attr.GetUnityConfigurationSection();
  15. if (unitySection != null)
  16. {
  17. var container = new Microsoft.Practices.Unity.UnityContainer().LoadConfiguration(unitySection, string.IsNullOrEmpty(attr.Container) ? unitySection.Containers.Default.Name : attr.Container);
  18. var obj = string.IsNullOrEmpty(attr.Name) ? container.Resolve(type) : container.Resolve(type, attr.Name);
  19. if (obj != null)
  20. {
  21. var piabAtttr = obj.GetType().GetCustomAttributes(typeof(ELPolicyinjectionAttribute), false) as ELPolicyinjectionAttribute[];
  22. if (piabAtttr.Length > 0)
  23. {
  24. obj = Microsoft.Practices.EnterpriseLibrary.PolicyInjection.PolicyInjection.Wrap(type, obj);
  25. }
  26. return obj;
  27. }
  28. }
  29. }
  30. return null;
  31. }
  32. public static IEnumerable<T> ResolveAll<T>() where T : class
  33. {
  34. return ResolveAll(typeof(T)) as IEnumerable<T>;
  35. }
  36. public static object ResolveAll(this Type type)
  37. {
  38. var attrs = type.GetCustomAttributes(typeof(Utils.UnityInjectionAttribute), true) as Utils.UnityInjectionAttribute[];
  39. if (attrs != null && attrs.Length > 0)
  40. {
  41. var attr = attrs[0];
  42. var unitySection = attr.GetUnityConfigurationSection();
  43. if (unitySection != null)
  44. {
  45. var container = new Microsoft.Practices.Unity.UnityContainer().LoadConfiguration(unitySection, string.IsNullOrEmpty(attr.Container) ? unitySection.Containers.Default.Name : attr.Container);
  46. return container.ResolveAll(type);
  47. }
  48. }
  49. return null;
  50. }
  51. }
  52. 复制代码

这里我们就可以很简便的获取IOC翻转。注:这里还有根据具体实现是否具体ELPolicyinjectionAttribute来决定是否进行PIAB的AOP操作,当然我们也可以在Unity配置文件中引入节点扩展

Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, 
                    Microsoft.Practices.Unity.Interception.Configuration

(PIAB利用的是透明代理速度较慢所以一般很少使用,当然你也可以实现具体的PIAB AOP方式比如注入MSIL,但我们已经有了很多注入MSIL的AOP框架了,我不准备去造轮子),ELPolicyinjectionAttribute:

  1. View Code
  2. [AttributeUsage(AttributeTargets.Class)]
  3. public class ELPolicyinjectionAttribute : Attribute
  4. {
  5. public string Name
  6. {
  7. get;
  8. set;
  9. }
  10. }
  11. 复制代码

这样:我们的客户端 就可以很简单的使用了:

  1. View Code
  2. class Program
  3. {
  4. static void Main(string[] args)
  5. {
  6. ELUnityUtility.Resolve<IClass2>().Show();
  7. (typeof(IClass2).Resolve() as IClass2).Show();
  8. Console.Read();
  9. }
  10. }
  11. public interface IClass1
  12. {
  13. void Show();
  14. }
  15. [Green.Utils.ELPolicyinjection]
  16. public class Class1 : IClass1
  17. {
  18. #region IClass1 成员
  19. [TestCallHandler]
  20. public void Show()
  21. {
  22. Console.WriteLine(this.GetType());
  23. }
  24. #endregion
  25. }
  26. [Green.Utils.UnityInjection("First", Name = "class2", ConfigFile = "App1.config")]
  27. public interface IClass2
  28. {
  29. void Show();
  30. }
  31. public class Class2 : ConsoleApplication1.IClass2
  32. {
  33. [Microsoft.Practices.Unity.Dependency("class1")]
  34. public IClass1 Class1
  35. {
  36. get;
  37. set;
  38. }
  39. public void Show()
  40. {
  41. Console.WriteLine(this.GetType());
  42. Class1.Show();
  43. }
  44. }
  45. 复制代码

App1.Config配置:

  1. View Code
  2. <?xml version="1.0" encoding="utf-8" ?>
  3. <configuration>
  4. <configSections>
  5. <section name="unity"
  6. type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
  7. Microsoft.Practices.Unity.Configuration"/>
  8. </configSections>
  9. <unity xmlns="http://schemas.microsoft.com/practices/2010/unity%22>
  10. <container name="First">
  11. <register type="ConsoleApplication1.IClass1,ConsoleApplication1" mapTo="ConsoleApplication1.Class1,ConsoleApplication1" name="class1" />
  12. <register type="ConsoleApplication1.IClass2,ConsoleApplication1" mapTo="ConsoleApplication1.Class2,ConsoleApplication1" name="class2"  />
  13. </container>
  14. </unity>
  15. </configuration>
  16. 复制代码

下边是一个完整的带PIAB的例子:

  1. View Code
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using Green.Utils;
  7. using Microsoft.Practices.Unity.InterceptionExtension;
  8. using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
  9. namespace ConsoleApplication1
  10. {
  11. class Program
  12. {
  13. static void Main(string[] args)
  14. {
  15. ELUnityUtility.Resolve<IClass2>().Show();
  16. (typeof(IClass2).Resolve() as IClass2).Show();
  17. Console.Read();
  18. }
  19. }
  20. public interface IClass1
  21. {
  22. void Show();
  23. }
  24. [Green.Utils.ELPolicyinjection]
  25. public class Class1 : IClass1
  26. {
  27. #region IClass1 成员
  28. [TestCallHandler]
  29. public void Show()
  30. {
  31. Console.WriteLine(this.GetType());
  32. }
  33. #endregion
  34. }
  35. [Green.Utils.UnityInjection("First", Name = "class2", ConfigFile = "App1.config")]
  36. public interface IClass2
  37. {
  38. void Show();
  39. }
  40. [Green.Utils.ELPolicyinjection]
  41. public class Class2 : ConsoleApplication1.IClass2
  42. {
  43. [Microsoft.Practices.Unity.Dependency("class1")]
  44. public IClass1 Class1
  45. {
  46. get;
  47. set;
  48. }
  49. [TestCallHandler]
  50. public void Show()
  51. {
  52. Console.WriteLine(this.GetType());
  53. Class1.Show();
  54. }
  55. }
  56. [Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ConfigurationElementType(typeof(CustomCallHandlerData))]
  57. public class TestCallHandler : ICallHandler
  58. {
  59. #region ICallHandler 成员
  60. public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
  61. {
  62. if (input == null) throw new ArgumentNullException("input");
  63. if (getNext == null) throw new ArgumentNullException("getNext");
  64. Console.WriteLine("begin....");
  65. var result = getNext()(input, getNext);
  66. Console.WriteLine("end....");
  67. return result;
  68. }
  69. public int Order
  70. {
  71. get;
  72. set;
  73. }
  74. #endregion
  75. }
  76. [AttributeUsage(AttributeTargets.Method)]
  77. public class TestCallHandlerAttribute : HandlerAttribute
  78. {
  79. public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container)
  80. {
  81. return new TestCallHandler();
  82. }
  83. }
  84. }
  85. 复制代码

欢迎大家指正,批评,交流是的大家都功能进步。代码下载

本文转自 破狼 51CTO博客,原文链接:http://blog.51cto.com/whitewolfblog/835199,如需转载请自行联系原作者

利用Attribute简化Unity框架IOC注入相关推荐

  1. Entity Framework 实体框架的形成之旅--利用Unity对象依赖注入优化实体框架(2)

    在本系列的第一篇随笔<Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)>中介绍了Entity Framework 实体框架的一些基础知识,以及构建 ...

  2. 深入理解IOC模式及Unity框架

    学习IOC发现如下博客写的很清楚了,故Mark下来以便以后查阅和温习! 1.IoC模式:http://www.cnblogs.com/qqlin/archive/2012/10/09/2707075. ...

  3. 框架依赖注入和普通依赖注入_角服务和依赖注入解释

    框架依赖注入和普通依赖注入 服务和喷油器 (Services and Injectors) Components are responsible for the data that renders i ...

  4. 利用Solrj技术+SSM框架完成仿京东搜索功能

    完成该功能的前提是配置好Solr服务器,这一部分内容可以参考博主上一篇的内容:基于Lucene的全文搜索服务器solr 一.利用Solrj技术+SSM框架完成仿京东搜索功能 1.如果不想配置solr服 ...

  5. 框架依赖注入和普通依赖注入_依赖注入快速入门:它是什么,以及何时使用它...

    框架依赖注入和普通依赖注入 by Bhavya Karia 通过Bhavya Karia 介绍 (Introduction) In software engineering, dependency i ...

  6. MVC3 中使用Unity实现依赖注入

    前言:前段时间一直在研究依赖注入,不过不是在MVC框架中使用,今天突然想到在MVC中使用Unity实现依赖注入,一时慌了,不知道从何下手,接着就是网上不停的找资料,下面我把我找到的资料分享下,也把我的 ...

  7. 《撸代码 学习 IOC注入技术1 》—— 布局注入 与 控件注入

    不诗意的女程序媛不是好厨师~ 转载请注明出处,From李诗雨-https://blog.csdn.net/cjm2484836553/article/details/104539874 [源代码下载地 ...

  8. 《撸代码学习 IOC注入技术2》—— 事件注入

    不诗意的女程序媛不是好厨师~ 转载请注明出处,From李诗雨-https://blog.csdn.net/cjm2484836553/article/details/104581855 源代码下载地址 ...

  9. 【机器学习实战】第14章 利用SVD简化数据

    第14章 利用SVD简化数据 SVD 概述 奇异值分解(SVD, Singular Value Decomposition):提取信息的一种方法,可以把 SVD 看成是从噪声数据中抽取相关特征.从生物 ...

最新文章

  1. SAP HUM 如何将2个HU合并并成一个?
  2. sql server 根据身份证号计算出生日期和年龄的存储过程
  3. linux思考の为何要挂载
  4. Vue warn Failed to mount component: template or render function not defined
  5. rest_framework08:分页器/根据ip进行频率限制
  6. Unity调用动态链接库dll和so
  7. MultiThread
  8. 数字化工厂-Process Simulate中的运动学定义
  9. kettle工具使用教程
  10. 计算机无法连接到桌面,Win7系统桌面天气小工具提示解决方案无法连接到服务...
  11. MapGuide应用最佳实践—MapGuide Server和MapGuide WebExtension分开部署
  12. 面板模型混合效应模型_树助混合效应模型
  13. java爬虫爬取b站视频分享iframe代码并保存10000条数据到数据库
  14. 软考网络工程师选择题题目(含答案)
  15. 如何使用TeamViewer远程控制电脑?三步即可成功
  16. 【MySQL】5.7新特性之七
  17. 带货直播源码,浅谈直播实现过程和技术
  18. Python 分数阶傅里叶变换
  19. Cesium空间分析、Cesium通视分析
  20. 生物蛋白质数据库类型【总结】

热门文章

  1. Autohotkey puretext
  2. smartbits的国产版本minismb-如何测试路由器
  3. 教你辨别36k纯数据科学家
  4. 《与编码人员一起工作》作者访谈
  5. ajax跨域问题解决方案
  6. Xcode_9_beta.xip 更新下载
  7. Linux常用的Shell命令
  8. hql 语法与详细解释转
  9. DataGrid的使用
  10. 组策略之账户安全设置