Skip to content

Message accumulation

SAIF.Application offers two related but independent message-building mechanisms: AppManagerBase.AppendMessageLines(...), which grows a single manager-scoped Message string one line at a time while skipping duplicates, and the static MessageFormatting helpers, which turn an array of message strings into one concatenated string using a caller-chosen (or fixed) separator, also skipping duplicates but as a batch operation.

Field Value
Operation ID OP-APP-04
Trigger A manager calls AppendMessageLines(...) on itself, or any caller invokes a MessageFormatting shared method with a message array
Inputs A single message string, an array of message strings, or an IEnumerable(Of String) of messages; an optional concatenation string for GetMessagesUserDefined
Outputs Updated AppManagerBase.Message string (instance path); a single formatted message string (static MessageFormatting path)
Primary components AppManagerBase.AppendMessageLines (three overloads), AppManagerBase.Message, AppManagerBase.NewLineCharacter, MessageFormatting.GetMessagesForWindows, MessageFormatting.GetMessagesForWeb, MessageFormatting.GetMessagesUserDefined, MessageFormatting.BuildMessageString, MessageFormatting.AppendMessageString, MessageFormatting.RemoveReturns
Entry point Application\SAIF.Application\AppManagerBase.vb; Application\SAIF.Application\MessageFormatting.vb

Steps

Instance path: AppManagerBase.AppendMessageLines

  1. Normalize the input shape. The three protected overloads all converge on the single-string overload:
  2. AppendMessageLines(inMessages As IEnumerable(Of String)) calls AppendMessageLines(inMessages.ToArray).
  3. AppendMessageLines(inMessage() As String) loops the array and calls AppendMessageLines(AMessage) once per element.
  4. AppendMessageLines(inMessage As String) is the actual append logic (step 2).
  5. Append with duplicate suppression. For a single message string, the method appends it to Message only when both conditions hold: the string is non-empty (inMessage.Length > 0) and it is not already a substring of the current Message (Not Message.Contains(inMessage)) (BR-002).
  6. If Message already has content: the configurable NewLineCharacter (default <BR>) is appended first as a separator before the new text.
  7. If Message is empty: the new text becomes the entire Message with no leading separator.
  8. If the message is empty or already contained: the call is a no-op — nothing is appended and Message is unchanged.
  9. Because the duplicate check is Message.Contains(inMessage) rather than an exact per-line match, a new message that is a substring of already-accumulated text is also suppressed, even if it was never appended as its own line.*

Static path: MessageFormatting

  1. Choose a formatting entry point. Callers pick one of three static methods based on the desired separator: GetMessagesForWindows (vbCrLf), GetMessagesForWeb (<BR>), or GetMessagesUserDefined (caller-supplied inConcatString).
  2. Strip embedded line breaks from each message. Each method iterates the input inMessages array and calls RemoveReturns(Msg) on every element, which replaces embedded vbCrLf or <BR> occurrences with an empty string so a single logical message cannot itself introduce extra line breaks into the joined result.
  3. De-duplicate at the batch level. Each cleaned message is added to a local Results list only if it is not already present (Not Results.Contains(temp)) (BR-002) — this is an exact-match check on the cleaned text, unlike the substring check used by AppManagerBase.AppendMessageLines.
  4. Join the de-duplicated list. BuildMessageString(Results, separator) concatenates every entry in Results, inserting the separator string after every entry except the last (compared by reference/value equality against inMessages.Last, which can misbehave if the list contains a repeated final value — see failure notes).
  5. Append to an existing message (alternate helper). AppendMessageString(ByRef inMessage, inMessages, inConcatString) performs the same join as step 6 but appends the result onto an existing inMessage string, inserting a hard-coded <br> separator first when inMessage already has non-blank content — independent of any NewLineCharacter setting on a calling AppManagerBase.

Process flow

The following diagram visualizes both the instance append path and the static batch-formatting path.

flowchart TD
    Start([Message text arrives]) --> Which{Instance or static path?}
    Which -->|AppManagerBase| Norm[Normalize to single-string calls]
    Norm --> Check{Non-empty and<br>not already in Message?}
    Check -->|No| Skip([No-op: Message unchanged])
    Check -->|Yes| Sep{Message already<br>has content?}
    Sep -->|Yes| AddSep[Append NewLineCharacter]
    Sep -->|No| AddDirect[No separator needed]
    AddSep --> Append[Append message text]
    AddDirect --> Append
    Which -->|MessageFormatting| Clean[RemoveReturns on each message]
    Clean --> Dedup[Add to Results if not<br>already present, exact match]
    Dedup --> Join[BuildMessageString joins<br>Results with chosen separator]
    Join --> Done([Return formatted string])

Failure and edge-case behavior

  • AppManagerBase.AppendMessageLines suppresses on a substring match (Message.Contains(inMessage)), while the static MessageFormatting methods suppress on an exact match (Results.Contains(temp)) — the two "duplicate suppression" behaviors covered by BR-002 are not identical, and callers mixing both mechanisms on the same logical message list may see inconsistent results.*
  • BuildMessageString and AppendMessageString compare inMessages.Last <> Message to decide whether to append the separator; if the same message string appears more than once at the end of a list that was not already de-duplicated by a caller, the separator logic can omit separators earlier than expected.*
  • RemoveReturns only replaces the first kind of return sequence it detects (vbCrLf else <BR>) — a message containing both vbCrLf and <BR> only has the vbCrLf occurrences removed, since the method returns immediately after that branch.*
  • NewLineCharacter on AppManagerBase defaults to <BR> (DefaultNewLineCharacter) and is settable per-instance, but the static MessageFormatting.AppendMessageString always uses a hard-coded <br> regardless of any AppManagerBase.NewLineCharacter setting, so the two paths can produce visually different separators in the same application.*

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

Sources

  • Application\SAIF.Application\AppManagerBase.vb
  • Application\SAIF.Application\MessageFormatting.vb