views:

30

answers:

0

I have a poisoned message service. When I receive a poisoned message, the error is handled by a poisoned message handler, which sends an email, which then moves the message off of the queue. the problem I'm having is rather than sending one email. It sends 4-5 and I'm really struggling to figure out why this is happening. The way I do this is check the inner exception of the poisoned message exception, which should be a strongly typed exception. that contains a fault contract that I use to send an email notification.

Below is how I have everything set up. Hope its not too convoluted and is clear.

This is the binding config.

<?xml version="1.0" encoding="utf-8" ?>
    <bindings>
      <netMsmqBinding>
        <binding name="BindingConfiguration" 
                 maxRetryCycles="1" 
                 receiveErrorHandling="Fault"
                 receiveRetryCount="0" 
                 retryCycleDelay="00:00:30">
          <security mode="None"/>
        </binding>

      </netMsmqBinding>
    </bindings>

When the poison message service receives a poisoned message it will have give the message another try. If that fails, I throw an msmqpoisonedmessageexception, of I add an inner exception, which is the strongly typed fault contract.

<OperationBehavior(TransactionScopeRequired:=True, TransactionAutoComplete:=True)>
    Public Sub SaveEmail(ByVal newEmail As Contracts.Contact, ByVal oldEmail As Contracts.Contact, ByVal emailType As Contracts.EmailType, ByVal settings As Contracts.Configuration) Implements Contracts.IService.SaveEmail
        If Validation.ValidateEmail(newEmail) Then
            Try
                _repository.SaveEmail(newEmail, oldEmail, emailType)

                If Not settings.AuditNote Is Nothing Then
                    _repository.WriteClientNote(settings.AuditNote)
                End If

            Catch fe As FaultException(Of ContactFault)
                Throw New MsmqPoisonMessageException(fe.Message, fe)
            Catch ex As Exception

                Dim contactFault As New ContactFault With {.Message = ex.Message, .NewContact = newEmail, .OldContact = oldEmail, .StackTrace = ex.StackTrace.ToString}
                Throw New MsmqPoisonMessageException(ex.Message, New FaultException(Of ContactFault)(contactFault))
            End Try
        End If
    End Sub

The exception is then handled in a poison message exception handler class. Which has two main methods :-

The one below checks wether the error is an msmqpoisonedmessageexception if it is , it will pass it to the next method to be removed.

1)

Public Function HandleError(ByVal [error] As System.Exception) As Boolean Implements System.ServiceModel.Dispatcher.IErrorHandler.HandleError
        poisonException = TryCast([error], MsmqPoisonMessageException)

        If poisonException IsNot Nothing Then
            Try
                lookupID = poisonException.MessageLookupId
            Catch ex As Exception
                EventLog.WriteEntry(My.Application.Info.ProductName, ex.Message & "Look up", EventLogEntryType.Warning)
            End Try


            Queue = New MessageQueue(ConfigurationManager.AppSettings("QueueName"))
            PoisonQueue = New MessageQueue(ConfigurationManager.AppSettings("PoisonQueueName"))
            RemovePoisonedMessage()

            Return True


        End If

        Return False
    End Function

this next method takes the poisoned messag exception and rmeoves it from the queue, and adds it to a deadmessagequeue. It also checks the type of fault and uses the corresponding method for the corresponding type of fault.

Protected Overrides Sub RemovePoisonedMessage()


        If TypeOf poisonException.InnerException Is FaultException(Of AddressFault) Then
            Email_AddressValidationFault(poisonException.InnerException)
        ElseIf TypeOf poisonException.InnerException Is FaultException(Of ContactFault) Then
            Email_ContactValidationFault(poisonException.InnerException)
        ElseIf TypeOf poisonException.InnerException Is FaultException(Of DebtFault) Then
            Email_DebtValidationFault(poisonException.InnerException)
        End If


        Dim message As System.Messaging.Message = Nothing


        Using txScope As New TransactionScope(TransactionScopeOption.RequiresNew)

            Dim retryCount As Int32 = 0
            While retryCount < 3
                retryCount += 1
                Try


                    message = MyBase.Queue.ReceiveByLookupId(MessageLookupAction.Current, MyBase.lookupID, MessageQueueTransactionType.Automatic)


                    If message IsNot Nothing Then


                        message.UseDeadLetterQueue = True
                        Try
                            MyBase.PoisonQueue.Send(message, System.Messaging.MessageQueueTransactionType.Automatic)

                        Catch ex As Exception
                            EventLog.WriteEntry(My.Application.Info.ProductName, ex.Message, EventLogEntryType.Error)
                        End Try

                        txScope.Complete()
                        '
                        Return

                    End If

                Catch generatedExceptionName As InvalidOperationException

                End Try
            End While
        End Using


    End Sub