天天看點

利用Attribute簡化Unity架構IOC注入

     當然Unity架構中為我們提供了RegisterInstance,RegisterType方法我們可以在代碼中注冊到容器,比如NLayerApp中就在<code>IoCFactory中注冊一大堆抽象-具體關聯。但是在我們的實際實踐中一般會選擇另一種方式xml配置配置,因為這樣我們會得到更大的靈活性,需求變化隻要抽象接口不變,我們也隻需要在xml配置檔案中修改一行配置加入我們的具體實作,加入我們的程式集,就可以适應需求變化,這更滿足oo設計“開閉原則”。</code>

<code>   在這裡個人實踐利用抽象(接口)定義Attribute制定具體ConfigFile(配置檔案),Container(容器),Name(名稱)解決IOC植入,減少我們多次去讀取配置檔案。Unity為我們提供了在Web.config,App.config中配置注入資訊,或者注冊外部配置,但是很多時候我們更希望,在我們的 不同子產品下,應用不同的IOC配置資訊,這些可以減少維護的關聯少些,清晰,同時檔案夾的出現便于我們的配置資訊的管理。</code>

<code>Attribute實作:</code>

UnityInjectionAttributeView Code   

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]   

   public class UnityInjectionAttribute : Attribute   

   {   

       public UnityInjectionAttribute(string Container)   

       {   

           this.Container = Container;              

       }   

       public string Container   

           get;   

           set;   

       public string ConfigFile   

       public string Name   

       public Microsoft.Practices.Unity.Configuration.UnityConfigurationSection GetUnityConfigurationSection()   

           if (!string.IsNullOrEmpty(this.ConfigFile))   

           {   

               var fileMap = new System.Configuration.ExeConfigurationFileMap { ExeConfigFilename = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, this.ConfigFile) };   

               System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, System.Configuration.ConfigurationUserLevel.None);   

               return configuration == null ? null : configuration.GetSection(Microsoft.Practices.Unity.Configuration.UnityConfigurationSection.SectionName) as Microsoft.Practices.Unity.Configuration.UnityConfigurationSection;   

           }   

           return System.Configuration.ConfigurationManager.GetSection(Microsoft.Practices.Unity.Configuration.UnityConfigurationSection.SectionName) as Microsoft.Practices.Unity.Configuration.UnityConfigurationSection;   

   }   

複制代碼 

在這裡我們GetUnityConfigurationSection根據ConfigFile擷取UnityConfigurationSection ,ConfigFile為空則目前應用配置檔案,不空則為路徑。在這裡我們為了性能,減少過多的IOC操作,讀取配置檔案,我們可以更具具體需要加入對配置檔案UnityConfigurationSection的緩存(ConfigFile作為key,UnityConfigurationSection為value )。

   同時提供操作輔助方法:ELUnityUtility

View Code   

public static class ELUnityUtility   

       public static T Resolve&lt;T&gt;() where T : class   

           return Resolve(typeof(T)) as T;   

       public static object Resolve(this Type type)   

           var attrs = type.GetCustomAttributes(typeof(Utils.UnityInjectionAttribute), true) as Utils.UnityInjectionAttribute[];   

           if (attrs != null &amp;&amp; attrs.Length &gt; 0)   

               var attr = attrs[0];   

               var unitySection = attr.GetUnityConfigurationSection();   

               if (unitySection != null)   

               {   

                   var container = new Microsoft.Practices.Unity.UnityContainer().LoadConfiguration(unitySection, string.IsNullOrEmpty(attr.Container) ? unitySection.Containers.Default.Name : attr.Container);   

                   var obj = string.IsNullOrEmpty(attr.Name) ? container.Resolve(type) : container.Resolve(type, attr.Name);   

                   if (obj != null)   

                   {   

                       var piabAtttr = obj.GetType().GetCustomAttributes(typeof(ELPolicyinjectionAttribute), false) as ELPolicyinjectionAttribute[];   

                       if (piabAtttr.Length &gt; 0)   

                       {   

                           obj = Microsoft.Practices.EnterpriseLibrary.PolicyInjection.PolicyInjection.Wrap(type, obj);   

                       }   

                       return obj;   

                   }   

               }   

           return null;   

       public static IEnumerable&lt;T&gt; ResolveAll&lt;T&gt;() where T : class   

           return ResolveAll(typeof(T)) as IEnumerable&lt;T&gt;;   

       public static object ResolveAll(this Type type)   

                   return container.ResolveAll(type);   

   }  

這裡我們就可以很簡便的擷取IOC翻轉。注:這裡還有根據具體實作是否具體ELPolicyinjectionAttribute來決定是否進行PIAB的AOP操作,當然我們也可以在Unity配置檔案中引入節點擴充

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

                    Microsoft.Practices.Unity.Interception.Configuration

(PIAB利用的是透明代理速度較慢是以一般很少使用,當然你也可以實作具體的PIAB AOP方式比如注入MSIL,但我們已經有了很多注入MSIL的AOP架構了,我不準備去造輪子),ELPolicyinjectionAttribute:

[AttributeUsage(AttributeTargets.Class)]   

   public class ELPolicyinjectionAttribute : Attribute   

這樣:我們的用戶端 就可以很簡單的使用了:

class Program   

       static void Main(string[] args)   

           ELUnityUtility.Resolve&lt;IClass2&gt;().Show();   

           (typeof(IClass2).Resolve() as IClass2).Show();   

           Console.Read();   

   public interface IClass1   

       void Show();   

   [Green.Utils.ELPolicyinjection]   

   public class Class1 : IClass1   

       #region IClass1 成員   

       [TestCallHandler]   

       public void Show()   

           Console.WriteLine(this.GetType());   

       #endregion   

   [Green.Utils.UnityInjection("First", Name = "class2", ConfigFile = "App1.config")]   

   public interface IClass2   

    public class Class2 : ConsoleApplication1.IClass2   

       [Microsoft.Practices.Unity.Dependency("class1")]   

       public IClass1 Class1   

            public void Show()   

           Class1.Show();   

   }     

App1.Config配置:

&lt;?xml version="1.0" encoding="utf-8" ?&gt;   

&lt;configuration&gt;   

  &lt;configSections&gt;   

    &lt;section name="unity"   

             type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,   

             Microsoft.Practices.Unity.Configuration"/&gt;   

  &lt;/configSections&gt;   

  &lt;unity xmlns="http://schemas.microsoft.com/practices/2010/unity%22&gt;   

    &lt;container name="First"&gt;   

      &lt;register type="ConsoleApplication1.IClass1,ConsoleApplication1" mapTo="ConsoleApplication1.Class1,ConsoleApplication1" name="class1" /&gt;   

      &lt;register type="ConsoleApplication1.IClass2,ConsoleApplication1" mapTo="ConsoleApplication1.Class2,ConsoleApplication1" name="class2"  /&gt;   

    &lt;/container&gt;   

  &lt;/unity&gt;   

&lt;/configuration&gt;  

下邊是一個完整的帶PIAB的例子:

using System;   

using System.Collections.Generic;   

using System.Linq;   

using System.Text;   

using Green.Utils;   

using Microsoft.Practices.Unity.InterceptionExtension;   

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;   

namespace ConsoleApplication1   

{   

    class Program   

    {   

        static void Main(string[] args)   

        {   

            ELUnityUtility.Resolve&lt;IClass2&gt;().Show();   

            (typeof(IClass2).Resolve() as IClass2).Show();   

            Console.Read();   

        }   

    }   

    public interface IClass1   

        void Show();   

    [Green.Utils.ELPolicyinjection]   

    public class Class1 : IClass1   

        #region IClass1 成員   

        [TestCallHandler]   

        public void Show()   

            Console.WriteLine(this.GetType());   

        #endregion   

    [Green.Utils.UnityInjection("First", Name = "class2", ConfigFile = "App1.config")]   

    public interface IClass2   

        [Microsoft.Practices.Unity.Dependency("class1")]   

        public IClass1 Class1   

            get;   

            set;   

            Class1.Show();   

    [Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ConfigurationElementType(typeof(CustomCallHandlerData))]   

    public class TestCallHandler : ICallHandler   

        #region ICallHandler 成員   

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)   

            if (input == null) throw new ArgumentNullException("input");   

            if (getNext == null) throw new ArgumentNullException("getNext");   

            Console.WriteLine("begin....");   

            var result = getNext()(input, getNext);   

            Console.WriteLine("end....");   

            return result;   

        public int Order   

    [AttributeUsage(AttributeTargets.Method)]   

    public class TestCallHandlerAttribute : HandlerAttribute   

        public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container)   

            return new TestCallHandler();   

}  

 本文轉自 破狼 51CTO部落格,原文連結:http://blog.51cto.com/whitewolfblog/835199,如需轉載請自行聯系原作者