2011-10-20 56 views
18

所以我決定在我的WCF應用程序中提高性能,並嘗試緩存Channels和ChannelFactory。我有兩個問題需要在開始之前清理。WCF Channel和ChannelFactory緩存

1)ChannelFactory是否應該作爲單例實現?

2)我有點不確定如何緩存/重用個別頻道。你有什麼可以分享的例子嗎?

重要的是要注意我的WCF服務是作爲一個獨立的應用程序部署的,只有一個端點。

編輯:

感謝您的答覆。我仍然有幾個問題,但...

1)我想我很困惑,應該發生緩存。我提供了一個客戶端API,使用此代碼到我們公司的另一個部門。這種緩存是否發生在客戶端上?

2)客戶端API將用作Silverlight應用程序的一部分,這是否會改變什麼?特別是,在這種情況下可以使用哪些緩存機制?

3)我仍然不清楚GetChannelFactory方法的設計。如果我只有一個服務,應該只創建一個ChannelFactory並進行緩存?

我還沒有實現任何緩存功能(因爲我心亂如麻它應該怎麼做!),但這裏是我有一個客戶端代理至今:

namespace MyCompany.MyProject.Proxies 
{ 
    static readonly ChannelFactory<IMyService> channelFactory = 
     new ChannelFactory<IMyService>("IMyService"); 

    public Response DoSomething(Request request) 
    { 
     var channel = channelFactory.CreateChannel(); 

     try 
     { 
      Response response = channel.DoSomethingWithService(request); 
      ((ICommunicationObject)channel).Close(); 
      return response; 
     } 
     catch(Exception exception) 
     { 
      ((ICommenicationObject)channel).Abort(); 
     } 
    } 
} 
+0

對於#3,是的,應該只創建一個通道工廠。基本上,您將爲每個服務端點擁有一個通道工廠。就我而言,到目前爲止,我們已經有6個,主要分佈在2層。在你的情況下,如果你只有一個服務,只需要一個應用程序就可以完成上面的工作。你上面的代碼是正確的。緩存將基於應用程序的需求。 – Tim

+0

@Tim - 感謝您的全力幫助。我真的很感激!我認爲就我而言,我的服務如此「簡單」這一事實讓我感到困惑,看看有多個端點的其他例子。我=現在不那麼困惑=蒂姆做了很好的解釋!多謝,夥計! – Didaxis

+0

你很受歡迎。很高興我可以幫助 - 快樂的編碼! – Tim

回答

20

使用ChannelFactory創建工廠實例,然後緩存該實例。然後您可以根據需要從緩存中創建communicatino頻道。

您是否需要多渠道工廠(即......有多種服務)?根據我的經驗,這是您將看到性能最大的好處的地方。創建頻道是一項相當便宜的任務;它在一開始就設置一切需要時間。

我不會緩存個別頻道 - 我會創建它們,將它們用於操作,然後關閉它們。如果你緩存它們,它們可能會超時並且通道會出錯,那麼你將不得不放棄它並創建一個新的。

不知道你爲什麼要用singleton實現ChannelFactory,特別是如果你要創建並緩存它,並且只有一個端點。

我稍後會發布一些示例代碼,當我有更多時間時。

UPDATE:代碼示例

這裏是我是如何實現這個在工作中項目的例子。我使用了ChannelFactory<T>,因爲我開發的應用程序是一個包含多個服務的n層應用程序,並且會添加更多。目標是在應用程序的整個生命週期中創建一個客戶端,然後根據需要創建通信渠道。這個想法的基礎知識不是我的(我從網上的一篇文章中獲得),儘管我根據需要修改了實現。

我在我的應用程序中有一個靜態助手類,在該類中,我有一個字典和一個方法來從channelf工廠創建通信通道。

字典如下(對象是值,因爲它將包含不同的渠道工廠,每個服務一個)。我在示例中將「Cache」作爲佔位符的一種 - 使用任何正在使用的緩存機制替換語法。

public static Dictionary<string, object> OpenChannels 
{ 
    get 
    { 
     if (Cache["OpenChannels"] == null) 
     { 
      Cache["OpenChannels"] = new Dictionary<string, object>(); 
     } 

     return (Dictionary<string, object>)Cache["OpenChannels"]; 
    } 
    set 
    { 
     Cache["OpenChannels"] = value; 
    } 
} 

接下來是從工廠實例創建通信通道的方法。該方法檢查工廠是否先存在 - 如果不存在,它會創建它,將其放入字典中,然後生成通道。否則,它只是從工廠的緩存實例中生成一個通道。

public static T GetFactoryChannel<T>(string address) 
{ 

    string key = typeof(T.Name); 

    if (!OpenChannels.ContainsKey(key)) 
    { 
     ChannelFactory<T> factory = new ChannelFactory<T>(); 
     factory.Endpoint.Address = new EndpointAddress(new System.Uri(address)); 
     factory.Endpoint.Binding = new BasicHttpBinding(); 
     OpenChannels.Add(key, factory); 
    } 

    T channel = ((ChannelFactory<T>)OpenChannels[key]).CreateChannel(); 

    ((IClientChannel)channel).Open(); 

    return channel; 
} 

我已經把這個例子從我在工作中使用的東西中剝離出來了。在這種方法中你可以做很多事情 - 你可以處理多個綁定,爲認證分配證書等。它幾乎是你的一站式購物中心,用於生成客戶端。最後,當我在應用程序中使用它時,我通常會創建一個頻道,完成我的業務並關閉它(或者在需要時終止它)。例如:

IMyServiceContract client; 

try 
{ 
    client = Helper.GetFactoryChannel<IMyServiceContract>("http://myserviceaddress"); 

    client.DoSomething(); 

    // This is another helper method that will safely close the channel, 
    // handling any exceptions that may occurr trying to close. 
    // Shouldn't be any, but it doesn't hurt. 
    Helper.CloseChannel(client); 
} 
catch (Exception ex) 
{ 
    // Something went wrong; need to abort the channel 
    // I also do logging of some sort here 
    Helper.AbortChannel(client); 
} 

希望上面的例子會給你一些東西繼續下去。在生產環境中,我一直在使用與此類似的東西大約一年,並且它工作得很好。我們遇到的任何問題中有99%通常與應用程序之外的某些內容(外部客戶或不受我們直接控制的數據源)相關。

讓我知道,如果有什麼不清楚,或者你有進一步的問題。

+0

謝謝蒂姆。你確實提供了一些有價值的信息。我一定會期待你的榜樣! – Didaxis

+0

@ user384080 - 代碼在我的答案中。如果不清楚,請告訴我。謝謝。 – Tim

+0

@Tim您的實施中存在一個錯誤。無論地址是什麼,都可以按合同類型緩存工廠。您應該有一個包含合同類型和地址的密鑰。 – Anubis

5

你總是可以只讓你的ChannelFactory靜態每一個WCF合同...

你應該知道,從.net 3.5的代理對象集中由通道工廠性能的原因。調用ICommunicationObject.Close()方法實際上會將對象返回到池中,以期可以重用它。

如果你想做一些優化,如果你可以防止在你的代碼中只做一個IO調用,那麼我會查看分析器,它可能遠遠超過你將在頻道工廠進行的任何優化。不要選擇一個區域進行優化,請使用分析器查找可以將目標優化的目標。例如,如果您有一個SQL數據庫,那麼您的查詢中可能會找到一些低級別的成果,如果這些數據尚未經過優化,那麼您的數據庫性能將提高數量級。

3

創建Channel對性能影響非常大。實際上,如果您在客戶端中使用ClientBase而不是純ChannelFactory,WCF已經擁有ChannelFactory的緩存機制。但是,如果您進行一些常規操作(如果需要,請詳細瞭解詳情),緩存將過期。 對於ErOx的問題,我得到了另一種解決方案,我認爲它更好。見下文:


namespace ChannelFactoryCacheDemo 
{ 
    public static class ChannelFactoryInitiator 
    { 
     private static Hashtable channelFactories = new Hashtable(); 

     public static ChannelFactory Initiate(string endpointName) 
     { 
      ChannelFactory channelFactory = null; 

      if (channelFactories.ContainsKey(endpointName))//already cached, get from the table 
      { 
       channelFactory = channelFactories[endpointName] as ChannelFactory; 
      } 
      else // not cached, create and cache then 
      { 
       channelFactory = new ChannelFactory(endpointName); 
       lock (channelFactories.SyncRoot) 
       { 
        channelFactories[endpointName] = channelFactory; 
       } 
      } 
      return channelFactory; 
     } 
    } 
    class AppWhereUseTheChannel 
    { 
     static void Main(string[] args) 
     { 
      ChannelFactory channelFactory = ChannelFactoryInitiator.Initiate("MyEndpoint"); 
     } 
    } 

    interface IMyContract { } 
} 

如果您有其他要求,您可以自行定製Initiate方法的邏輯和參數。但是這個啓動器類不僅限於一個端點。它對應用程序中的所有端點都很強大。希望。它適合你。 BTW。這個解決方案不是來自我的。我從一本書中得到了這個。

+0

請注意''鎖'使用不正確。鎖也應該在對'ContainsKey'的調用中進行。 –