SOAP FaultException returning empty response

I have a project in which I’m using ServiceStack in 2 capacities

  1. Restful webservice provider to which my asp.net mvc application will connect and interact
  2. SOAP services which are provided to 3rd party, in these I have to conform with their specification.

My problem is that after following the instructions at SOAP support (specifically “Convert SOAP Exceptions to SOAP Faults”) I get empty responses.

So I have the following definition

public GetXPriceResponse Any(GetXPrice request)

then I validate as such

List<ErrorCode> validationErrorCodes = new List<ErrorCode>();
        var result = _xBusinessService.GetXPrice(x, validationErrorCodes, logInfo);
        if (validationErrorCodes.Count > 0)
        {
            validationErrorCodes = validationErrorCodes.Distinct().ToList();
            validationErrorCodes.Sort(new ErrorCodeComparer());
        }

then if I find any validation errors, I try to raise an exception

var fault = new ApiFault
        {
            Status = "Fail",
            ErrorCode = validationErrorCodes.Select(vec => (int)vec.Id).ToArray(),
            ErrorDescription = validationErrorCodes.Select(vec => vec.Description).ToArray(),
        };
        string reason = validationErrorCodes.Count > 0 ? "Validation Errors Encountered" : "An Error Occured";
        throw new FaultException<ApiFault>(fault, reason);

I also have the following in AppHost (copy pasted from the mentioned url)

ServiceExceptionHandlers.Add((req, request, ex) =>
        {
            var requestMsg = req.GetItem("SoapMessage") as System.ServiceModel.Channels.Message;
            if (requestMsg != null)
            {
                var msgVersion = requestMsg.Version;
                using (var response = XmlWriter.Create(req.Response.OutputStream))
                {
                    var message = System.ServiceModel.Channels.Message.CreateMessage(
                        msgVersion, new FaultCode("Receiver"), ex.ToString(), null);
                    message.WriteMessage(response);
                }
                req.Response.End();
            }
            return null;
        });

with this setup, if I use SoapUI to query with a validation error, I get the following in the raw view

HTTP/1.1 200 OK
Cache-Control: private
Transfer-Encoding: chunked
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
Set-Cookie: ss-id=elrMfKcu5oQ9O9Skkv75; path=/; HttpOnly
Set-Cookie: ss-pid=05WeMGTJ6LEQwQz6gXxd; expires=Thu, 03-Dec-2037 10:53:41 GMT; path=/; HttpOnly
X-SourceFiles: =?UTF-8?B?QzpcRGV2XFZpc2l0b3JJbnN1cmFuY2VcVmlzaXRvckluc3VyYW5jZUFwcGxpY2F0aW9uXEFwcFdTXGFwaVxzb2FwMTE=?=
X-Powered-By: ASP.NET
Date: Sun, 03 Dec 2017 10:53:41 GMT

and if I remove it, I get the html for the usual exception page from aps.net as the response

How can I get the fault exceptions from ServiceStack using SOAP?
note that I have no control over the 3rd party codebase, I need to comply with their standards.

my expectation is to have something like this

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
    <s:Fault>
        <faultcode xmlns:a="http://schemas.microsoft.com/2009/WebFault">a:BadRequest</faultcode>
        <faultstring xml:lang="en-US">Bad Request</faultstring>
        <detail>
            <CCHIFaultContract xmlns="http://schemas.datacontract.org/2004/07/CCHIVisitVisa.Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                <FaultContracts>
                    <FaultContract>
                        <ErrorCode>113</ErrorCode>
                        <ErrorMessage>Gender must be 1 -&gt; Male, 2 -&gt; Female  </ErrorMessage>
                        <Type i:nil="true"/>
                    </FaultContract>
                    <FaultContract>
                        <ErrorCode>102</ErrorCode>
                        <ErrorMessage>Email format must be xx@xx.xx </ErrorMessage>
                        <Type i:nil="true"/>
                    </FaultContract>
                </FaultContracts>
            </CCHIFaultContract>
        </detail>
    </s:Fault>
</s:Body>
</s:Envelope>

ServiceStack isn’t a suitable choice if you need to “conform to a 3rd Party SOAP specification”, it’s output is not customizable or adaptable and only supports creating SOAP Services for WCF SOAP clients and generated proxies.

SOAP Faults are extremely fragile which is why the default behavior is to return a 200 OK with the Error Response populated in the ResponseStatus DTO as it fits into the expected WSDL Response Type Contract.

The Sample code to convert to a SOAP Fault shown only emits the Exception string not the structured error you’re after.

But to try and track down the issue with the fault response, can you put a debug breakpoint in the ServiceExceptionHandlers so you can see if it’s getting called. If it is being called, can you provide the full HTTP POST Response which includes the Response Body. You may need to use Fiddler or WireShark to view it if you can’t see it in SOAP UI.

Hi Mythz, great work with ServiceStack, really well structured.

I can confirm that “ServiceExceptionHandlers” works, and I used Fiddler as you suggested, here’s the raw output if I have “ServiceExceptionHandlers”.

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
Set-Cookie: ss-id=hgSL4mep46vugMaIKwwa; path=/; HttpOnly
Set-Cookie: ss-pid=J7y8ddCpbOfsRo5vcgjp; expires=Thu, 03-Dec-2037 20:49:02 GMT; path=/; HttpOnly
X-SourceFiles: =?UTF-8?B?QzpcZGV2XFZpc2l0b3JJbnN1cmFuY2VcVmlzaXRvckluc3VyYW5jZUFwcGxpY2F0aW9uXEFwcFdTXGFwaVxzb2FwMTE=?=
X-Powered-By: ASP.NET
Date: Sun, 03 Dec 2017 20:49:03 GMT
Content-Length: 0

So, I see now that it has no body, could it be because I’m throwing a fault instead of letting the exception cascade?
nope, I tried throwing a custom exception inheriting from HttpError, but it still shows content-length: 0

when it gets to the line

var message = System.ServiceModel.Channels.Message.CreateMessage(msgVersion, new FaultCode("Receiver"), ex.ToString(), null);

the value of ex.ToString() is “ServiceStack.HttpError: Failed to update the values” then the call stack.

is it possible for me to access the fields I put in the fault and write the body manually? or would you recommend I build separate WCF services for the necessary requests?

if I you recommend WCF, how would you suggest I structure my solution? (separate project? same project, just add WCF services? other?)

if I can write the body, do you have any suggestion? I know that servicestack.text has serialization for XML, so I’m sure it can help.

Thanks for looking into this :smile:

I would honestly ask your 3rd Party what SOAP framework they’d recommend as it will require a lot less effort to use a SOAP framework that naturally supports the specification they’re proposing, then it would be to try augment WCF to emit the exact wire format they want. They may also suggest using a SOAP Framework in another language, which if that’s not an option on your end I’d personally just be implementing this using raw ASP.NET IHttpHandler which will let you write the exact raw XML you need directly to the response.

ServiceStack.Text doesn’t have it’s own Xml Serializer, it just wraps .NET’s XML DataContractSerializer which if you’re lucky you’ll be able to use [DataContract] and [DataMember] attributes to get the exact wire format they want, but it’s quite limited in customizability and doesn’t support basic things like XML attributes for instance in which case you’d either need to use .NET’s more verbose but customizable XmlSerializer or hand-roll the raw XML output using a StringBuilder.

Not sure what the issue is on your end as I’ve added a custom SOAP Fault using the same approach in this commit which returns the expected SOAP Fault response.

Mythz,
after digging deeper, I found that the main issue was that “Content-Length” was not being set, and “Transfer-Encoding: chunked” was being sent
which together meant I didn’t receive any real content.

if you add the line “req.Response.UseBufferedStream = true;” then it works, and as you mentioned, the default response from servicestack is just the error message.

however, if you use a service runner or manually inject your code inside the ServiceExceptionHandlers, then you can return the wanted message.

I will add my code to my service runner since I already have it, and it makes more sense to have the logic there, but for completeness sake, I would recommend you change the code to the following (adding only one line)

ServiceExceptionHandlers.Add((req, request, ex) =>
        {
            var requestMsg = req.GetItem("SoapMessage") as System.ServiceModel.Channels.Message;
            if (requestMsg != null)
            {
                req.Response.UseBufferedStream = true;
                var msgVersion = requestMsg.Version;
                using (var response = XmlWriter.Create(req.Response.OutputStream))
                {
                    var message = System.ServiceModel.Channels.Message.CreateMessage(
                        msgVersion, new FaultCode("Receiver"), ex.ToString(), null);
                    message.WriteMessage(response);
                }
                req.Response.End();
            }
            return null;
        });

or at least mention it in case anybody runs into the same issue (or I run into it in the future again :wink: )

Thanks for the help

1 Like

Ok great, thx for the info, I’ve updated the SOAP Fault example in the docs.