2010-03-07 66 views
5

我有一個asmx web服務,應該只允許一次響應1個客戶端。如何確保一次僅調用一次asmx Web服務?

換句話說,如果服務被客戶端A調用,並且服務器B調用,我希望B掛起直到A完成,然後B可以得到服務。

如果這太複雜了,那麼在B服務期間,來自B的最低限度的呼叫應該會失敗,並且在用戶定義的錯誤期間A會發生。

原因是服務在很大程度上依賴於IO操作和XML序列化,因此至關重要的是服務不會被多於一個客戶端同時調用。

在此先感謝

回答

4
static object _LockObject = new object(); 

void WebServiceCall() 
{ 
    lock(_LockObject) 
    { 
     // Do work... 
    } 
} 

創建一個靜態對象,您可以調用lock()lock()語句將阻止其他調用在內部執行代碼,直到獲得鎖的第一次執行完成。

請注意,取決於您的超時設置,B可能會因超時時間的長短而失敗,具體取決於A完成的時間。

更新:是的,你可以使用Monitor類來代替lock()。您可以使用Monitor.TryEnter()方法來檢查對象是否已被鎖定(即:如果您想返回錯誤而不是等待)。

更多細節:

http://msdn.microsoft.com/en-us/library/aa664735(VS.71).aspx

形式

lock (x) ... 

的lock語句,其中x是一個引用類型的表達式,是恰恰相當於

System.Threading.Monitor.Enter(x); 
try { 
    ... 
} 
finally { 
    System.Threading.Monitor.Exit(x); 
} 

http://msdn.microsoft.com/en-us/library/de0542zz.aspx

使用Enter獲取作爲參數傳遞的對象上的監視器。如果另一個線程在對象上執行了一個Enter,但尚未執行相應的Exit,則當前線程將阻塞,直到另一個線程釋放該對象。

所以它只是設計,代碼知道阻止和不跳過。如果你想使用Monitor.TryEnter()方法,你可以跳過。

+0

請原諒我的無知,但這對我來說毫無意義,您能否詳細說明一下?謝謝 – 2010-03-07 18:55:01

+0

@JL:增加了一些細節。讓我知道你是否有一個具體的問題,你想要更多的細節。 – 2010-03-07 18:58:00

+0

也可以確定對象的鎖定狀態嗎? – 2010-03-07 19:02:53

2

我不知道它是如何在.NET中實現的,但我想你想實現當正在維修它由請求這是「擁有」的鎖定對象,不能給一次請求多個請求。在Java中,我可能會同步一些全局對象。

要小心,但要注意常見的併發問題......對於一個天真的實現來說,一個請求檢查鎖並找到它可用,然後睡覺,然後第二個請求檢查鎖並接受它,然後第一次請求喚醒,認爲鎖是免費的,壞事發生)。另外請確保您處理請求處理崩潰並保留鎖定的情況。

由於作爲一種不好的做法,制定非併發的基於Web的系統的使用模式(當然在Java servlets世界中),我建議你在服務已經存在的情況下拋出一個錯誤在使用中而不是阻止,因爲可能難以判斷阻塞的影響。

+0

您的意思是標記一個asp.net全局應用程序變量? – 2010-03-07 18:53:15

+0

就像我說的,我不確定asp.net的詳細信息,因爲我不使用該語言,但您需要一些可用於所有請求的對象,這些對象可用於宣傳請求正在被服務。然後該請求可以檢查該對象,並且只有在沒有其他請求正在進行時才繼續。但要小心,注意死鎖的可能性,並確保處理請求處理崩潰而將鎖留在原地的情況。 – Brabster 2010-03-07 19:01:40

0

我不知道你爲什麼要這樣做,但無論如何,這可能是一個有效的方案。嘗試查看Linux的APT程序包管理器如何獲取鎖定:

要防止包管理器的多個實例產生,要使包管理器正常工作,需要鎖定鎖定文件並將其寫入PID。

同樣,您可以在虛擬主機的根目錄中創建一個文件。當客戶端連接時,鎖定該文件,然後在其中寫入內容。完成後,將文件清空。試圖鎖定它之前,試着看看裏面有沒有東西。如果是,則將錯誤消息返回給客戶端。

+0

這是一個很好的答案,但你忘記了一個重要的點 - 重新啓動能力。如果ws線程死亡,您如何採取措施確保文件被重置,否則最終可能導致服務調用被鎖定到所有客戶端。 – 2010-03-07 18:59:52

+0

糟糕!我沒有想到這一點。如果客戶端沒有釋放鎖定(清除文件),則該人員必須手動清除它。這個問題的第一個答案(上面)是正確的。乾杯!! – 2010-03-08 05:18:05

2

我理解一次只處理一個請求的要求,但我不認爲一次只允許一個請求就是答案。

某些答案建議阻止請求。雖然這將小規模工作,但這會導致諸如超時縮放到更多服務器的問題。

另一種方法是您在處理每個請求時將其服務並將其放在隊列以供稍後處理。該隊列可以一次處理一個任務(或者取決於服務器的繁忙程度)。

可以通過幾種方式通知原始請求者完成。一種方法是輪詢查看原始請求是否已完成,或者是否仍在隊列中進行處理,可能使用生成的令牌(如GUID)。

+0

+1鑑於現在有更多信息,我同意排隊請求聽起來像是正確的想法。 – Brabster 2010-03-07 19:05:14