---
title: Architecture
summary: How the proxy is constructed, configured, invoked, and disposed.
status: draft
owner: SAIF.Core documentation
last_reviewed: 2026-09-24
---

# Architecture

This repository reaches `clsGenerate` through the generated `clsGenerateSoapClient`, wrapped by the authored `DocumentServiceProxy`, which builds its own `BasicHttpBinding` in code with raised size quotas and takes its URL from the caller, so the `app.config` endpoint is bypassed.

## Proxy mechanism

| Aspect | Finding |
| --- | --- |
| Mechanism | Service Reference (svcutil) |
| Proxy type | `SAIF.Services.Web.Proxies.Document.clsGenerateSoapClient` (`internal`) |
| Base type | `System.ServiceModel.ClientBase<T>` |
| Contract type | `internal interface clsGenerateSoap` |
| Constructed in | `DocumentServiceProxy` constructor (`Services/SAIF.Services.Web.Proxies/DocumentServiceProxy.cs:22-29`) |
| Binding configured in | Code |
| Address supplied by | Constructor argument (`serviceUrl`), itself sourced from `IEnvironmentService.GetConfigSetting("documentGeneratorServiceUrl")` |

## Architecture diagram

The following diagram visualizes how a call reaches the remote service.

```mermaid
flowchart TD
    CALLER["DocumentService.GenerateDocument /<br>DistributeDocument"] --> WRAP["DocumentServiceProxy<br>hand-written wrapper"]
    WRAP --> BIND["Binding constructed<br>BasicHttpBinding<br>MaxReceivedMessageSize/MaxArrayLength = int.MaxValue"]
    BIND --> ADDR["EndpointAddress<br>from documentGeneratorServiceUrl setting"]
    ADDR --> PROXY["clsGenerateSoapClient<br>generated proxy"]
    PROXY --> REMOTE["Remote service<br>clsGenerate (ASMX, xPression)"]
    WRAP --> DISPOSE["Close only<br>no Abort on fault"]
```

## Hand-written wrapper

| Field | Value |
| --- | --- |
| **Type** | `SAIF.Services.Web.Proxies.DocumentServiceProxy` |
| **Source** | `Services/SAIF.Services.Web.Proxies/DocumentServiceProxy.cs` |
| **Visibility** | `public` |
| **Implements** | `IDisposable` |
| **Responsibility** | Validates the supplied service URL, constructs the generated `clsGenerateSoapClient` with a raised-quota binding and an explicit address, maps caller types to the generated contract types, and exposes preview, distribution, and listing methods |
| **Proxy lifetime** | Shared — one `clsGenerateSoapClient` is created in the wrapper's constructor and held for the wrapper's lifetime |

| Configuration applied | Value | Source |
| --- | --- | --- |
| `BasicHttpBinding` security mode | None declared — `BasicHttpBinding()` defaults*, so `BasicHttpSecurityMode.None` applies | `DocumentServiceProxy.cs:23` |
| Transport client credential | None set | `DocumentServiceProxy.cs:23-27` |
| `MaxReceivedMessageSize` | `int.MaxValue` | `DocumentServiceProxy.cs:24` |
| `MaxBufferSize` | Not set — WCF default applies* | `DocumentServiceProxy.cs:23-27` |
| `ReaderQuotas.MaxArrayLength` | `int.MaxValue` | `DocumentServiceProxy.cs:25-27` |
| Timeouts | None set — binding defaults apply* | `DocumentServiceProxy.cs:23-27` |

## Endpoint resolution

| Environment | Address | Resolved from | Changeable without a rebuild |
| --- | --- | --- | --- |
| dev1, dev2, test1, test2, qa | `http://xpressionsdev:8000/wsDocuments/clsGenerate.asmx` | `Services/SAIF.Services.WebApi/EnvironmentApi/App_Data/environments.xml:22,41,60,79,97` | Yes |
| prod | `http://xpressionsprod:8000/wsDocuments/clsGenerate.asmx` | `environments.xml:115` | Yes |

Test, QA, and every non-prod track share the dev host `xpressionsdev`; the test mocks use the same value (`Tests/SAIF.Services.Tests/Agencies/AgenciesTestBase.cs:24`). The link between `IEnvironmentService.GetConfigSetting` and `environments.xml` is inferred*, because the `IEnvironmentService` implementation is not defined in this repository.

## Lifetime and disposal

| Aspect | Finding |
| --- | --- |
| Proxy lifetime | Per consuming instance — one `clsGenerateSoapClient` is created per `DocumentServiceProxy` and reused for the owner's lifetime |
| Disposal | `Dispose()` calls `webService.Close()` (`DocumentServiceProxy.cs:217-225`); there is no `Abort()` fallback |
| Faulted-channel handling | `Close()` on a faulted `ClientBase<T>` throws `CommunicationObjectFaultedException`* and poisons every later call on that instance |
| Thread safety | Not determined from source |

## Integration points

| System | Type | Purpose |
| --- | --- | --- |
| `clsGenerate` | SOAP service | Renders and distributes xPression-authored document packages |

## Related documentation
- [Client index](index.md)
- [Overview](overview.md)
- [Contract](contract.md)
- [Operation map](operation-map.md)
- [Client reference](reference.md)
- [Consumption](consumption.md)
- [Dependencies](dependencies.md)
- [Business rules](business-rules.md)
- [Tech debt](tech-debt.md)

> **Note:** Statements marked with `*` were inferred from code structure or contextual
> evidence.

## Sources
- `Services/SAIF.Services.Web.Proxies/DocumentServiceProxy.cs`
- `Services/SAIF.Services/Utilities/Documents/DocumentService.cs`
- `Services/SAIF.Services.WebApi/EnvironmentApi/App_Data/environments.xml`
