Thursday, February 17, 2011

Handling WCF Faults in .NET 2.0 client applications

WCF handles errors and convey these details to the client using Fault contracts. SOAP fault messages are included in the metadata for an operation contract and when the exception is raised in these methods create a fault for the clients to get more details about the exceptions. But when you have a client that runs on 2.0 version of .NET framework, they can't make use of these fault contracts. In this case you need to send your faults as SOAP exceptions as in Web services.
For e.g.
public void MyServiceMethod()
{
    try
    {
//Application Logic
    }
    catch (System.Security.SecurityException securityException)
    {
        throw GenerateSoapException("ServiceMethodName", "YourNamespace", securityException.Message, "1000", securityException.Source, ServiceFaultLocation.FromServerCode);
    }
}

private SoapException GenerateSoapException(string uri,
                            string serviceNamespace,
                            string message,
                            string errNum,
                            string source,
                            ServiceFaultLocation faultLocation)
{
    XmlQualifiedName faultCodeLocation = SetFaultCode(faultLocation);

    XmlDocument xmlDoc = new XmlDocument();
    XmlNode rootNode = CreateExceptionNode(serviceNamespace, message, errNum, source, xmlDoc);
    SoapException soapException = new SoapException(message, faultCodeLocation, uri, rootNode);
    return soapException;
}

private XmlNode CreateExceptionNode(string serviceNamespace, string message, string errNum, string source, XmlDocument xmlDoc)
{
    XmlNode rootNode = xmlDoc.CreateNode(XmlNodeType.Element, SoapException.DetailElementName.Name, SoapException.DetailElementName.Namespace);
    XmlNode errorNode = PopulateErrorDetails(serviceNamespace, message, errNum, source, xmlDoc);

    rootNode.AppendChild(errorNode);
    return rootNode;
}

private XmlNode PopulateErrorDetails(string serviceNamespace, string message, string errNum, string source, XmlDocument xmlDoc)
{
    XmlNode errorNode = xmlDoc.CreateNode(XmlNodeType.Element, "Error", serviceNamespace);
    XmlNode errorNumberNode = xmlDoc.CreateNode(XmlNodeType.Element, "ErrorNumber", serviceNamespace);
    errorNumberNode.InnerText = errNum;
    XmlNode errorMessageNode = xmlDoc.CreateNode(XmlNodeType.Element, "ErrorMessage", serviceNamespace);
    errorMessageNode.InnerText = message;
    XmlNode errorSourceNode = xmlDoc.CreateNode(XmlNodeType.Element, "ErrorSource", serviceNamespace);
    errorSourceNode.InnerText = source;
    errorNode.AppendChild(errorNumberNode);
    errorNode.AppendChild(errorMessageNode);
    errorNode.AppendChild(errorSourceNode);
    return errorNode;
}

private XmlQualifiedName SetFaultCode(ServiceFaultLocation code)
{
    XmlQualifiedName faultCodeLocation = null;
    switch (code)
    {
        case ServiceFaultLocation.FromClientCode:
            faultCodeLocation = SoapException.ClientFaultCode;
            break;
        case ServiceFaultLocation.FromServerCode:
            faultCodeLocation = SoapException.ServerFaultCode;
            break;
    }
    return faultCodeLocation;
}

Later in your client you can use this SOAP exception and parse the XML message to get the details of the exception.

No comments: