Example: SOAP service activation and hosting (ASMX)¶
activation-hosting.md records how an ASMX web service publishes its
operations: the marker files that activate each service class, the metadata and
test surface it exposes, the other projects that share its repository, and the
deployment variants it builds. Doc gen produces one per ASMX service at
docs/services/<service-slug>/activation-hosting.md.
What reviewers should check¶
- ASMX is activated by a file, not by configuration. Each
.asmxmarker file is a one-line@WebServicedirective, and its path within the project is the service's address. The page says there is no route table and no<system.serviceModel>section, which is the opposite of the WCF activation page, where a.svcfile or a service route and a<services>block define the endpoint. - WCF vocabulary does not leak in. An ASMX page has no bindings, endpoint
contracts, service behaviors, or
ServiceHostFactory; a reviewer should not expect them, and their presence would mean the wrong template was used. - The marker file inventory has one row per
.asmxfile, including files in a subfolder, and the subfolder appears in the address suffix. Check that the marker file name and the class differ where they do here (CoverageCheck.asmxactivatesCoverageVerifier), because the address and the class name are not interchangeable. - The service count agrees across the page: three marker files, four operations, three services listed for the project in the host inventory, and the same three-and-two split in the deployment variants.
- Metadata and test surface are stated plainly. WSDL, the ASP.NET test page, and the documentation protocol are on by default, and an ASMX service that does not turn them off exposes an invocable form for every operation. The page says so and points to tech debt, and the cell reads "Not determined from source" when configuration cannot be evidenced.
- The host inventory places this project among its siblings. A second in-repo class library is an embedded library and links to its library document set, not to a services set. A project with no documentation reads "Not documented".
- A service class deployed by two hosts is documented in full in only one set. The table names that primary set, and states whether the second host shares the file or carries a copy. A separate copy would be a divergence risk and a tech-debt finding.
- Each deployment variant is a separate surface with its own audience and configuration. Variant differences cite the transform file or project file the value came from, and do not repeat settings that are identical in both.
- The IIS configuration cells come from checked-in files, here the release variables pipeline file. Anything not in the repository reads "Not determined from source" or "Not declared", and is not guessed.
- The diagram uses real names for the first operation path and matches the directive form in the activation table. Links are relative to the service's document root.
Example¶
The document below is a complete, correct service-activation-hosting.md for a
fictional ASMX service.
View rendered example — the same document as a real page, so you can compare rendering as well as source.
---
title: Activation and hosting
summary: Marker files, codebehind mapping, host inventory, and deployment variants.
status: draft
owner: Employer Systems Team
last_reviewed: 2026-09-10
---
# Activation and hosting
`SAIF.Employer.Lookup.Service` publishes four operations through three `.asmx` marker files, which are served by IIS under the `EmployerLookupService` virtual directory, and it produces two deployable variants: an internal build that exposes all three services and an external build that omits the code table service.
## Activation mechanism
| Aspect | Finding |
| --- | --- |
| Mechanism | `.asmx` marker file + codebehind |
| Marker files | 3 |
| Directive form | `<%@ WebService Language="vb" CodeBehind="EmployerLookup.asmx.vb" Class="SAIF.Employer.Lookup.Service.EmployerLookup" %>` |
| Route table | Not used |
| `<system.serviceModel>` | Not present |
| Address composition | Application base address + the marker file's path within the project |
`Global.asax` configures logging at application start and registers nothing else, so the marker files are the only way a request reaches a service class.
## Marker file inventory
| Marker file | Language | Codebehind | Class | Address suffix |
| --- | --- | --- | --- | --- |
| `EmployerLookup.asmx` | `vb` | `EmployerLookup.asmx.vb` | `SAIF.Employer.Lookup.Service.EmployerLookup` | `/EmployerLookup.asmx` |
| `CoverageCheck.asmx` | `vb` | `CoverageCheck.asmx.vb` | `SAIF.Employer.Lookup.Service.CoverageVerifier` | `/CoverageCheck.asmx` |
| `Reference/CodeTables.asmx` | `vb` | `CodeTables.asmx.vb` | `SAIF.Employer.Lookup.Service.CodeTableService` | `/Reference/CodeTables.asmx` |
Two of the three marker file names differ from the class they activate. A caller addresses `CoverageCheck.asmx`, and the class that answers is `CoverageVerifier`. `Reference/CodeTables.asmx` carries its subfolder in the address.
## Activation diagram
The following diagram visualizes how a request reaches an operation.
```mermaid
flowchart TD
REQ["Caller request<br>/EmployerLookupService/EmployerLookup.asmx"] --> IIS["IIS maps .asmx<br>to the ASP.NET handler"]
IIS --> DIRECTIVE["WebService directive<br>names SAIF.Employer.Lookup.Service.EmployerLookup"]
DIRECTIVE --> INST["EmployerLookup constructed<br>per request"]
INST --> ACTION{"SOAP action"}
ACTION -->|"FindEmployerByPolicyNumber"| WM["WebMethod invoked"]
ACTION -->|"GetEmployerContacts"| WM
ACTION -->|"Unknown"| FAULT["SOAP fault"]
WM --> RESP["Response message"]
```
## Metadata and test surface
| Aspect | Finding |
| --- | --- |
| WSDL document | `EmployerLookup.asmx?wsdl`, `CoverageCheck.asmx?wsdl`, `Reference/CodeTables.asmx?wsdl` |
| ASP.NET test page | Enabled (`HttpGet` / `HttpPost` protocols) |
| Documentation protocol | Enabled |
`Web.config` does not declare a `<webServices><protocols>` element and does not remove the documentation protocol, so anyone who can reach the service can read each WSDL and invoke every operation from the generated test page. This is raised in [Tech debt](tech-debt.md).
## Host inventory
This repository contains more than one deployable project. Each web service project has its own document set; this table places this one among them.
| Project | Kind | Services | Document set |
| --- | --- | --- | --- |
| `SAIF.Employer.Lookup.Service` | Web service | `EmployerLookup`, `CoverageVerifier`, `CodeTableService` | This set |
| `SAIF.Employer.Lookup.Service.X86` | Web service | `CoverageVerifier` | [SAIF.Employer.Lookup.Service.X86](../saif-employer-lookup-service-x86/index.md) |
| `SAIF.Employer.Lookup.Data` | Class library | - | [Embedded library](libraries/saif-employer-lookup-data/index.md) |
| `SAIF.Employer.Lookup.Service.Tests` | Test project | - | Not documented |
## Services hosted in more than one host
| Service class | Also deployed by | Implementation shared | Primary document set |
| --- | --- | --- | --- |
| `CoverageVerifier` | `SAIF.Employer.Lookup.Service.X86` | Same file (linked from `src/SAIF.Employer.Lookup.Service/CoverageCheck.asmx.vb`) | [SAIF.Employer.Lookup.Service](contracts/coverage-verifier.md) |
The x86 host compiles the same codebehind file into its own assembly, so there is one implementation and two deployments.
## Deployment variants
| Variant | Build configuration | Artifact | Config transform | Audience | Notes |
| --- | --- | --- | --- | --- | --- |
| Internal | `Release` | `SAIF.Employer.Lookup.Service.Internal.zip` | `Web.Release.config` | SAIF applications on the corporate network | All three services are published |
| External | `ReleaseExternal` | `SAIF.Employer.Lookup.Service.External.zip` | `Web.ReleaseExternal.config` | Partner systems outside the corporate network | `Reference/CodeTables.asmx` is excluded from the build in the project file |
### Variant differences
| Setting or behavior | Internal | External | Source |
| --- | --- | --- | --- |
| `MaxSearchResults` (`appSettings`) | 500 | 25 | `src/SAIF.Employer.Lookup.Service/Web.Release.config`, `src/SAIF.Employer.Lookup.Service/Web.ReleaseExternal.config` |
| Services exposed | All | `EmployerLookup`, `CoverageVerifier` | `src/SAIF.Employer.Lookup.Service/SAIF.Employer.Lookup.Service.vbproj` |
## IIS configuration
| Aspect | Finding |
| --- | --- |
| Site / virtual directory | Virtual directory `EmployerLookupService` under `Default Web Site` |
| Application pool | `SAIF-EmployerLookup` (.NET CLR v4.0) |
| Platform target | Any CPU |
| `httpErrors` mode | Not declared |
| Custom modules or handlers | None |
## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Operations](operations.md)
- [Faults and error pipeline](faults.md)
- [Authentication and authorization](authentication-authorization.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [Data model](data-model.md)
- [Operational runbook](operational-runbook.md)
- [Tech debt](tech-debt.md)
- [Embedded libraries](libraries/index.md)
## Sources
- `src/SAIF.Employer.Lookup.Service/EmployerLookup.asmx`
- `src/SAIF.Employer.Lookup.Service/EmployerLookup.asmx.vb`
- `src/SAIF.Employer.Lookup.Service/CoverageCheck.asmx`
- `src/SAIF.Employer.Lookup.Service/CoverageCheck.asmx.vb`
- `src/SAIF.Employer.Lookup.Service/Reference/CodeTables.asmx`
- `src/SAIF.Employer.Lookup.Service/Reference/CodeTables.asmx.vb`
- `src/SAIF.Employer.Lookup.Service/Global.asax`
- `src/SAIF.Employer.Lookup.Service/Web.config`
- `src/SAIF.Employer.Lookup.Service/Web.Release.config`
- `src/SAIF.Employer.Lookup.Service/Web.ReleaseExternal.config`
- `src/SAIF.Employer.Lookup.Service/SAIF.Employer.Lookup.Service.vbproj`
- `src/SAIF.Employer.Lookup.Service.X86/SAIF.Employer.Lookup.Service.X86.vbproj`
- `Pipelines/employer-lookup-release-vars.yml`