---
title: Cross-site remote form redirect
summary: Forwards a user, along with POST-body parameters, from an ASP.NET web application to a target URL by writing and auto-submitting a hidden HTML form.
status: draft
owner: <owner>
last_reviewed: 2026-07-30
library: SAIF.Services.Web
reference_type: package
operation_id: OP-SW-01
trigger: Caller code constructs a RemotePost instance, adds inputs, and calls Post()
---

# Cross-site remote form redirect

This is the only operation exposed by `SAIF.Services.Web`. It gives an ASP.NET page or handler a way to forward the current user's browser, together with a set of POST-body name/value parameters, to another URL — for example a payment gateway or another SAIF web application — where a plain HTTP redirect (a GET) cannot carry the required data. The class accumulates the caller's inputs, writes a minimal self-submitting HTML `<form>` directly to the current response, and ends the response so the browser executes the auto-submit and issues the outbound POST.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-SW-01 |
| **Trigger** | Caller instantiates `RemotePost`, sets `URL`, calls `AddInput` for each parameter, optionally sets `FormName`, then calls `Post()` |
| **Inputs** | Target `URL` (string), one or more `Name`/`Value` pairs added via `AddInput`, optional `FormName` (defaults to `"form1"`) |
| **Outputs** | An HTML response written to the current ASP.NET response containing a hidden `<form>` that auto-submits via a `<body onload>` handler; the current response is cleared and ended as part of this operation |
| **Primary components** | `RemotePost` (`AddInput`, `URL`, `FormName`, `Post`) |
| **Entry point** | `Services\SAIF.Services.Web\RemotePost.vb` |

## Steps

1. Caller instantiates `RemotePost`. The instance starts with an empty internal `NameValueCollection` of inputs and a default `FormName` of `"form1"`.
2. Caller sets the `URL` property to the destination address that the auto-submitted form will POST to.
   - If `URL` is never set, it remains `Nothing`/empty, and the generated form's `action` attribute is written as an empty string, causing the browser to POST back to the current page instead of an external target.*
3. Caller calls `AddInput(Name, Value)` once for each parameter to be sent as a hidden form field. Each call adds an entry to the internal `NameValueCollection`; the collection allows duplicate `Name` keys, so calling `AddInput` twice with the same name accumulates rather than replaces the value.*
4. Caller optionally sets `FormName` to override the default `"form1"`, which changes both the form's `name` attribute and the `document.<FormName>.submit()` call emitted in the `onload` handler.
5. Caller calls `Post()`, which performs the remainder of this operation against `HttpContext.Current`.
   - On failure: if `Post()` executes outside an active ASP.NET web request (i.e., `HttpContext.Current` is null), a `NullReferenceException` occurs when the method dereferences `HttpContext.Current.Response`.*
6. `Post()` calls `HttpContext.Current.Response.Clear()`, discarding any response content buffered before this call.
7. `Post()` writes the opening `<html><head>` markup, then closes the head and opens `<body>` with an `onload="document.<FormName>.submit()"` attribute.
8. `Post()` writes a `<form>` element with `name="<FormName>"`, `method="post"`, and `action="<URL>"`.
9. `Post()` iterates every key in the internal inputs collection and writes one hidden `<input name="<Key>" type="hidden" value="<Value>">` element per entry, in the collection's enumeration order.
   - Caller-supplied `Name` and `Value` strings are written directly into the HTML attribute values via `String.Format` with no HTML-encoding; values containing quote characters or HTML-significant characters can produce malformed markup or, if the values originate from untrusted input, enable HTML/script injection.*
10. `Post()` writes the closing `</form>` and `</body></html>` tags.
11. `Post()` calls `HttpContext.Current.Response.End()`, which flushes the written HTML to the client and terminates further processing of the current request.
12. The browser receives the HTML page; because scripting is enabled, the `<body onload>` handler fires and submits the form, issuing an HTTP POST containing all registered name/value pairs to the target `URL`.
    - If the browser has JavaScript disabled, the `onload` handler never fires and the auto-submit does not occur, leaving the user on the intermediate blank page with no visible fallback submit control.*

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Caller constructs RemotePost]) --> SetUrl[Set URL property]
	SetUrl --> AddInputs[Call AddInput for<br>each name/value pair]
	AddInputs --> OptFormName{Override<br>FormName?}
	OptFormName -->|Yes| SetFormName[Set FormName property]
	OptFormName -->|No| CallPost[Call Post]
	SetFormName --> CallPost
	CallPost --> HasContext{HttpContext.Current<br>available?}
	HasContext -->|No| Err([NullReferenceException])
	HasContext -->|Yes| Clear[Response.Clear]
	Clear --> Write[Write hidden form with<br>one input per name/value pair]
	Write --> End[Response.End]
	End --> Browser[Browser receives HTML]
	Browser --> JsCheck{JavaScript<br>enabled?}
	JsCheck -->|Yes| AutoSubmit([onload fires;<br>browser POSTs to target URL])
	JsCheck -->|No| Stuck([Form never submits;<br>user stuck on blank page])
```

## Failure and edge-case behavior

- If `Post()` is called outside an active ASP.NET web request context (i.e., `HttpContext.Current` is null), a `NullReferenceException` occurs at runtime.*
- If `URL` is not set before calling `Post()`, the generated form targets an empty `action` attribute, causing the browser to POST back to the current page rather than an external target.*
- Caller-supplied `Name`/`Value` pairs are written directly into HTML `<input>` attribute values without HTML-encoding; values containing HTML-special characters may produce malformed markup or enable injection if untrusted input is passed.*
- Duplicate `AddInput` calls with the same `Name` accumulate multiple values under that key in the underlying `NameValueCollection` rather than overwriting the prior value, and all are written as separate hidden inputs with the same `name` attribute.*
- If the browser has JavaScript disabled, the `onload` auto-submit never fires and the request is never forwarded to the target URL, with no visible fallback for the user.*
- `Response.End()` terminates the current request pipeline; any code after the `Post()` call in the caller's page lifecycle does not execute for the current request.*

## 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.

## Sources

- `Services\SAIF.Services.Web\RemotePost.vb`
