(RequestSoap| > CallTBCServiceAsync(PerformedActionSoapEnvelope performedActionSoapEnvelope)
{
const string url = "https://secdbi.tbconline.ge/dbi/dbiService";
@@ -137,7 +135,11 @@ async Task> CallTBCServiceAsync(PerformedActionSoapEnvelope perfo
}
catch (Exception)
{
- return Result.Failure(responseContent.FormatXml());
+ // Try to parse SOAP fault first, fallback to formatted XML
+ var faultParseResult = TryParseSoapFault(responseContent);
+ return Result.Failure(faultParseResult.IsSuccess
+ ? faultParseResult.Value.FormattedError
+ : responseContent.FormatXml());
}
X509Certificate2Collection GetCertificates()
@@ -147,4 +149,29 @@ X509Certificate2Collection GetCertificates()
return collection;
}
}
+
+ ///
+ /// Attempts to parse SOAP fault from response content
+ ///
+ static Result TryParseSoapFault(string responseContent)
+ {
+ try
+ {
+ var doc = new XmlDocument();
+ doc.LoadXml(responseContent);
+
+ var nsManager = new XmlNamespaceManager(doc.NameTable);
+ nsManager.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
+
+ var faultNode = doc.SelectSingleNode("//s:Fault", nsManager);
+ if (faultNode == null)
+ return Result.Failure("No SOAP fault found in response");
+
+ return faultNode.OuterXml.XmlDeserializeFromString();
+ }
+ catch (Exception ex)
+ {
+ return Result.Failure($"Failed to parse SOAP fault: {ex.Message}");
+ }
+ }
}
\ No newline at end of file
diff --git a/AppifySheets.TBC.IntegrationService.Tests/SoapFaultResponseTests.cs b/AppifySheets.TBC.IntegrationService.Tests/SoapFaultResponseTests.cs
new file mode 100644
index 0000000..1e7ba53
--- /dev/null
+++ b/AppifySheets.TBC.IntegrationService.Tests/SoapFaultResponseTests.cs
@@ -0,0 +1,91 @@
+using AppifySheets.TBC.IntegrationService.Client.SoapInfrastructure;
+using AppifySheets.TBC.IntegrationService.Client.TBC_Services;
+using CSharpFunctionalExtensions;
+using Shouldly;
+using Xunit;
+
+namespace AppifySheets.TBC.IntegrationService.Tests;
+
+public class SoapFaultResponseTests
+{
+ [Fact]
+ public void Should_Deserialize_SOAP_Fault_Response()
+ {
+ // Arrange
+ const string soapFaultXml = """
+
+
+
+
+
+ a:USER_IS_BLOCKED
+ User is blocked.
+
+
+
+ """;
+
+ // Act
+ var result = soapFaultXml.DeserializeInto();
+
+ // Assert - deserialization should fail with SOAP fault error message
+ result.IsFailure.ShouldBeTrue();
+ result.Error.ShouldContain("USER_IS_BLOCKED");
+ result.Error.ShouldContain("User is blocked");
+ }
+
+
+ [Fact]
+ public void Should_Create_SoapFaultResponse_With_Static_Factory()
+ {
+ // Act
+ var fault = SoapFaultResponse.Create("a:USER_IS_BLOCKED", "User is blocked.");
+
+ // Assert
+ fault.FaultCode.ShouldBe("a:USER_IS_BLOCKED");
+ fault.FaultString.ShouldBe("User is blocked.");
+ fault.FormattedError.ShouldBe("SOAP Fault [a:USER_IS_BLOCKED]: User is blocked.");
+ }
+
+ [Fact]
+ public void Should_Check_Fault_Code_Case_Insensitive()
+ {
+ // Arrange
+ var fault = SoapFaultResponse.Create("a:USER_IS_BLOCKED", "User is blocked.");
+
+ // Act & Assert
+ fault.IsFaultCode("a:user_is_blocked").ShouldBeTrue();
+ fault.IsFaultCode("A:USER_IS_BLOCKED").ShouldBeTrue();
+ fault.IsFaultCode("a:USER_IS_BLOCKED").ShouldBeTrue();
+ fault.IsFaultCode("different_code").ShouldBeFalse();
+ }
+
+ [Fact]
+ public void TryParseSoapFault_Should_Parse_Valid_Fault()
+ {
+ // Arrange
+ const string soapFaultXml = """
+
+
+
+
+
+ a:USER_IS_BLOCKED
+ User is blocked.
+
+
+
+ """;
+
+ // Act - use reflection to call the private static method
+ var method = typeof(TBCSoapCaller).GetMethod("TryParseSoapFault",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
+ var result = (Result)method!.Invoke(null, [soapFaultXml])!;
+
+ // Assert
+ result.IsSuccess.ShouldBeTrue();
+ result.Value.FaultCode.ShouldBe("a:USER_IS_BLOCKED");
+ result.Value.FaultString.ShouldBe("User is blocked.");
+ result.Value.FormattedError.ShouldBe("SOAP Fault [a:USER_IS_BLOCKED]: User is blocked.");
+ }
+}
\ No newline at end of file
diff --git a/PROJECTNAME b/PROJECTNAME
new file mode 100644
index 0000000..e7f6efc
--- /dev/null
+++ b/PROJECTNAME
@@ -0,0 +1 @@
+TBC-IntegrationService
\ No newline at end of file
diff --git a/README.md b/README.md
index 05a685a..c670d0c 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ dotnet add package AppifySheets.TBC.IntegrationService.Client
* Import Single Payment Orders - Execute various types of payment transfers
* Get Account Movements - Retrieve account transaction history
* Get Payment Order Status - Check status of submitted payment orders
-* Change Password - Change API user password
+* Change Password - Change API user password
## Usage Examples
diff --git a/VERSION b/VERSION
index 50aea0e..7c32728 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.1.0
\ No newline at end of file
+2.1.1
\ No newline at end of file
|