Example: SOAP client consumption¶
consumption.md tells a consumer how to reference, construct, call, and dispose
a SOAP client proxy, and what resilience the package does and does not provide.
Doc gen produces one per SOAP client package at
docs/clients/<client-slug>/consumption.md: the reference style, the
construction code, the endpoint configuration, the six resilience concerns,
disposal, the exceptions a caller must handle, and usage drawn from real
consumer source.
What reviewers should check¶
- The reference style names the real mechanism (Service Reference, Web
Reference, or
ChannelFactory<T>), the file that declares it, the generated file, and the regeneration command. A hand edit inside generated code is called out, because the next refresh discards it. - The construction code is copied from source, not rewritten, and no credential value appears; only the credential type and where it comes from.
- Endpoint configuration says where the address comes from and whether an
operator can change it without a rebuild. A library project's
app.configis not read at run time, and the page says the consumer must copy the sections. - All six resilience rows are present: timeout, retry, circuit breaking, thread
safety, cancellation, and message size limits. "None configured" is a finding,
not a blank, and each one is expanded in the prose below the table with what a
consumer must do instead. A source column cites a file and line, or reads
-. - Disposal records what the repository does, not what it should do. Here
Dispose()callsClose()with noAbort()on a faulted channel, and the page says that a faulted channel throws from disposal and masks the original failure instead of showing the correct pattern. - Every exception type in Error handling for consumers carries the dagger
marker, because it describes behavior inherited from the framework, and the
note box follows Related documentation. A fault type local to the service,
ClaimValidationFault, is named only inside the genericFaultException. - The empty-output row names the actual value a caller gets, here
null, and says what it can mean. It must agree with the service documentation, where the service also returns null when its own lookup fails. - Usage examples come from real source, here the integration tests, and each cites file and line in the Notes column. An invented usage pattern is a defect.
- Lifecycle answers agree with the rest of the page: not safe to share, so a gateway per unit of work, and disposable.
- No HTTP vocabulary: no verb, route, or status code. A SOAP fault is a fault,
and a timeout is a
TimeoutException.
Example¶
The document below is a complete, correct client-consumption.md for a
fictional SOAP client package.
View rendered example — the same document as a real page, so you can compare rendering as well as source.
---
title: Consumption
summary: How a consuming application references, constructs, calls, and disposes the proxy.
status: draft
owner: Claims Systems Team
last_reviewed: 2026-09-10
---
# Consumption
A consumer references `SAIF.Claims.Intake.Client`, copies the `ClaimIntakeBasic` client endpoint into its own configuration file, constructs a `ClaimIntakeGateway` with that endpoint name, calls `Submit` or `GetStatus`, and disposes the gateway. The gateway wraps a svcutil-generated `ClaimIntakeClient`. It applies a 30-second send timeout, performs no retry, and is not safe for concurrent use.
## Reference style
| Field | Value |
| --- | --- |
| Mechanism | Service Reference (svcutil) |
| Declared in | `src/SAIF.Claims.Intake.Client/Service References/ClaimIntakeReference/Reference.svcmap` |
| Generated artifacts | `src/SAIF.Claims.Intake.Client/Service References/ClaimIntakeReference/Reference.cs` |
| Target framework | .NET Framework 4.8 |
| Regeneration command | Visual Studio "Update Service Reference" |
`Reference.cs` has no hand edits, so a refresh does not discard any repository change.
## Construction
```csharp
public ClaimIntakeGateway(string endpointConfigurationName)
{
_client = new ClaimIntakeClient(endpointConfigurationName);
_client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Identification;
}
```
| Step | Requirement |
| --- | --- |
| Endpoint address | Read from the `<client><endpoint name="ClaimIntakeBasic">` element of the consuming application's configuration file, selected by the `endpointConfigurationName` constructor argument |
| Binding | Named binding configuration `ClaimIntakeBasic` |
| Credentials | Windows transport credential of the calling process, with an impersonation level of `Identification` |
| Initialization | Single-constructor |
## Endpoint configuration
| Setting | Value | Source | Changeable without a rebuild |
| --- | --- | --- | --- |
| Endpoint address | `http://claims-intake-dev.saif.example/ClaimIntake.svc` | `src/SAIF.Claims.Intake.Client/app.config` | Yes |
| Binding configuration | `ClaimIntakeBasic` | `src/SAIF.Claims.Intake.Client/app.config` | Yes |
| Security mode | `TransportCredentialOnly` (`clientCredentialType="Windows"`) | `src/SAIF.Claims.Intake.Client/app.config:14` | Yes |
A class library's own `app.config` is not read at run time. The consuming application must copy the `<client>` and `<bindings>` sections into its own configuration file, which is also where each environment sets its address.
## Resilience
| Concern | Finding | Configurable by consumer | Source | Tech debt |
| --- | --- | --- | --- | --- |
| Timeout | 30 seconds | Yes (`sendTimeout`) | `src/SAIF.Claims.Intake.Client/app.config:12` | No |
| Retry | None configured | No | - | Yes |
| Circuit breaking | None configured | No | - | Yes |
| Thread safety | Not safe - one channel is shared by every call on a gateway instance | - | `src/SAIF.Claims.Intake.Client/ClaimIntakeGateway.cs:21` | Yes |
| Cancellation | Not supported - no cancellation on any call site | - | - | No |
| Message size limits | None set - binding defaults apply | Yes (`maxReceivedMessageSize`) | - | No |
A consumer that needs retry must wrap each call in its own policy and create a new gateway for each attempt, because a faulted channel cannot be reused. A consumer that needs circuit breaking must provide it outside the package. A consumer that calls from several threads must construct one gateway per thread. The retry, circuit breaking, and thread safety findings are recorded in [Tech debt](tech-debt.md).
## Disposal
| Aspect | Finding |
| --- | --- |
| Disposal performed | `Close()` |
| Faulted channel handled | No - a faulted channel throws from disposal and masks the original failure |
| Wrapper responsibility | `ClaimIntakeGateway` disposes the proxy |
| Source | `src/SAIF.Claims.Intake.Client/ClaimIntakeGateway.cs:78` |
```csharp
public void Dispose()
{
_client.Close();
}
```
## Error handling for consumers
| Failure | Surfaces as | Consumer action |
| --- | --- | --- |
| Service unreachable | `EndpointNotFoundException`† | Treat as transient, check the configured address, and retry with a new gateway |
| SOAP fault returned | `FaultException<ClaimValidationFault>`† for a failed validation on `SubmitClaim`, `FaultException`† for any other failure | Read `Detail.Code` and `Detail.FieldErrors` from the typed fault; treat the generic fault as a service error and do not retry blindly |
| Timeout exceeded | `TimeoutException`† | Retry with a new gateway, because the channel is faulted after a timeout |
| Response larger than the message size limit | `CommunicationException`† | Raise `maxReceivedMessageSize` in the consuming application's binding configuration |
| Empty or absent output message | `null` from `GetStatus` | Treat as "claim not found or status unavailable"; the service also returns null when its own lookup fails |
## Usage examples
```csharp
// Submit a claim, then read its status
using (var gateway = new ClaimIntakeGateway("ClaimIntakeBasic"))
{
ClaimReceipt receipt = gateway.Submit(submission);
ClaimStatusResult status = gateway.GetStatus(receipt.ClaimNumber);
}
```
```csharp
// Handle a validation failure
try
{
gateway.Submit(submission);
}
catch (FaultException<ClaimValidationFault> ex)
{
Assert.Equal("INJURY_DATE_FUTURE", ex.Detail.Code);
}
```
| Scenario | Operations used | Notes |
| --- | --- | --- |
| Submit a claim and read its status | `SubmitClaim`, `GetClaimStatus` | Taken from `tests/SAIF.Claims.Intake.Client.IntegrationTests/GatewayTests.cs:18` |
| Handle a validation failure | `SubmitClaim` | Taken from `tests/SAIF.Claims.Intake.Client.IntegrationTests/GatewayTests.cs:41` |
## Lifecycle guidance
| Question | Answer |
| --- | --- |
| Construct once or per call | Per unit of work - every integration test constructs a gateway inside a `using` block and disposes it after one or two calls |
| Disposable | Yes (`IDisposable`) |
| Safe to share across threads | No - see the Thread safety row in Resilience |
## Related documentation
- [Client index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Contract](contract.md)
- [Operation map](operation-map.md)
- [Client reference](reference.md)
- [Dependencies](dependencies.md)
- [Tech debt](tech-debt.md)
> **Note:** Statements marked with † were retrieved from dependency library documentation
> via the Legends CLI RAG service. They describe inherited behavior from the indicated
> origin library and should be verified if the dependency version changes.
## Sources
- `src/SAIF.Claims.Intake.Client/ClaimIntakeGateway.cs`
- `src/SAIF.Claims.Intake.Client/Service References/ClaimIntakeReference/Reference.svcmap`
- `src/SAIF.Claims.Intake.Client/Service References/ClaimIntakeReference/Reference.cs`
- `src/SAIF.Claims.Intake.Client/app.config`
- `tests/SAIF.Claims.Intake.Client.IntegrationTests/GatewayTests.cs`