2011-07-20 55 views
3

我有一個WCF服務XYZ將在多個主機進行部署。每個這樣的服務都可以連接到部署在其他主機上的另一個XYZ服務。這是一個分佈式系統,各州之間的服務會有所不同。WCF C# - 獲取具體的配置值從App.config中

爲了傳達它並沒有真正意義對我來說,在Visual Studio中的「添加服務引用」,因爲這隻會增加冗餘(服務已經知道它要與之通信)。

所以目前我的想法是在每個服務的App.config文件到指定其他服務端點。例如:現在

<client> 
    <endpoint name="BEL" 
      address="tcp://us.test.com:7650/OrderManagementService" 
      binding="tcpBinding" 
      contract="IOrderManagementService"/> 
    <endpoint name="BEL2" 
     address="tcp://us.test2.com:7650/OrderManagementService" 
     binding="tcpBinding" 
     contract="IOrderManagementService"/> 
</client> 

,我只想要一個方式來閱讀這些設置,並在我的代碼創建ChannelFactories和渠道。但是,這樣做很麻煩。

兩個問題:我在做正確的事情;如果是這樣,從配置文件中提取這些值的最佳方法是什麼?

+0

這個問題http://stackoverflow.com/questions/297431/channelfactory-dont-have-an-address-on-the-endpoint-why可能有幫助 –

回答

3

直接創建通道並不難,並且所有端點配置都是爲您讀取的。一旦

var factory = new ChannelFactory<IOrderManagementService>("BEL"); 
var proxy = factory.CreateChannel(); 
// call methods on proxy 
proxy.Close(); 

注意,代理需要正確地關閉(這意味着正確調用CloseAbort),您已完成了它:嘗試這樣的事情。但是,即使在緩存中,您也可以長時間打開工廠。如果我沒有理解你的問題是類似的東西我想做的事

public static ChannelFactory<TContract> NewChannelFactory<TContract>(string endpointConfigurationName) where TContract : class { 
    // TODO: Cache the factory in here for better performance. 
    return new ChannelFactory<TContract>(endpointConfigurationName); 
} 

public static void Invoke<TContract>(ChannelFactory<TContract> factory, Action<TContract> action) where TContract : class { 
    var proxy = (IClientChannel) factory.CreateChannel(); 
    bool success = false; 
    try { 
     action((TContract) proxy); 
     proxy.Close(); 
     success = true; 
    } finally { 
     if(!success) { 
      proxy.Abort(); 
     } 
    } 
} 
+0

謝謝,我不知道端點配置是自動的爲我讀! – UmaN

+0

奇怪的表述 - 爲什麼不只是抓住一個例外,放棄渠道和重新拋出? –

+0

@Richard:捕獲並重新拋出異常需要時間並刪除部分堆棧跟蹤。如果這些東西與你的代碼無關,那很好,但是它避免了這種情況。 –

0

WebConfigurationManager可以用來讓你的端點。你有一個客戶端部分,所以在GetSection中就像上面的代碼一樣傳遞它。

ClientSection clientSection = (WebConfigurationManager.GetSection("system.serviceModel/client") as ClientSection); 

foreach(ChannelEndpointElement cee in clientSection.Endpoints) 
{ 
    // Store your endpoint for future use with ChannelFactories 
} 
0

您可以封裝到這個輔助方法,使調用代碼簡單。我不希望在需要訪問該服務的每個庫或應用程序中包含服務引用。我創建了一個Mediator模式類,它有一個服務引用並作爲服務的代理。它將端點字​​符串作爲唯一的類構造函數參數。構造函數看起來像這樣(我在一個通道工廠例子投擲作爲評論)

public DspServiceMediator(String serviceAddress) 
    { 
     EndpointAddress end_point = new EndpointAddress(serviceAddress); 
     NetTcpBinding new_tcp = new NetTcpBinding(SecurityMode.None); 
     new_tcp.ReceiveTimeout = TimeSpan.MaxValue; 
     new_tcp.SendTimeout = new TimeSpan(0, 0, 30); //30 seconds 
     //_channelFactory = new ChannelFactory<DspServiceClient>(new_tcp, end_point); 
     _dspClient = new DspServiceClient(new_tcp, end_point); 
    } 

我居然在服務複製每個屬性(很多時候我不得不說做服務更容易被最終客戶端使用的小器官功能障礙綜合徵),但是你可能只是在你的客戶端代碼中違反了Demeter的法則,並返回底層服務客戶端(上面代碼中的_dspClient)並使用它。

0

由於所有的連接都是一樣的合同,基本上是相同的客戶端代碼,您可以使用相同的ChannelFactory創造儘可能多的ServiceChannel S作爲你的需要,並在定期指定可以連接每個ServiceChannel不同EndpointAddress ES舊的應用程序設置,或在數據庫:

private List<string> _endpointLists = new List<string>() { "127.0.0.0:1234" }; 
private static ChannelFactory<IWCFServiceChannel> _channelFactory = new ChannelFactory<ServiceReference.IWCFServiceChannel>("App.config Binding Name Here"); 
private List<WCFServiceChannel> _serviceChannels = new List<WCFServiceChannel>(); 

foreach (string uriEndpoint in _endpointLists) 
    _serviceChannels.Add(_channelFactory.CreateChannel(new EndpointAddress(uriEndpoint))); 

_serviceChannels[0].Open(); 
... 

而且,因爲你需要,使用相同的ChannelFactory,但每次都創建新的ServiceChannel s的不同的端點,你可以這樣做,因爲很多次。