SmartWsdlKit is a lightweight, high-performance, enterprise-grade WSDL and SOAP client toolkit for .NET.
It is designed from the ground up to eliminate the complexity of Visual Studio Connected Services, svcutil, and legacy WCF configurations by providing a modern, developer-friendly, and async-first API.
SoapClient&SoapClientOptions: Modern, thread-safe, async-first SOAP client supporting full configuration inheritance (Envelope/Service namespaces, SOAPActions, Serializer modes, *Specified properties, Resilience, Diagnostics, Auth).SoapOperationBuilder: Fluent request construction supporting parameters, dynamic dictionaries, custom SOAP headers, HTTP headers, attachments, raw XML bodies, JSON inputs, and multiple execution shortcuts (ExecuteAsync<T>,ExecuteJsonAsync,ExecuteDictionaryAsync).SoapResponse: Flexible response wrapper allowing raw XML access, BodyXElementextraction, generic type deserialization (As<T>), runtime type deserialization (As(Type)), JSON projection (AsJson()), and dictionary mapping (ToDictionary()).DependencyInjection(AddSmartWsdlKit,AddSmartWsdlClient): NativeIServiceCollectionextensions withIHttpClientFactoryintegration for socket safety andILoggerstructured traffic logging.SoapXmlJsonEngine: Allocation-optimized JSON-to-XML and XML-to-JSON stream and string transformation engine.SoapRestBridge: API Gateway bridge engine enabling REST JSON endpoints to execute backend SOAP services seamlessly.WsdlExplorer&WsdlDocument: Rapid high-level service metadata exploration and full stream-based WSDL 1.1/2.0 schema parsing.WsdlAnalyzer: Automated WSDL schema complexity scoring and compatibility analysis.WsdlCodeGenerator&OpenApiGenerator: On-the-fly C# DTO/Record proxy code generation and WSDL to OpenAPI 3.x specification conversion.SoapResilienceEngine: Built-in, thread-safe Polly-less Retry and Circuit Breaker engine.- Zero Third-Party Dependencies: Relying exclusively on native .NET standard abstractions.
dotnet add package SmartWsdlKitusing SmartWsdlKit;
using SmartWsdlKit.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Register SmartWsdlKit with IHttpClientFactory and ILogger integration
builder.Services.AddSmartWsdlKit(options =>
{
options.BaseAddress = new Uri("http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso");
options.SerializerMode = SoapSerializerMode.StandardXml;
options.EnableDiagnostics = true;
});Inject SoapClient into controllers or minimal API endpoints:
app.MapGet("/api/capital/{isoCode}", async (string isoCode, SoapClient client, CancellationToken cancellationToken) =>
{
// Execute and deserialize directly to dictionary
var dict = await client.Operation("CapitalCity")
.With("sCountryISOCode", isoCode)
.ExecuteDictionaryAsync(cancellationToken);
return Results.Ok(dict["CapitalCityResult"]);
});// Pathway A: Direct options instance
using var client1 = new SoapClient(new SoapClientOptions
{
BaseAddress = new Uri("http://service.local/soap")
});
// Pathway B: Fluent inline SoapClient.Create(...) factory
using var client2 = SoapClient.Create("http://service.local/soap", options =>
{
options.EnableDiagnostics = true;
options.SerializerMode = SoapSerializerMode.DataContract;
});
// Pathway C: Dynamic initialization from live WSDL metadata
using var client3 = await SoapClient.FromWsdlAsync("http://service.local/service.wsdl");[DataContract(Namespace = "http://enterprise.org/contract")]
public class CustomerRequest
{
[DataMember(Name = "CustomerId", Order = 1)]
public int Id { get; set; }
[DataMember(Name = "CustomerName", Order = 2)]
public string Name { get; set; } = string.Empty;
[DataMember(Name = "Age", Order = 3, EmitDefaultValue = false)]
public int Age { get; set; }
public bool AgeSpecified { get; set; } // When false, Age element is omitted
}
// Fluent invocation with DataContract mode & Specified handling
var response = await client.Operation("ProcessCustomer")
.WithSerializerMode(SoapSerializerMode.DataContract)
.WithSpecifiedHandling(SpecifiedModeHandling.HonorSpecifiedProperties)
.With("customer", new CustomerRequest { Id = 101, Name = "Acme", AgeSpecified = false })
.ExecuteAsync(cancellationToken);var response = await client.Operation("UpdateInventory")
.WithSoapAction("http://tempuri.org/UpdateInventory")
.WithChildElementName("CustomItemRequest")
.WithSuppressAutoChildrenXmlNamespace(true) // Strip child element target namespaces
.With("itemCode", "ITEM-99")
.ExecuteAsync(cancellationToken);// 1. Strongly-typed POCO deserialization (.ExecuteAsync<T>)
CapitalCityResponse typedResp = await client.Operation("CapitalCity")
.With("sCountryISOCode", "TR")
.ExecuteAsync<CapitalCityResponse>(cancellationToken);
// 2. Direct JSON string shortcut (.ExecuteJsonAsync)
string jsonString = await client.Operation("CapitalCity")
.With("sCountryISOCode", "TR")
.ExecuteJsonAsync(cancellationToken);
// 3. Direct Dictionary shortcut (.ExecuteDictionaryAsync)
Dictionary<string, object?> dictMap = await client.Operation("CapitalCity")
.With("sCountryISOCode", "TR")
.ExecuteDictionaryAsync(cancellationToken);
// 4. Raw SoapResponse object methods
SoapResponse response = await client.Operation("CapitalCity")
.With("sCountryISOCode", "TR")
.ExecuteAsync(cancellationToken);
string rawXml = response.RawXml; // Full response SOAP XML string
XElement bodyXml = response.Body; // Body XElement
CapitalCityResponse poco = response.As<CapitalCityResponse>(); // Generic cast
object runtimeObj = response.As(typeof(CapitalCityResponse)); // Runtime Type cast
string jsonBody = response.AsJson(); // JSON string5. XML-to-JSON Transformer Engine (SoapXmlJsonEngine) & Schema JSON Template Generator (SoapJsonTemplateGenerator)
using SmartWsdlKit;
// Option A: Extract JSON Request Body template from live WSDL URL
string requestJson = await WsdlExplorer.GenerateJsonRequestTemplateAsync(
"http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL",
"CapitalCity"
);
// Output Request JSON Template:
// {
// "sCountryISOCode": "string"
// }
// Option B: Extract JSON Response Body template from live WSDL URL
string responseJson = await WsdlExplorer.GenerateJsonResponseTemplateAsync(
"http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL",
"FullCountryInfo"
);
// Output Response JSON Template:
// {
// "FullCountryInfoResult": {
// "sISOCode": "string",
// "sName": "string",
// "sCapitalCity": "string",
// "sPhoneCode": "string",
// "sContinentCode": "string",
// "sCurrencyISOCode": "string",
// "sCountryFlag": "string",
// "Languages": [
// {
// "sISOCode": "string",
// "sName": "string"
// }
// ]
// }
// }
// Option C: Extract Request & Response JSON templates for ALL operations from parsed WsdlDocument
var wsdlDoc = await WsdlDocument.LoadAsync("http://service.local/service.wsdl");
Dictionary<string, string> requestTemplates = wsdlDoc.GenerateAllJsonRequestTemplates();
Dictionary<string, string> responseTemplates = wsdlDoc.GenerateAllJsonResponseTemplates();using SmartWsdlKit.Transformers;
string xmlText = @"<Order xmlns=""http://tempuri.org/""><Id>500</Id><Amount>150.50</Amount></Order>";
// XML to JSON String Conversion
string jsonText = SoapXmlJsonEngine.XmlToJsonString(xmlText, new SoapJsonOptions
{
StripNamespaces = true,
InferTypes = true
});
// JSON to XML String Conversion
string xmlBack = SoapXmlJsonEngine.JsonToXmlString(jsonText, new SoapXmlOptions
{
RootElementName = "OrderPayload",
TargetNamespace = "http://tempuri.org/"
});
// Async Stream-based Conversion (Gateway pipeline optimized)
await SoapXmlJsonEngine.XmlToJsonStreamAsync(xmlInputStream, jsonOutputStream, cancellationToken: cancellationToken);using SmartWsdlKit.Bridge;
app.MapPost("/api/gateway/{operationName}", async (string operationName, [FromBody] object jsonBody, SoapRestBridge bridge, CancellationToken cancellationToken) =>
{
string jsonString = System.Text.Json.JsonSerializer.Serialize(jsonBody);
// Bridges REST JSON request to backend SOAP service and projects response back to JSON
string jsonResponse = await bridge.ExecuteRestRequestAsync(operationName, jsonString, cancellationToken);
return Results.Content(jsonResponse, "application/json");
});// 1. WsdlExplorer (Rapid high-level service metadata)
var info = await WsdlExplorer.ExploreAsync("http://service.local/service.wsdl");
Console.WriteLine($"Service: {info.ServiceName} | Operations: {string.Join(", ", info.SupportedOperations)}");
// 2. WsdlDocument & WsdlParser (Full schema parsing)
var wsdlDoc = await WsdlDocument.LoadAsync("http://service.local/service.wsdl");
// 3. WsdlAnalyzer (Schema complexity scoring & warnings)
var report = WsdlAnalyzer.Analyze(wsdlDoc);
Console.WriteLine($"Complexity Score: {report.ComplexityScore} / 100");
// 4. WsdlCodeGenerator (C# DTO proxy code generation)
string csharpCode = WsdlCodeGenerator.Generate(wsdlDoc, new CodeGeneratorOptions
{
Namespace = "MyGeneratedProxy",
GenerateRecords = true
});
// 5. OpenApiGenerator (WSDL to OpenAPI 3.0 conversion)
string openApiSpecJson = OpenApiGenerator.Generate(wsdlDoc);// 1. Basic Authentication
client.WithBasicAuth("username", "password");
// 2. Bearer Token
client.WithBearerToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...");
// 3. API Key (Header or Query)
client.WithApiKey("X-API-Key", "secret-key", ApiKeyLocation.Header);
// 4. WS-Security UsernameToken (Plaintext or Password Digest with Nonce & Created timestamp)
client.WithWsSecurity("WsdlUser", "SecretPassword123", WsSecurityPasswordType.PasswordDigest);
// 5. NTLM / Windows Authentication
client.WithNtlmAuth("win_user", "win_pass", "domain");var attachment = new SoapAttachment(
contentId: "file-01",
data: File.ReadAllBytes("contract.pdf"),
contentType: "application/pdf",
fileName: "contract.pdf"
);
var response = await client.Operation("UploadDocument")
.With("Document", attachment) // Serialized as xop:Include for MTOM or href/cid for SwA
.ExecuteAsync(cancellationToken);| Property | Type | Default | Description |
|---|---|---|---|
BaseAddress |
Uri? |
null |
Base endpoint URL of the target SOAP service. |
DefaultSoapAction |
string? |
null |
Default HTTP SOAPAction header for operations. |
TargetNamespace |
string? |
null |
Target URI namespace override for service operations. |
EnvelopeNamespace |
string? |
null |
Custom SOAP Envelope namespace URI (overrides standard SOAP 1.1 / 1.2). |
SerializerMode |
SoapSerializerMode |
StandardXml |
Serialization engine (StandardXml vs DataContract). |
SpecifiedHandling |
SpecifiedModeHandling |
HonorSpecifiedProperties |
Controls evaluation of boolean *Specified properties. |
SuppressAutoChildrenXmlNamespace |
bool |
false |
When true, strips explicit target namespaces from nested child elements. |
Timeout |
TimeSpan |
30s |
HTTP request timeout duration. |
RetryCount |
int |
0 |
Number of retry attempts on transient failures. |
RetryDelay |
TimeSpan |
2s |
Delay between retry attempts. |
EnableResilience |
bool |
false |
Enables built-in Polly-less retry and circuit breaker engine. |
CircuitBreakerFailureThreshold |
int |
5 |
Failures threshold before tripping circuit breaker OPEN. |
CircuitBreakerResetTimeout |
TimeSpan |
30s |
Duration circuit stays OPEN before moving to HALF-OPEN. |
EnableDiagnostics |
bool |
false |
Enables in-memory traffic diagnostics inspector logging. |
MaxDiagnosticsCount |
int |
100 |
Rolling buffer limit for diagnostic log entries. |
AttachmentMode |
SoapAttachmentMode |
SwA |
Attachment protocol (SwA vs Mtom). |
HttpClientFactory |
IHttpClientFactory? |
null |
External IHttpClientFactory instance for socket safety. |
HttpClientName |
string? |
"SmartWsdlKit" |
Named client identifier when resolving from IHttpClientFactory. |
Logger |
ILogger? |
null |
ILogger instance for structured logging output. |
Credentials |
ICredentials? |
null |
Network credentials for NTLM / Kerberos / Proxy auth. |
Proxy |
IWebProxy? |
null |
Network HTTP proxy server configuration. |
Cookies |
CookieContainer |
new() |
Cookie container for HTTP sessions. |
UserAgent |
string |
"SmartWsdlKit/1.0.3" |
HTTP User-Agent header value. |
CustomHeaders |
Dictionary<string, string> |
new() |
Custom HTTP headers applied to all client requests. |
SslProtocols |
SslProtocols? |
null |
SSL/TLS protocol versions to enable. |
BypassSslValidation |
bool |
false |
When true, completely bypasses SSL/TLS certificate validation. |
ServerCertificateCustomValidationCallback |
Func<...>? |
null |
Custom SSL server certificate validation callback. |
ConfigureHttpClientHandler |
Action<HttpClientHandler>? |
null |
Delegate for modifying HttpClientHandler properties (decompression, certs, redirect). |
ConfigureHttpClient |
Action<HttpClient>? |
null |
Delegate for modifying HttpClient instance properties. |
RequestEncoding |
Encoding |
UTF-8 |
Character encoding for request payloads. |
ResponseEncoding |
Encoding |
UTF-8 |
Character encoding for response payloads. |
BackchannelHandler |
HttpMessageHandler? |
null |
Custom HttpMessageHandler for mock testing or connection management. |
| Method | Return Type | Description |
|---|---|---|
WsdlExplorer.GenerateJsonRequestTemplateAsync(url, op) |
Task<string> |
Extracts sample JSON Request Body template for operation directly from WSDL URL. |
WsdlExplorer.GenerateJsonResponseTemplateAsync(url, op) |
Task<string> |
Extracts sample JSON Response Body template for operation directly from WSDL URL. |
wsdlDoc.GenerateJsonRequestTemplate(op) |
string |
Extracts sample JSON Request Body template for operation from parsed WsdlDocument. |
wsdlDoc.GenerateJsonResponseTemplate(op) |
string |
Extracts sample JSON Response Body template for operation from parsed WsdlDocument. |
wsdlDoc.GenerateAllJsonRequestTemplates() |
Dictionary<string, string> |
Extracts sample JSON Request Body templates for all operations in the WSDL. |
wsdlDoc.GenerateAllJsonResponseTemplates() |
Dictionary<string, string> |
Extracts sample JSON Response Body templates for all operations in the WSDL. |
| Fluent Method | Return Type | Description |
|---|---|---|
.With(string name, object? value) |
SoapOperationBuilder |
Adds a parameter to the SOAP request body. |
.WithDynamicParameters(IDictionary<string, object?> dict) |
SoapOperationBuilder |
Adds dynamic key-value parameters from a dictionary. |
.WithSerializerMode(SoapSerializerMode mode) |
SoapOperationBuilder |
Overrides serialization mode (StandardXml vs DataContract). |
.WithSpecifiedHandling(SpecifiedModeHandling handling) |
SoapOperationBuilder |
Overrides boolean *Specified property handling. |
.WithSuppressAutoChildrenXmlNamespace(bool suppress) |
SoapOperationBuilder |
Overrides child element namespace suppression switch. |
.WithChildElementName(string customChildName) |
SoapOperationBuilder |
Overrides root child element tag name. |
.WithSoapAction(string soapAction) |
SoapOperationBuilder |
Overrides HTTP SOAPAction header value. |
.WithSoapHeader(XElement element) |
SoapOperationBuilder |
Appends custom XML element into <soap:Header>. |
.WithSoapHeader(string name, object? value) |
SoapOperationBuilder |
Appends custom SOAP header in default target namespace. |
.WithSoapHeader(string name, string ns, object? value) |
SoapOperationBuilder |
Appends custom SOAP header in specified XML namespace. |
.WithHttpHeader(string name, string value) |
SoapOperationBuilder |
Adds custom HTTP header to this specific request. |
.WithAttachment(string contentId, byte[] data, ...) |
SoapOperationBuilder |
Adds MTOM/SwA attachment to the request. |
.WithBody(string rawXml) |
SoapOperationBuilder |
Overrides request SOAP body with raw XML string. |
.WithJson(string json) |
SoapOperationBuilder |
Adds body parameters from a JSON string. |
.ExecuteAsync(CancellationToken cancellationToken) |
Task<SoapResponse> |
Executes SOAP operation and returns SoapResponse. |
.ExecuteAsync<T>(CancellationToken cancellationToken) |
Task<T> |
Executes SOAP operation and deserializes directly to POCO T. |
.ExecuteAsync(Type type, CancellationToken cancellationToken) |
Task<object> |
Executes SOAP operation and deserializes directly to runtime Type. |
.ExecuteJsonAsync(CancellationToken cancellationToken) |
Task<string> |
Executes SOAP operation and returns response body as JSON string. |
.ExecuteDictionaryAsync(CancellationToken cancellationToken) |
Task<Dictionary<string, object?>> |
Executes SOAP operation and returns response body as dictionary. |
This project is licensed under the MIT License.