自定義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

相關文章
相關標籤/搜索