預設 WCF 設定寫在 app.config/web.config 中,修改會導致應用程式重啟 (ASP.NET) 或需重新部署。獨立配置檔優勢:
但 WCF <system.serviceModel> 區段不支援 configSource 屬性,需程式碼介入。
public class CustomServiceHost : ServiceHost
{
public CustomServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses) { }
protected override void ApplyConfiguration()
{
// 1. 依服務型別名稱定位專屬配置檔:{ServiceFullName}.config
string configName = this.Description.ServiceType.FullName + ".config";
string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, configName);
if (!File.Exists(configPath))
{
base.ApplyConfiguration(); // 回退預設行為
return;
}
// 2. 載入指定配置檔
var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = configPath };
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
var serviceModel = ServiceModelSectionGroup.GetSectionGroup(config);
if (serviceModel == null)
{
base.ApplyConfiguration();
return;
}
// 3. 比對服務名稱並載入對應區段
foreach (ServiceElement element in serviceModel.Services.Services)
{
if (element.Name == this.Description.ServiceType.FullName)
{
LoadConfigurationSection(element);
return;
}
}
throw new Exception($"配置檔中找不到服務: {this.Description.ServiceType.FullName}");
}
}
// 替代 new ServiceHost(...)
using (var host = new CustomServiceHost(typeof(MyService), baseAddresses))
{
host.Open();
Console.ReadLine();
}
public class CustomChannelFactory : ChannelFactory
{
private readonly string _configPath;
public CustomChannelFactory(string configPath)
{
_configPath = configPath;
}
protected override ServiceEndpoint CreateDescription()
{
ServiceEndpoint endpoint = base.CreateDescription();
var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = _configPath };
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
var group = ServiceModelSectionGroup.GetSectionGroup(config);
ChannelEndpointElement matched = null;
foreach (ChannelEndpointElement e in group.Client.Endpoints)
{
if (e.Contract == endpoint.Contract.ConfigurationName)
{
matched = e;
break;
}
}
if (matched != null)
{
if (endpoint.Binding == null)
endpoint.Binding = CreateBinding(matched.Binding, group);
if (endpoint.Address == null)
endpoint.Address = new EndpointAddress(matched.Address, GetIdentity(matched.Identity), matched.Headers.Headers);
if (endpoint.Behaviors.Count == 0 && matched.BehaviorConfiguration != null)
AddBehaviors(matched.BehaviorConfiguration, endpoint, group);
endpoint.Name = matched.Contract;
}
return endpoint;
}
}
var factory = new CustomChannelFactory(@"C:\Configs\Client.config");
IMyService proxy = factory.CreateChannel();
proxy.DoWork();
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<services>
<service name="MyNamespace.MyService">
<endpoint address="" binding="wsHttpBinding" contract="MyNamespace.IMyService" />
<host>
<baseAddresses>
<add baseAddress="https://localhost:8080/MyService" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
ConfigurationManager.RefreshSection 實現配置熱更新FileSystemWatcher 監控配置檔變更自動重載