自定义WCF的配置文件

WCF的承载既能够经过编码实现,也可以经过配置实现.并且使用配置,更有利于往后的维护和扩展。咱们常常会碰到这样的一个场景:须要把WCF的配置信息放在一个单独的文件中,这种状况常常出如今须要为本身开发的服务配置,须要采用独立的配置文件,而不是只能放到app.config/web.config中。.NET提供了一种机制是经过ConfigSource。例如在asp.net的在站点的默认 Web.Config 文件中使用:web

<appSettings configSource="customAppSetting.config"/>app

而后新建 customAppSetting.Config 文件:asp.net

<?xml version="1.0" encoding="utf-8"?>
<appSettings>
<add key="IsDev" value="True"/>
</appSettings>
在网站运行时,若是修改 Web.Config 文件会引发站点的重启,而修改 My.Config 文件则不会,同时也提升了配置文件的可读性。
然而WCF的配置上configSource是无效的,那么WCF如何自定义配置文件?
WCF的ServiceHost和ChannelFactory<T>分别提供了服务端和客户端的可扩展解决方案。下面针对这两个对象分别说明如何自定义服务端和客户端的配置文件。
一、服务端自定义配置文件:在ServiceHost的父类ServiceHostBase中,有一个和配置文件的加载密切相关的方法,它为:
protected virtual void ApplyConfiguration();
这个方法用于将应用程序配置文件中<system.serviceModel>节点下的配置信息,转换成WCF的具体服务设置。那么重写这个方法,代码以下:

/// <summary>
/// override ApplyConfiguration to load config from custom file
/// </summary>
protected override void ApplyConfiguration()
{
//get custom config file name by our rule: config file name = ServiceType.Name
var myConfigFileName = this.Description.ServiceType.FullName;
//get config file path
string dir = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
string myConfigFilePath = System.IO.Path.Combine(dir, myConfigFileName + ".config");
if (!System.IO.File.Exists(myConfigFilePath))
{
base.ApplyConfiguration();
return;
}
var configFileMap = new System.Configuration.ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = myConfigFilePath;
var config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
var serviceModel = System.ServiceModel.Configuration.ServiceModelSectionGroup.GetSectionGroup(config);
if (serviceModel == null)
{
base.ApplyConfiguration();
return;
}
foreach (ServiceElement serviceElement in serviceModel.Services.Services)
{
if (serviceElement.Name == this.Description.ServiceType.FullName)
{
LoadConfigurationSection(serviceElement);
return;
}
}
throw new Exception("there is no service element match the description!");
}
}
}ide

二、WCF的客户端自定义配置文件,WCF能够经过两种方式构建代理,ClientBase<T>和ChannelFactory<T>,ClientBase最终也是经过ChannelFactory<T>来构建Channel的
ChannelFactory<T>有两个方法为自定义配置文件提供解决方案:

protected virtual void ApplyConfiguration(string configurationName);
protected abstract ServiceEndpoint CreateDescription();网站

ApplyConfiguration方法和ServiceHost的ApplyConfiguration方法的功能相似,可是有一点不一样的是须要和CreateDescription交互。其实ApplyConfiguration并非客户端代理这里所要关注的地方,咱们只须要关注CreateDescription就能够了。this

ChannelFactory<T>的方法CreateDescription实现上是从默认配置文件(缺省AppDomain的配置文件),因此咱们经过重写这个方法就能够实现从外部文件加载配置。编码

/// <summary>.net

/// Loads the serviceEndpoint description from the specified configuration file代理

/// </summary>orm

/// <returns></returns>

protected override ServiceEndpoint CreateDescription()

{

   ServiceEndpoint serviceEndpoint = base.CreateDescription();

   ExeConfigurationFileMap map = new ExeConfigurationFileMap();

   map.ExeConfigFilename = this.configurationPath;

   Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);

   ServiceModelSectionGroup group = ServiceModelSectionGroup.GetSectionGroup(config);

   ChannelEndpointElement selectedEndpoint = null;

   foreach (ChannelEndpointElement endpoint in group.Client.Endpoints)

   {

      if (endpoint.Contract == serviceEndpoint.Contract.ConfigurationName)

      {

        selectedEndpoint = endpoint;

        break;

      }

    }

    if (selectedEndpoint != null)

    {

      if (serviceEndpoint.Binding == null)

      {

        serviceEndpoint.Binding = CreateBinding(selectedEndpoint.Binding, group);

      }

      if (serviceEndpoint.Address == null)

      {

        serviceEndpoint.Address = new EndpointAddress(selectedEndpoint.Address, GetIdentity(selectedEndpoint.Identity), selectedEndpoint.Headers.Headers);

      }

      if (serviceEndpoint.Behaviors.Count == 0 && selectedEndpoint.BehaviorConfiguration != null)

      {

        AddBehaviors(selectedEndpoint.BehaviorConfiguration, serviceEndpoint, group);

      }

      serviceEndpoint.Name = selectedEndpoint.Contract;

    }

    return serviceEndpoint;

}

具体的实现能够参看例子代码,这个例子WCF sdk的例子ICalculator。代码下载CustomChannel.zip

相关文章
相关标签/搜索