首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WCF 自訂配置檔完整指南:服務端與客戶端獨立配置最佳實踐

     編輯:關於.NET

為什麼需要獨立 WCF 配置檔?

預設 WCF 設定寫在 app.config/web.config 中,修改會導致應用程式重啟 (ASP.NET) 或需重新部署。獨立配置檔優勢:

  • 修改不觸發應用程式重啟
  • 配置邏輯隔離,維護性更佳
  • 支援多環境部署 (開發/測試/生產) 只需替換配置檔

但 WCF <system.serviceModel> 區段不支援 configSource 屬性,需程式碼介入。

服務端:重寫 ServiceHost.ApplyConfiguration()

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();
}

客戶端:重寫 ChannelFactory<T>.CreateDescription()

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();

配置檔結構範例 (MyService.config)

<?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 監控配置檔變更自動重載
  • 敏感資訊 (連線字串、憑證) 建議加密儲存或使用 Azure Key Vault
  • 單元測試時可注入記憶體內配置 (ExeConfigurationFileMap 支援虛擬路徑)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved