2009-06-19 72 views
1

如果我有這樣的服務定義:我瞭解MsmqPoisonMessageException錯誤嗎?

[PoisonErrorBehavior] 
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)] 
public class MsgQueue: IMsgQueue 
{ 
    public void ProcessMsg(CustomMsg msg) 
    { 
     throw new Exception("Test"); 
    } 
} 

(其中ProcessMsg是傳入MSMQ的消息的註冊方法)

,我想用我的錯誤處理程序來處理異常(我拿了從MSDN代碼爲礦山模板):

public sealed class PoisonErrorBehaviorAttribute : Attribute, IServiceBehavior 
    { 
     MsmqPoisonMessageHandler poisonErrorHandler; 

     public PoisonErrorBehaviorAttribute() 
     { 
      this.poisonErrorHandler = new MsmqPoisonMessageHandler(); 
     } 

     void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase) 
     { 
     } 

     void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters) 
     { 
     } 

     void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase) 
     { 
      foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers) 
      { 
       ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher; 
       channelDispatcher.ErrorHandlers.Add(poisonErrorHandler); 
      } 
     } 
    } 

    class MsmqPoisonMessageHandler : IErrorHandler 
    { 
     public void ProvideFault(Exception error, MessageVersion version, ref System.ServiceModel.Channels.Message fault) 
     { 
     } 

     public bool HandleError(Exception error) 
     { 
      string test = error.GetType().ToString(); 
      // 
      // The type of the exception is never MsmqPoisonMessageException !!! 
      // 
      MsmqPoisonMessageException poisonException = error as MsmqPoisonMessageException; 
      if (null != poisonException) 
      { 
       long lookupId = poisonException.MessageLookupId; 
       Console.WriteLine(" Poisoned message -message look up id = {0}", lookupId); 
      } 
     } 

然後我得到了異常的類型MsmqPoisonMessageException的從來都不是問題。我希望.NET能夠神奇地將我的「新異常(」測試「)」封裝在MsmqPoisonMessageException中,但在我的錯誤處理程序中捕獲的異常總是與我拋出的異常類型相同。

我是否會誤解這整個毒訊的行爲?我想如果我的消息處理代碼引發了一個未處理的異常,那麼這個異常就會變成MsmqPoisonMessageException,否則我不會有機會在隊列中獲得msg的lookup-id。

謝謝大家。

回答

1

首先,您需要檢索事務內部的消息,否則當您的代碼拋出異常時,它們不會被放回隊列。這增加了ProcessMessage的功能:

[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)] 

此外,您還需要確保該綁定設置檢測到有害消息時故障,並且重試次數和時間是足夠小,你會看到它在你的測試。

請嘗試以下步驟(使用VS 2008):爲您的app.config文件

  • 選擇綁定在樹

    1. 打開WCF配置工具,然後單擊「新建綁定配置」,在任務區
    2. 選擇端點的綁定類型(可能netMsmqBinding或msmqIntegrationBinding)
    3. 設置新的綁定配置
    4. 將ReceiveErrorHandling屬性爲「F名行兇」
    5. 設置的ReceiveRetryCount屬性爲2
    6. 將RetryCycleDelay爲‘00:00:10’
    7. 選擇端點爲您服務,並設置綁定配置的名稱步指定4

    (對於您的生產配置,您可能需要ReceiveRetryCount和RetryCycleDelay的不同值。)