---
title: Distribute document (synchronous or asynchronous)
summary: Sends an xPression distribution request either directly to xPression or through a transactional MSMQ queue, depending on the Asynchronous flag.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Services.Printing
reference_type: package
operation_id: OP-PRT-03
trigger: Caller invokes clsPrint.distributeDocument(package, xml)
---

# Distribute document (synchronous or asynchronous)

`clsPrint.distributeDocument` is a single public entry point with two mutually exclusive execution modes controlled by the `Asynchronous` property: a direct SOAP call to xPression, or a transactional message placed on an MSMQ queue for later processing by a separate consumer. Both modes carry the same package, XML, printer, delivery, and imaging metadata; only the transport differs.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-PRT-03 |
| **Trigger** | Caller invokes `clsPrint.distributeDocument(package, xml)` (directly, or through `ReportBase.Distribute`, see [Distribute report](distribute-report.md)) |
| **Inputs** | Package name, report XML payload, and the printer, plex mode, copies, scale mode, output profile, import info, email info, fax info, deferred-print info, and application name already set on the `clsPrint` instance |
| **Outputs** | Boolean `True` returned after the synchronous call or the queued send completes |
| **Primary components** | `clsPrint.distributeDocument` (public overload and private worker), `clsPrint.StartMQTransaction`, `clsPrint.EndMQTransaction` |
| **Entry point** | `Services\SAIF.Services.Printing\clsPrint.vb` |

## Steps

1. The caller invokes `distributeDocument(inPackage, inXML)`. `Package` is normalized (trailing `.pkg` stripped) ([BR-007](../business-rules.md#br-007-package-name-normalization-strips-a-trailing-pkg-extension)) and `XML` is stored.
2. The public overload calls the private, parameterless `distributeDocument()` worker, which branches on `Asynchronous` ([BR-001](../business-rules.md#br-001-distribution-mode-follows-the-asynchronous-flag)).
3. **Synchronous path (`Asynchronous = False`).** The worker calls `m_Xpresso.distributeDocument`, passing the package, XML, printer, plex mode, copies, scale mode, output profile, serialized import info, email info, fax info, IDM path, a fixed `PaperTray.Tray2` tray selection, deferred-print info, and application name directly to the xPression SOAP service.
4. **Asynchronous path (`Asynchronous = True`).** The worker prepares and sends a transactional MSMQ message instead of calling xPression directly ([BR-002](../business-rules.md#br-002-asynchronous-distribution-must-commit-or-abort-an-msmq-transaction)):
   - If `m_Queue` has not been created yet, the worker opens a `MessageQueue` for the configured `documentMSMQPath`.
   - The worker populates a `CompositeRequestClass` with package name, XML, printer, plex mode, copies, scale mode, format, output profile, import info, email info, fax info, the resolved IDM path, and deferred-print info.
   - The request object is wrapped in a `Message` using `BinaryMessageFormatter`.
   - If the caller had already started a transaction via `StartMQTransaction` (`m_TxnStarted = True`), the worker sends the message on that existing transaction.
     - If `m_TxnStarted` is not yet true, the worker calls `StartMQTransaction` itself, sends the message, and calls `EndMQTransaction(True)` to commit.
   - On failure: `EndMQTransaction(False)` aborts the transaction before the exception is re-thrown.
5. Both paths return `True` after their respective transport step completes without throwing.

## Process flow

The following diagram visualizes the branch between the synchronous and asynchronous distribution paths.

```mermaid
flowchart TD
	Start([Caller invokes distributeDocument]) --> Norm[Normalize package name]
	Norm --> Mode{Asynchronous flag?}
	Mode -->|False| Sync[Call xPression<br>distributeDocument SOAP method]
	Mode -->|True| Queue{MessageQueue open?}
	Queue -->|No| Open[Open MessageQueue<br>for documentMSMQPath]
	Queue -->|Yes| Build
	Open --> Build[Build CompositeRequestClass<br>and wrap in Message]
	Build --> TxnCheck{Transaction already<br>started by caller?}
	TxnCheck -->|Yes| SendExisting[Send on existing transaction]
	TxnCheck -->|No| StartTxn[StartMQTransaction]
	StartTxn --> SendNew[Send message]
	SendNew --> Commit[EndMQTransaction True]
	SendExisting --> Done
	Commit --> Done([Return True])
	Sync --> Done
	Build -.->|Exception| Abort[EndMQTransaction False<br>re-throw]
```

## Failure and edge-case behavior

- Any exception during the asynchronous path's queue-open, build, or send steps triggers `EndMQTransaction(False)` before the exception is re-thrown; the caller still sees the original exception, not a swallowed failure ([BR-002](../business-rules.md#br-002-asynchronous-distribution-must-commit-or-abort-an-msmq-transaction)).
- The synchronous path does not catch exceptions from `m_Xpresso.distributeDocument`; a SOAP fault propagates directly to the caller.*
- The tray selection for the synchronous xPression call is hard-coded to `PaperTray.Tray2` and is not configurable through any public property.*
- If a caller starts a transaction with `StartMQTransaction` but never sends a message and never calls `EndMQTransaction`, the transaction remains open until the next asynchronous distribution call reuses it or the object is discarded.*

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

> **Note:** Statements marked with * were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with ** could not be confirmed; treat as unknown until verified.

## Sources
- `Services\SAIF.Services.Printing\clsPrint.vb`
