4.1 扩展 ServiceHost的背景
_____________________________________________________________
我们不能让这个App.config跟我们的exe文件在一起,这样的耦合是我们的不想要的,扩展ServiceHost的原因是:我们需要解除这样的限制。
好了。了解这点后。我们需要了解ServiceHost内部是如何操作App.config的,如果了解成功,我们自己就可以操作App.config而不是让程序自动去操作App.config
4.2 关于App.config
_____________________________________________________________
如你所见:
App.config核心参数由三部分构成,分别是服务、绑定与行为:
Services : 服务节点
Bindings : 绑定节点。为服务节点服务
Behaviors: 行为。为服务节点服务
关键点:
1) 绑定与行为都是为Services中的信息服务的。
2) 我们猜想ServiceHost操作了这三部分参数。如果我们能重写ServiceHost对配置的操作,我们自己不就可以操作App.config了吗?
3) 你猜对了。ServiceHost的确为继承者提供了这样的便利,我们可以通过重写ServiceHost中的
protected virtual void ApplyConfiguration();
虚方法,把Services中的节点信息,Bindings中的信息、Behaviors中的节点信息加入ServiceHost.Description属性中 就能能达成这一目的。
接下来我们要干的工作很明确了。我们要重写ApplyConfiguration
图 4.1 WCF服务端配置文件
原理清楚后,接来来就好办了:
1) 我们只需要写一个类继承ServiceHost.
2) 重写 ApplyConfiguration 把services/behaviors与bindings信息加入到ServiceHost的Description属性中
3) 并用 ExeConfigurationFileMap 修改App.config路径与文件名即可。
重写ServiceHost中ApplyConfiguration方法
#region Rewrite ApplyConfiguration
/// <summary>
/// Override ApplyConfiguration to load custom config file
/// Attention : ConfigPath must be static variable according to the follow rules:
/// 1. First run ApplyConfiguration of base class of ServiceHost
/// 2. Second run constructor of EIPServiceHost itself
/// </summary>
protected override void ApplyConfiguration()
{
// Check user config invalidation
if (!CheckConfigExist(ConfigPath))
{
// Use default config
base.ApplyConfiguration();
return;
}
base.ApplyConfiguration();
// Use user config
ExeConfigurationFileMap execfgMap = new ExeConfigurationFileMap();
// Set user config FilePath
execfgMap.ExeConfigFilename = ConfigPath;
// Config info
Configuration cfg = ConfigurationManager.OpenMappedExeConfiguration(execfgMap,ConfigurationUserLevel.None);
// Gets all service model config sections
ServiceModelSectionGroup servicemodelSections = ServiceModelSectionGroup.GetSectionGroup(cfg);
// Find serivce section matched with the name "this.Description.ServiceType.FullName"
if (!ApplySectionInfo(this.Description.ServiceType.FullName,servicemodelSections))
{
throw new Exception("ConfigApply Error : There is no endpoint existed in your config!! Please check your config file!");
}
this.ApplyMultiBehaviors(servicemodelSections);
}
添加services信息与bindings信息
/// <summary>
/// Add behaviors
/// </summary>
/// <param name="servicemodelSections"></param>
/// <returns></returns>
private bool ApplyMultiBehaviors(ServiceModelSectionGroup servicemodelSections)
{
if (servicemodelSections == null) return false;
foreach (ServiceBehaviorElement element in servicemodelSections.Behaviors.ServiceBehaviors)
{
foreach (BehaviorExtensionElement behavior in element)
{
BehaviorExtensionElement behaviorEx = behavior;
object extention = behaviorEx.GetType().InvokeMember("CreateBehavior",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null,
behaviorEx,
null);
if (extention == null) continue;
IServiceBehavior isb = (IServiceBehavior)extention;
//if (base.Description.Behaviors.Contains(isb)) break;
bool isbehaviorExisted = false;
foreach (IServiceBehavior i in base.Description.Behaviors)
{
if (i.GetType().Name == isb.GetType().Name)
{
isbehaviorExisted = true;
break;
}
}
if (isbehaviorExisted) break;
base.Description.Behaviors.Add((IServiceBehavior)extention);
}
}
return true;
}
本节的源代码下载:
_____________________________________________________________
_____________________________________________________________
到此。大功告成。
我们已经扩展了ServiceHost,能自定义用ServiceHost创建的WCF服务了。。。
下一节我们将扩展ChannelFactory.........................................
参考引文:
[1] Artech.WCF全面解析[M].2012
[2] O'Reilly.WCF编程[M].2009
[3] Adnrew Trolesen.C#与.net3.5/4高级程序设计[M].2009/2013