Abhijeet
Abhijeet

Reputation: 43

Catch Actual Error details from SOAP API in C#

Accessing SoapAPI in C# i have WSDL File Added as SeriviceRefrence in my c# classLinrery some how i am unable to catch actual Exception thrown by that API

I am getting ErrorMessage :-"An exception has been raised as a result of client data".

InnerException:-Null,

For Catching Actual Exception I tried below code:-

 public RegisterResponse1 RegisterAccount()
        {
            try
            {
                var upss = CreateAccessRequest();
                //Process Request
                var responce = regService.ProcessRegister(CreateRegisterWebServiceRequest(shipment));
                return responce;
            }
            catch (SoapException ex)
            {
                //I never go here
                return null;
            }
            catch (FaultException ex)
            {
                //always go there
                return null;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

In Above exception handling i always fouling to FaultException (ex) the above errorMessaeg from FaultException

When i try to request this API from SoapUI(readyAPI) tool manually i got below Error details which is actual error from API side that error I want in my c# Library See the below actual ERROR DETAILS enter image description here

"Invalid access License Number" is Actual Message that i want to fetch

Please help me to catch that Actual Error Details "Invalid access License Number" in c# instead error-exception has been raised as a result of client data

Thank you in Advance

Upvotes: 2

Views: 3543

Answers (2)

Junior Grão
Junior Grão

Reputation: 1671

In my case the real error description was:

Hard9264030The state is not supported in the Customer Integration Environment.

I realized that just NY and CA states in US are valid using my current sandbox credentials. So I suggest you change the code this way to check which error show up for you.

public RegisterResponse1 RegisterAccount()
{
    try
    {
        var upss = CreateAccessRequest();
        //Process Request
        var responce = regService.ProcessRegister(CreateRegisterWebServiceRequest(shipment));
        return responce;
    }
    catch (SoapException ex)
    {
        //=====================================================================
        //put this code here and you will see the correct description of the error
        var error = ex.Detail.InnerText;
        Console.WriteLine(error);
        return null;
    }
    catch (FaultException ex)
    {
        //always go there
        return null;
    }
    catch (Exception ex)
    {
        return null;
    }
}

Upvotes: 2

Zackary Geers
Zackary Geers

Reputation: 360

Yes, I fought this issue for quite a while on my own project, and finally found the solution. The WSDL generator has a problem where it mis-generates the fault object, which is why you can't access it.

To diagnose what's going on under the covers, you can use a tool like Fiddler, and monitor the traffic. UPS is returning a fault detail that has a message that will tell you what's wrong, but you can't see it because of the badly generated object.

To fix this problem in any of the UPS APIs, go into the generated Reference.cs, and just after the namespace declaration, add this class:

// The WSDL generator doesn't properly generate the Errors Class.  This was taken from the UPS Samples.  The FaultContractAttribute was also updated to use this class instead.
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.7.2612.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1")]
public partial class Errors : object, System.ComponentModel.INotifyPropertyChanged
{

    private ErrorDetailType[] errorDetailField;

    private string testElementField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("ErrorDetail", Order = 0)]
    public ErrorDetailType[] ErrorDetail
    {
        get
        {
            return this.errorDetailField;
        }
        set
        {
            this.errorDetailField = value;
            this.RaisePropertyChanged("ErrorDetail");
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order = 1)]
    public string TestElement
    {
        get
        {
            return this.testElementField;
        }
        set
        {
            this.testElementField = value;
            this.RaisePropertyChanged("TestElement");
        }
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if ((propertyChanged != null))
        {
            propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }
    }
}

Then search in the file for for FaultContractAttribute. Change it to:

[System.ServiceModel.FaultContractAttribute(typeof(Errors), Action="http://onlinetools.ups.com/webservices/ShipBinding/v1.1", Name="Errors", Namespace="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1")]

You may need to adjust the namespace in the typeof() statement.

Then a block like this will catch/return the error messages:

        catch (FaultException<Errors> ex)
        {
            return new MyResult
            {
                ErrorMessage =
                    $"UPS returned the following errors: {string.Join(", ", ex.Detail.ErrorDetail.Select(ed => ed.PrimaryErrorCode.Description))}"
            };
        }

That will give you the full error from the UPS API call, and you can read the API docs from there to know what's wrong.

Upvotes: 6

Related Questions