簡體   English   中英

在一個WCF調用中更新許多實體,而不是為每個實體點擊WCF服務以進行更新

[英]Update many entities in one WCF call versus hitting the WCF service for each entity to update

我在多層應用程序上工作,我需要通過三種方式優化長時間運行的過程:

  1. 避免EF更新並發問題。
  2. 提高速度。
  3. 通知用戶進度。

實際上,客戶端代碼使用一種完成所有工作的方法調用WCF服務( 評估要更新的實體數查詢要更新的實體更新它們 ,最后將它們保存回數據庫中 )。

該過程很長,一旦完成, 除了最終結果外什么都不會發回給用戶 用戶可能不知道正在發生什么,最多可以在等待表單前停留10分鍾。

被查詢實體的數量和深度可能會非常大,有時我會遇到OutOfMemoryExceptions。 我不得不更改服務方法以一次處理實體更新100個實體,因此我的DbContext將經常刷新並且不會變得太大。

我的實際問題是,每次實體更新時,我都無法通知用戶,因為我的服務方法會在將結果返回給用戶之前完成整個過程。

我閱讀了有關實現雙工服務的信息,但是由於我必須向用戶返回兩個不同的回調 (一個回調返回要更新的實體數,另一個回調用於每個實體更新的結果 ),因此我必須在一個接口上使用多個接口繼承通用回調接口,並且變得有點混亂(按我的口味)。

有一種WCF服務方法返回要評估的實體數,而另一種WCF方法將返回一個簡單的實體更新結果,每個實體都將命中更新結果,這會更好嗎? 我的DBContext僅在單個實體更新時有效,因此它不會增長太多,我認為這很好。 但是,我擔心在該過程中確實經常訪問WCF服務

你有什么想法? 你有什么建議?

  1. 避免EF更新並發問題。

    查看此問題/答案Entity Framework事務長期運行

  2. 提高速度。

    一些建議:

    • 嘗試使用SQL事件探查器查看正在執行的SQL查詢,並優化linq查詢
    • 或者嘗試改進查詢本身或調用存儲過程。
    • 可以並行進行更新嗎? 不同的線程? 不同的處理器?
  3. 通知用戶進度。

    我建議更改客戶端以調用異步方法,或隨后異步啟動長時間運行的方法的方法。 這將立即將控制權返回給客戶端。 然后將需要長期運行的操作來提供有關其進度的反饋。

    有關從后台線程更新進度的信息,請參閱本文

    更新資料
    我建議的“架構”如下:

. Service . . .
    ________  .    _________    _______    ____
   |        | .   |   WCF   |  |  EF   |  |    |
   | Client |---->| Service |->| Class |->| DB |
   |________| .   |_________|  |_______|  |____|
              .
              . .

WCF服務僅負責接受客戶端請求,並開始執行EF類中長期運行的操作。 客戶端應向WCF服務發送異步請求,以使其保持控制和響應能力。 EF類負責更新數據庫,您可以選擇一次更新全部子集或記錄。 然后,EF類可以根據需要通過WCF服務將其取得的任何進展通知客戶端。

您是否考慮過將WCF主機添加到客戶端? 這樣,您將獲得兩種雙向通信。

客戶端連接到服務器,並將服務器連接詳細信息返回給客戶端
客戶端請求長時間運行的操作才能開始
隨着工作的進行,服務器將多個更新發送到客戶端WCF主機。
服務器將工作發送到客戶端。

這使您的客戶端可以自由地做其他事情,只要您認為合適,就可以使用服務器中的消息。 可能會在收到消息時更新狀態區域。

您甚至可以讓服務器維護客戶端列表並向所有客戶端發送更新。

- - - - 編輯 - - - - -
當我說WCF主機時,我的意思是一個ServiceHost,它可以從您在App.config中的XML中自動創建,也可以直接通過代碼創建。

var myUri = new Uri[0];
myUri[0] = new Uri("net.tcp://localhost:4000");
var someService = new SomeService(); //implements ISomeService interface
var host = new ServiceHost(someService, myUri);
var binding = new NetTcpBinding(); // need to configure this
host.AddServiceEndpoint(typeof(ISomeService), binding, "");
host.Open();

代理是一個術語,我用它來表示客戶端用於連接服務器的內容,在我遇到的一個早期示例中,它就一直困擾着我。 兩種方式都可以再次創建。

var binding = new NetTcpBinding(); // need to configure this
var endpointAddress = new EndpointAddress("net.tcp://localhost:4000");
var factory = new ChannelFactory<ISomeService>(binding, endpointAddress);
var proxy = factory.CreateChannel();
proxy.DoSomeWork();

因此,在典型的客戶端/服務器應用中

CLIENT APP 1       SERVER APP         CLIENT APP 2
proxy------------->ServiceHost<-------proxy

我的建議是,您也可以使客戶端成為“服務器”

CLIENT APP 1       SERVER APP         CLIENT APP 2
proxy------------->ServiceHostA<------proxy
ServiceHostB<------proxy1
                   proxy2------------>ServiceHostB

如果這樣做,您仍然可以根據需要將大型任務拆分為較小的任務(您提到了內存問題),但是從事態上看,它們仍然可能需要一些時間,因此進度更新仍可以發送回客戶端或如果您希望所有人都知道發生了什么,那么即使是所有客戶也是如此。 不需要回調,盡管您仍然可以使用它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM