---
id: web--soap-handler
title: "SOAP handler"
summary: "Answers one SOAP operation behind an **Http listener**: it reads the request envelope (SOAP 1.1 or 1.2, document/literal wrapped) into a typed record, emits it, and sends what the flow returns to its `Response` pin back as the SOAP response, or a SOAP fault. Connect one SOAP handler per operation to the same listener `Output` pin; together they are one SOAP service, and they serve its WSDL at `?wsdl`."
audience: user
keywords: "input, output, validate, response, operation, typename, operationspecification"
---
# SOAP handler

Answers one SOAP operation behind an **Http listener**: it reads the request envelope (SOAP 1.1 or 1.2, document/literal wrapped) into a typed record, emits it, and sends what the flow returns to its `Response` pin back as the SOAP response, or a SOAP fault. Connect one SOAP handler per operation to the same listener `Output` pin; together they are one SOAP service, and they serve its WSDL at `?wsdl`.

## Pins

| Pin | Kind | Types | Description |
|---|---|---|---|
| Input | input | `Viaducta.Plugins.Http.Types.WebHttpRequest` | Request from the Http listener `Output` pin. |
| Output | output | generated (see Behaviour) | The operation's parameters as a typed record. |
| Validate | validate | `Viaducta.Plugins.SoapHandler.SoapRequest` | Called before the output with the call (`HttpRequest`, `SoapAction`, `OperationName`, `Namespace`, `SoapVersion` `1.1`/`1.2`, `Header` as XML text, WS-Security `UserName`, `Password`, `PasswordType`). An error answers a client fault. |
| Response | input | the return type, or `Viaducta.TypeSystem.Metadata.NoInputData`; `Viaducta.Plugins.SoapHandler.SoapFault` | Connect the operation's result here (from the end of the branch that starts at `Output`); it is sent as the response. A `SoapFault` is sent as a fault. |

## Configuration

| Field | Type | Default | Description |
|---|---|---|---|
| `Operation` | operation builder | | Required. Display form `Service.Name`. Regenerated from `OperationSpecification` (reconfigures the component). |
| `TypeName` | string | | Name of the generated output type. Empty: `<name>Request`. Changing it reconfigures the component. |
| `OperationSpecification` | hidden string (JSON) | | The actual definition, written by the operation builder dialog. |

### OperationSpecification format

```json
{
  "service": "OrderService",
  "namespace": "http://example.com/orders",
  "name": "GetOrder",
  "soapAction": "",
  "parameters": [
    { "name": "id", "type": "System.Int32" },
    { "name": "includeLines", "type": "System.Boolean", "defaultValue": "false" }
  ],
  "returnType": "Orders.Order"
}
```

- `service`: groups operations into one port type, bindings and service in the WSDL. Empty: `Service`.
- `namespace`: the XML namespace of the request and response elements. Empty: `http://tempuri.org/`.
- `soapAction`: empty means `<namespace without trailing />/<service>/<name>`.
- `parameters[].type`: .NET full type name (`System.String`, `System.Int32`, ...) or the full name of a flow type.
- `returnType`: full name of a flow type; empty for an operation that answers an empty response.
- After editing the JSON by hand, the `Operation` field must be reconfigured to regenerate the output type and the `Response` pin types.

## Behaviour

- Matching: only `POST` requests with `Content-Type` `text/xml`, `application/soap+xml` or `application/xml` whose body is a SOAP envelope. The action comes from the `SOAPAction` header (1.1) or the `action` parameter of the `Content-Type` (1.2). If an operation of the flow has that action, the action decides; otherwise the request element's name and namespace (`<GetOrder xmlns="http://example.com/orders">`) decide.
- Output type: no parameters → `Viaducta.TypeSystem.Metadata.NoInputData`; a single parameter whose type is a flow type → that type; otherwise a generated class (`TypeName`) with one property per parameter. Saving the operation or changing `TypeName` rebuilds it and removes the type generated before.
- Request XML: one child element per parameter, in the operation's namespace, matched by local name. Lists are `<item>` children, dictionaries `<entry><key/><value/></entry>`, enums their member names (numbers accepted), `xsi:nil="true"` is null. A missing parameter takes its `defaultValue`.
- Response: `<NameResponse><NameResult>...</NameResult></NameResponse>` with the record sent to `Response`, HTTP `200`, in the request's SOAP version (`text/xml` for 1.1, `application/soap+xml` for 1.2).
- When the flow is done and nothing answered: an operation without `returnType` and with nothing connected to `Response` answers an empty `<NameResponse/>`; any other gets a server fault "The operation ... sent no response".
- Faults: a request that is not a SOAP envelope, not valid XML (DTDs are refused), not readable as the output type, or refused by `Validate` gets a client fault; an error in the flow after `Output` gets a server fault with the error message. SOAP 1.1 faults are HTTP `500` (`soap:Client` / `soap:Server`); SOAP 1.2 Sender faults `400`, Receiver faults `500`. The detail is a `ViaductaError` element (flow, component, trace id) in `urn:viaducta:error`.
- `SoapFault` on `Response`: `Code` `Client`/`Sender` or `Server`/`Receiver` (a custom code such as `Client.NotFound` becomes the 1.1 `faultcode` or the 1.2 `Subcode`), `Message` the reason, `Detail` an XML element or text (empty: the `ViaductaError` detail), `StatusCode` `0` for the SOAP default.
- A SOAP request that no SOAP handler of the flow matches is answered with a client fault by one handler.
- A `GET` with a `wsdl` or `singleWsdl` query parameter is answered with the WSDL 1.1 document of all SOAP handlers in the flow (one handler answers it). It has an inline XML schema per namespace, a port type per service and a SOAP 1.1 and a SOAP 1.2 binding. The address is the request's url without the query, or the one `X-Forwarded-Proto` / `X-Forwarded-Host` / `X-Forwarded-Prefix` name. The designer's operation builder shows the same document and a Try it page (sample envelope, curl and PowerShell).

## Notes

- Only document/literal wrapped messages; no RPC/encoded, MTOM attachments, WS-Addressing or WS-Security signing. The WS-Security `UsernameToken` is read and given to `Validate`; checking it is up to the flow.
- Two operations with the same request element or action: the WSDL lists the first and names the other in its documentation; both handlers are called for such a request and the first answer is sent.
- The response is sent once; a second record on `Response` is logged and dropped.
- Untyped (`System.Object`) values are written as text; an empty object comes back as an empty string.

## Example

Http listener (`http://0.0.0.0:9000/orders`) → **SOAP handler** (`OrderService.GetOrder`, `Output`) → Database reader → Mapping (to `Orders.Order`) → **SOAP handler** `Response`

`GET http://host:9000/orders?wsdl` returns the WSDL; clients post envelopes to `http://host:9000/orders`.
