我正在使用netNamedPipeBinding
執行從Windows應用到Windows服務的進程間WCF通信。在使用回調關閉連接時收到WCF異常
現在我的應用程序在所有其他帳戶中運行良好(消除了WCF異常的公平份額,因爲任何使用WCF的人都會知道..),但是此錯誤證明是相當有彈性的。
爲了繪製我的場景圖片:我的Windows服務可以在任何給定的時間通過在Windows應用程序中按下的按鈕排隊等待一段時間,然後通過netNamedPipeBinding
這是一個支持回調的綁定(兩如果您不熟悉併發起執行此項工作的請求(在本例中爲文件上傳過程),它還會從文件進度到傳輸速度等每隔幾秒鐘拋出一次回調(事件)到Windows應用程序,所以有一些相當緊密的客戶端 - 服務器集成;這就是我如何將我的Windows服務中正在運行的程序的進度返回到我的Windows應用程序中。
現在,一切都很好,除了我每次關閉應用程序(這是一個非常有效的場景)時收到的一個令人討厭的異常,WCF神對我現在都比較滿意。雖然轉移正在進行中,並且回調射擊相當嚴重,我收到此錯誤:
System.ServiceModel.ProtocolException:
The channel received an unexpected input message with Action
'http://tempuri.org/ITransferServiceContract/TransferSpeedChangedCallback'
while closing. You should only close your channel when you are not expecting
any more input messages.
現在我明白了錯誤,但不幸的是我不能保證永遠不會收到任何更多的輸入形式交往後關閉我的頻道,如用戶可能隨時關閉該應用程序,因此該工作仍將繼續在Windows服務的後臺(類似於病毒掃描程序的運行方式)。用戶應該能夠在不受干擾的情況下儘可能多地啓動和關閉贏管理工具應用程序。
現在錯誤,我執行我的Unsubscribe()
調用後立即收到錯誤,這是終止應用程序之前的第二次調用,我相信是斷開WCF客戶端的首選方式。在關閉連接之前,所有的退訂操作只是簡單地將客戶端ID從本地存儲在win服務wcf服務上的數組中刪除(因爲win服務和windows應用程序共享此實例,因爲win服務可以在預定的事件本身)和我執行客戶端ID數組刪除後,我希望(感覺)應該是一個乾淨的斷開連接。
這樣做的結果是,除了接收到一個異常,我的應用程序掛起,用戶界面完全鎖定,進度條和一切中途,所有跡象指出有競爭條件或WCF死鎖[嘆氣],但我現在很聰明,我認爲這是一個相對孤立的情況,現在閱讀例外情況,我認爲這不是一個「線索」問題,因爲它更多地指出了早期斷開連接的問題,然後把我所有的線索都打亂,也許會導致鎖定。
我Unsubscribe()
的客戶上的做法是這樣的:
public void Unsubscribe()
{
try
{
// Close existing connections
if (channel != null &&
channel.State == CommunicationState.Opened)
{
proxy.Unsubscribe();
}
}
catch (Exception)
{
// This is where we receive the 'System.ServiceModel.ProtocolException'.
}
finally
{
Dispose();
}
}
而且我Dispose()
方法,應該進行清潔斷開:
public void Dispose()
{
// Dispose object
if (channel != null)
{
try
{
// Close existing connections
Close();
// Attempt dispose object
((IDisposable)channel).Dispose();
}
catch (CommunicationException)
{
channel.Abort();
}
catch (TimeoutException)
{
channel.Abort();
}
catch (Exception)
{
channel.Abort();
throw;
}
}
}
而WCF服務Subscription()
對口和類屬性(供參考)在windows服務服務器(這裏沒有任何棘手,我的例外發生客戶端):
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public class TransferService : LoggableBase, ITransferServiceContract
{
public void Unsubscribe()
{
if (clients.ContainsKey(clientName))
{
lock (syncObj)
{
clients.Remove(clientName);
}
}
#if DEBUG
Console.WriteLine(" + {0} disconnected.", clientName);
#endif
}
...
}
接口:
[ServiceContract(
CallbackContract = typeof(ITransferServiceCallbackContract),
SessionMode = SessionMode.Required)]
public interface ITransferServiceContract
{
[OperationContract(IsInitiating = true)]
bool Subscribe();
[OperationContract(IsOneWay = true)]
void Unsubscribe();
...
}
回調契約的接口,它不會做任何事情非常令人興奮的,只是調用通過委託事件等,我包括在此的原因是爲了展示你我的屬性。我沒有減輕一組死鎖的已經包括UseSynchronizationContext = false
:
[CallbackBehavior(UseSynchronizationContext = false,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public class TransferServiceCallback : ITransferServiceCallbackContract
{ ... }
真的希望有人能幫幫我!非常感謝= :)
我不知道具體的問題,但對於信息螺紋天翻地覆聲音*可能是由於WCF如何使用同步上下文(通過在的WinForms等形式爲)*。 – 2010-09-18 07:56:34
謝謝馬克,是抓住了我,並通過閱讀這個問題緩解了一組僵局,訣竅就是在回調協議上設置UseSynchronizationContext = false;我將這個添加到我的示例中。 – GONeale 2010-09-18 08:04:56
啊,對;很高興看到你已經覆蓋; p – 2010-09-18 08:10:24