WCF利用企業庫Unity框架的IOC層次解耦


     由於工作幾個月來框架開發已經好久沒寫博客了,今天想抽點時間出來冒泡。在領域驅動開發中SOA已經成為我們開發的主流技術,在面對當前眾多的UI框架選擇(asp.net mvc,silverlight,wpf,winform,wp7等一些列甚至跨語言),我們能夠重用和抽象的業務邏輯是不會變化的,為了屏蔽這些UI的復雜性和差異性,我們可能會采用諸如wcf soap的服務發布。再說在領域驅動開發中我們肯定會把各個邏輯分層次隔離解除耦合,這就出現了N層架構,在於我們的每一層次之間的耦合度當前流程的解決方案IOC框架,以及業務解耦AOP。這里要解決的是SOA框架WCF和IOC框架的結合。

    WCF框架是一個極易擴展的框架,提供了非常多的擴展點(InstanceProvider,MessageInspector,CallContextInitializer,MessageFilter,MessageFormatter,ParameterInspector等等)。在這里IOC是作為一個容器組裝創建的框架,我們需要的是對服務對象的創建,所以我們選擇的當然是InstanceProvider擴展點。

     多說一句廢話,正如前篇利用Attribute簡化Unity框架IOC注入AOP之PostSharp7-解決IOC 不能直接new問題,簡化IOC開發和IOC對象LazyLoad中所說,我是一個固執的人,個人希望注入支持自定義配置文件,不喜歡把配置信息全部寫在一個web.config/app.config中,也不喜歡el的寫在同一個外部配置文件中,傾向於每個模塊在一個不同的配置文件,並在模塊中在區分container容器,所以特別寫了每個單獨配置文件的延時加載,緩存。

      下面就是對InstanceProvider的擴展:

View Code
public  class ELUnityInstanceProvider : IInstanceProvider 
   { 
        private Type contractType; 
        private  string container; 
        private  string configFile; 
        private  string name; 
        private  static  object lockObj =  new  object(); 
        private  static Dictionary< string, UnityConfigurationSection> sectionDict =  new Dictionary< string, UnityConfigurationSection>(); 

        public ELUnityInstanceProvider(Type contractType,  string container,  string configFile,  string name) 
       { 
            this.name = name; 
            this.configFile = configFile; 
            this.contractType = contractType; 
            this.container = container; 
       } 

        #region IInstanceProvider 成員 

        public  object GetInstance(System.ServiceModel.InstanceContext instanceContext, System.ServiceModel.Channels.Message message) 
       { 
           Microsoft.Practices.Unity.Configuration.UnityConfigurationSection unitySection = GetUnityConfigurationSection(); 

            if (unitySection !=  null
           { 
                var container =  new Microsoft.Practices.Unity.UnityContainer().LoadConfiguration(unitySection,  string.IsNullOrEmpty( this.container) ? unitySection.Containers.Default.Name :  this.container); 
                var obj =  string.IsNullOrEmpty( this.name) ? container.Resolve( this.contractType) : container.Resolve( this.contractType,  this.name); 

                var piabAtttr = obj.GetType().GetCustomAttributes( typeof(ELPolicyinjectionAttribute),  falseas ELPolicyinjectionAttribute[]; 
                if (piabAtttr.Length >  0
               { 
                   obj = Microsoft.Practices.EnterpriseLibrary.PolicyInjection.PolicyInjection.Wrap( this.contractType, obj); 
               } 
                return obj; 
           } 
            return  null
       } 
        private Microsoft.Practices.Unity.Configuration.UnityConfigurationSection GetUnityConfigurationSection() 
       { 
            if (! string.IsNullOrEmpty( this.configFile)) 
           { 
                if (!sectionDict.ContainsKey( this.configFile)) 
               { 
                    lock (lockObj) 
                   { 
                        if (!sectionDict.ContainsKey( this.configFile)) 
                       { 
                           Microsoft.Practices.Unity.Configuration.UnityConfigurationSection unitySection =  null
                            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); 
                           unitySection = configuration ==  null ?  null : configuration.GetSection(Microsoft.Practices.Unity.Configuration.UnityConfigurationSection.SectionName)  as Microsoft.Practices.Unity.Configuration.UnityConfigurationSection; 
                            if (unitySection ==  null
                                return  null
                           sectionDict.Add( this.configFile, unitySection); 
                       } 
                   } 
               } 
                return sectionDict[ this.configFile]; 
           } 

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

       } 

        public  object GetInstance(System.ServiceModel.InstanceContext instanceContext) 
       { 
            return  this.GetInstance(instanceContext,  null); 
       } 

        public  void ReleaseInstance(System.ServiceModel.InstanceContext instanceContext,  object instance) 
       { 
           IDisposable disposable = instance  as IDisposable; 
            if (disposable !=  null
           { 
               disposable.Dispose(); 
           } 
           instance =  null
       } 

        #endregion 
   }

     下面我們需要已Attribute方式貼在Contract上:

View Code
public  class ELUnityBehaviorAttribute : Attribute, IContractBehavior 
   { 
        public  string Container 
       { 
            get
            set
       } 

        public  string ConfigFile 
       { 
            get
            set
       } 

        public  string Name 
       { 
            get
            set
       } 

        #region IContractBehavior 成員 

        public  void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) 
       { 

       } 

        public  void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime) 
       { 

       } 

        public  void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime) 
       { 
           dispatchRuntime.InstanceProvider =  new ELUnityInstanceProvider(contractDescription.ContractType,  this.Container,  this.ConfigFile,  this.Name); 
       } 

        public  void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint) 
       { 
       } 

        #endregion 
   }
 

     對於wcf同時我們也該支持配置文件擴展:

View Code
public  class ELUnityBehaviorElement : BehaviorExtensionElement 
   { 
       [ConfigurationProperty( " Container ", IsRequired =  false, DefaultValue =  "")] 
        public  string Container 
       { 
            get
            set
       } 

       [ConfigurationProperty( " ConfigFile ", IsRequired =  false, DefaultValue =  "")] 
        public  string ConfigFile 
       { 
            get
            set
       } 

       [ConfigurationProperty( " Name ", IsRequired =  false, DefaultValue =  "")] 
        public  string Name 
       { 
            get
            set
       } 

        protected  override  object CreateBehavior() 
       { 
            return  new ELUnityBehavior( this.Container,  this.ConfigFile,  this.Name); 
       } 

        public  override Type BehaviorType 
       { 
            get {  return  typeof(ELUnityBehavior); } 
       } 
   }

public  class ELUnityBehavior : IEndpointBehavior 
   { 
        public  string Container 
       { 
            get
            set
       } 

        public  string ConfigFile 
       { 
            get
            set
       } 

        public  string Name 
       { 
            get
            set
       } 

        public ELUnityBehavior( string container,  string configFile,  string name) 
       { 
            this.Name = name; 
            this.ConfigFile = configFile; 
            this.Container = container; 
       } 
        #region IEndpointBehavior 成員 

        public  void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) 
       { 

       } 

        public  void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime) 
       { 

       } 

        public  void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) 
       { 
           endpointDispatcher.DispatchRuntime.InstanceProvider =  new ELUnityInstanceProvider(endpoint.Contract.ContractType,  this.Container,  this.ConfigFile,  this.Name); 
       } 

        public  void Validate(ServiceEndpoint endpoint) 
       { 

       } 

        #endregion 
   }

目前我們已經簡單實現了:看看測試:

View Code
Contract:

   [ServiceContract()] 
   [Green.WCFExtensions.ELUnityBehavior(Container =  " test ", ConfigFile =  " App1.config ")]   
   public  interface IHelloService 
  { 
      [OperationContract] 
       string Say( string name); 
  }

Service:

public  class HelloService1 : IHelloService 
   { 
       [Microsoft.Practices.Unity.Dependency( " proxy ")] 
        public IHelloService Service 
       { 
            get
            set
       } 

        #region IHelloService 成員 
           public  string Say( string name) 
       { 
                      return Service.Say(name); 

       } 

        #endregion 
   } 

    public  class HelloServiceProxy : IHelloService 
   { 
        #region IHelloService 成員 
        public  string Say( string name) 
       { 
            return  string.Format( " Hello:{0} ", name); 
       } 

        #endregion 
   }

配置app1.config:

< register  type ="WcfService.IHelloService,WcfService"  mapTo ="WcfService.HelloServiceProxy,WcfService"   name ="proxy" >  </ register > 
< register  type ="WcfService.IHelloService,WcfService"  mapTo ="WcfService.HelloService1,WcfService"   >  </ register >

IOC,AOP博客參考:

  • AOP之PostSharp初見-OnExceptionAspect
  • AOP之PostSharp2-OnMethodBoundaryAspect
  • AOP之PostSharp3-MethodInterceptionAspect
  • AOP之PostSharp4-實現類INotifyPropertyChanged植入
  • AOP之PostSharp5-LocationInterceptionAspect
  • AOP之PostSharp6-EventInterceptionAspect
  • AOP之PostSharp7-解決IOC 不能直接new問題,簡化IOC開發和IOC對象LazyLoad
  • http://www.cnblogs.com/whitewolf/category/312638.html
  • 利用Attribute簡化Unity框架IOC注入

  • 免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM