首页 / 软件开发 / .NET编程技术 / WCF后续之旅(7):通过WCF Extension实现和Enterprise Library
WCF后续之旅(7):通过WCF Extension实现和Enterprise Library2011-01-03 cnblogs artech松耦合、高内聚是我们进行设计的永恒的目标,如何实现这样的目标呢?我们有很多实现的方式和方法,不管这些方式和方法在表现形式上有什么不同,他们的思想都可以表示为:根据稳定性进行关注点的分离或者分解,交互双方依赖于一个稳定的契约,而降低对对方非稳定性因素的依赖。从抽象和稳定性的关系来讲,抽象的程度和稳定程度成正相关关系。由此才有了我们面向抽象编程的说法,所以“只有依赖于不变,才能应万变”。然后,对于面向对象的思想来讲,我们的功能通过一个个具体的对象来承载。对象是具体的,不是抽象的;创建对象是必然的;对象的创建从某种程度上即使对面向抽象的违背。所以模块之间的耦合度在很大程度上是由于对象创建的方式决定的,而在对象创建过程实现解耦是实现我们“松耦合、高内聚”目标的一个重要途径。对于这一点,我们可以看看我们常用的设计模式中有多少是用于解决如何合理进行对象创建的就可以知道了。Enterprise Library推出的新的Application Block:Unity Application Block为我们提供了一个很好的、可扩展的框架,帮助我们合理、有效的创建对象,并解决创建对象中的依赖。而通过WCF一个简单的扩展对象,就可以很容易地实现和Unity的集成。1、Unity Application Block由于本篇文章的重点仍然是对WCF的扩展,因此我不会花太多的篇幅对Enterprise Library Unity作详细的介绍。这是比较官方的定义:"The Unity Application Block (Unity) is a lightweight, extensible dependency injection container with support for constructor, property, and method call injection”. Unity实际是建立在ObjectBuilder基础之上,而ObjectBuilder是整个Enterprise Library的基石(实际上还不止于此,MS P&P开发的很多的开源框架都依赖于ObjectBuilder,比如CAB、SCSF等),为我们提供了一个可扩展的、基于策略(strategy based)对象创建方式。借助于ObjectBuilder,Unity可以帮助我们基于Interface或者abstract class创建对象;可以帮助我们管理对象的生命周期;以及实现依赖注入(DI:Dependency Injection)。下面是3种主要的DI方式:Constructor Injection:帮助我们选择我们需要的构造函数来创建对象。Property (Setter) Injection:帮助我们在创建的对象上自动设置某些必要的属性值。Method Injection:帮助我们在对象上调用我们指定的方法做一些初始化的工作。如果读者想进一步了解Unity Application Block和Enterprise Library,可以访问微软P&P 的网站。2、实现基于Unity的IntanceProvider在本系列的第三部分对Dispachter的介绍,和第四部分对WCF可扩展点的介绍中,我提到了一个重要的对象InstanceProvider, 该对象用于service instance的创建。既然Unity的根本目的是创建对象,我们就可以自定义InstanceProvider,让Unity来帮助创建service instance,很容易地实现了和Unity的集成。下面是我们的自定义InstanceProvider:UnityInstanceProvidernamespace Artech.WCFExtensions{
public class UnityInstanceProvider: IInstanceProvider
{
private Type _contractType;
private string _containerName;
public UnityInstanceProvider(Type contractType, string containerName)
{
if (contractType == null)
{
throw new ArgumentNullException("contractType");
}
this._containerName = containerName;
this._contractType = contractType;
}
#region IInstanceProvider Members
public object GetInstance(InstanceContext instanceContext, Message message)
{
UnityConfigurationSection unitySection = ConfigurationManager.GetSection("unity") as UnityConfigurationSection;
if (unitySection == null)
{
throw new ConfigurationErrorsException(string.Format(CultureInfo.CurrentCulture, Resources.MissUnityConfiguration));
}
IUnityContainer container = new UnityContainer();
UnityContainerElement containerElement;
if (string.IsNullOrEmpty(this._containerName))
{
containerElement = unitySection.Containers.Default;
}
else
{
containerElement = unitySection.Containers[this._containerName];
}
containerElement.Configure(container);
UnityTypeElement[] unityTypeElements = Array.CreateInstance(typeof(UnityTypeElement), containerElement.Types.Count) as UnityTypeElement[];
containerElement.Types.CopyTo(unityTypeElements, 0);
if (unityTypeElements.Where(element => element.Type == this._contractType).Count() == 0)
{
container.RegisterType(this._contractType, instanceContext.Host.Description.ServiceType);
}
return container.Resolve(this._contractType);
}
public object GetInstance(InstanceContext instanceContext)
{
return this.GetInstance(instanceContext, null);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
IDisposable disposable = instance as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
#endregion
}
}