Answer
Catch the specific WebException type, rather than a generic Exception, and when it has a Response object attached, which it does for HTTP error status codes like 500, read that response's stream via a StreamReader to capture the full response body text — this is exactly where the detailed SOAP fault information lives, and a WebException's bare .Message property alone doesn't include it. Reading ex.Response.GetResponseStream() this way surfaces the same detailed fault content a dedicated SOAP testing tool shows directly.