Skip to main content

SOAP HttpClient Sample

The ECGrid-SOAP-dotnet10-Console-HttpClient project demonstrates calling the ECGridOS SOAP API without a generated proxy. Instead, SOAP envelopes are constructed manually using XDocument and sent with HttpClient. This approach gives maximum control and has minimal dependencies.

:::caution Established API The ECGridOS SOAP API is in maintenance mode. For new integrations, use the REST API instead. This sample is provided for teams maintaining or migrating existing SOAP-based integrations. :::

Project Location

samples/soap/ECGrid-SOAP-dotnet10-Console-HttpClient/

What It Demonstrates

  • Constructing SOAP 1.1 envelopes with XDocument
  • Sending SOAP requests with HttpClient and the correct SOAPAction header
  • Parsing SOAP response XML with LINQ to XML
  • Full session lifecycle: Login → operations → Logout
  • Operations covered: Login, ParcelInBox, ParcelDownload, ParcelDownloadConfirm, Logout

SOAP Endpoint Details

PropertyValue
Endpointhttps://os.ecgrid.io/v4.1/prod/ECGridOS.asmx
XML Namespacehttp://www.ecgridos.net/
SOAP VersionSOAP 1.1
Content-Typetext/xml; charset=utf-8

Key Files

FilePurpose
Program.csEntry point — full session workflow
SoapClient.csReusable helper for sending SOAP envelopes
appsettings.jsonLogin credentials and endpoint URL

Key Patterns

SOAP Envelope Construction

/// <summary>
/// Builds a SOAP 1.1 envelope wrapping a single operation element.
/// </summary>
private static XDocument BuildEnvelope(string methodName, string ns, params (string Name, string Value)[] parameters)
{
var soapNs = XNamespace.Get("http://schemas.xmlsoap.org/soap/envelope/");
var apiNs = XNamespace.Get(ns);

// SOAP body element containing the operation and its parameters
var bodyContent = new XElement(apiNs + methodName,
parameters.Select(p => new XElement(apiNs + p.Name, p.Value)));

return new XDocument(
new XElement(soapNs + "Envelope",
new XAttribute(XNamespace.Xmlns + "soap", soapNs),
new XAttribute(XNamespace.Xmlns + "ecg", apiNs),
new XElement(soapNs + "Body", bodyContent)));
}

Sending a SOAP Request

private const string EcgNs = "http://www.ecgridos.net/";
private const string EndpointUrl = "https://os.ecgrid.io/v4.1/prod/ECGridOS.asmx";

/// <summary>
/// Posts a SOAP envelope and returns the parsed response document.
/// </summary>
private static async Task<XDocument> PostSoapAsync(
HttpClient http, string methodName, XDocument envelope)
{
var body = new StringContent(
envelope.ToString(),
System.Text.Encoding.UTF8,
"text/xml");

// SOAPAction header is required by SOAP 1.1; value identifies the operation
body.Headers.Add("SOAPAction", $"\"{EcgNs}{methodName}\"");

var response = await http.PostAsync(EndpointUrl, body);
response.EnsureSuccessStatusCode();

var xml = await response.Content.ReadAsStringAsync();
return XDocument.Parse(xml);
}

Session Lifecycle

// Program.cs — .NET 10 top-level statements

// Load credentials from IConfiguration — never hardcoded
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddUserSecrets<Program>()
.Build();

using var http = new HttpClient(); // Console sample — single instance is acceptable here

// --- Login ---
var loginEnvelope = BuildEnvelope("Login", EcgNs,
("Login", config["ECGridOS:Login"]!),
("Password", config["ECGridOS:Password"]!));

var loginResponse = await PostSoapAsync(http, "Login", loginEnvelope);

XNamespace ns = EcgNs;
// Extract the session ID from the Login response
var sessionId = loginResponse
.Descendants(ns + "LoginResult")
.First().Value;

// --- Check inbox ---
var inboxEnvelope = BuildEnvelope("ParcelInBox", EcgNs,
("SessionID", sessionId),
("MailboxID", config["ECGridOS:MailboxId"]!));

var inboxResponse = await PostSoapAsync(http, "ParcelInBox", inboxEnvelope);

foreach (var parcel in inboxResponse.Descendants(ns + "ParcelIDInfo"))
{
var parcelId = parcel.Element(ns + "ParcelID")!.Value;

// --- Download parcel ---
var downloadEnvelope = BuildEnvelope("ParcelDownload", EcgNs,
("SessionID", sessionId),
("ParcelID", parcelId));

var downloadResponse = await PostSoapAsync(http, "ParcelDownload", downloadEnvelope);
var base64Content = downloadResponse
.Descendants(ns + "ParcelDownloadResult")
.First().Value;

var ediBytes = Convert.FromBase64String(base64Content);
await File.WriteAllBytesAsync($"parcel-{parcelId}.edi", ediBytes);

// --- Confirm download ---
var confirmEnvelope = BuildEnvelope("ParcelDownloadConfirm", EcgNs,
("SessionID", sessionId),
("ParcelID", parcelId));

await PostSoapAsync(http, "ParcelDownloadConfirm", confirmEnvelope);
}

// --- Logout ---
var logoutEnvelope = BuildEnvelope("Logout", EcgNs, ("SessionID", sessionId));
await PostSoapAsync(http, "Logout", logoutEnvelope);

Configuration

{
"ECGridOS": {
"Login": "",
"Password": "",
"MailboxId": 0
}
}

Store credentials with user-secrets:

cd samples/soap/ECGrid-SOAP-dotnet10-Console-HttpClient
dotnet user-secrets set "ECGridOS:Login" "your-login"
dotnet user-secrets set "ECGridOS:Password" "your-password"

How to Run

cd samples/soap/ECGrid-SOAP-dotnet10-Console-HttpClient
dotnet user-secrets set "ECGridOS:Login" "your-login"
dotnet user-secrets set "ECGridOS:Password" "your-password"
dotnet run

See Also