由於工作幾個月來框架開發已經好久沒寫博客了,今天想抽點時間出來冒泡。在領域驅動開發中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
{
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), false) as 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 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
{
[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
[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.HelloService1,WcfService" > </ register >
IOC,AOP博客參考:
