What is the best way to return WCF arguement exceptions with Exception Shielding

Topics: Exception Handling Application Block
Jan 19, 2011 at 6:01 PM
Edited Jan 19, 2011 at 8:41 PM

Is there an example of the best way to return a list of Name/Value pairs for method argument validations that fail. I want to shield sensitive information, such as the stack trace, and am thinking that extended properties might be helpful here. In the WCF boundary, this exception needs to be past as is, but with the stack trace information removed.

Something like:

private static void ValidateEmpMedAuthDetail(EmpMedAuthDetail rqst)
{
    var ex = new ArgumentException("EmpMedAuthDetail Invalid Arguement[s]");

    if (rqst.CAID == 0)
        ex.Data.Add("CAID", "Invalid CAID");
    if (string.IsNullOrEmpty(rqst.PatientLastName))
        ex.Data.Add("PatientLastName" , "Patient last name required");
    if (string.IsNullOrEmpty(rqst.PatientFirstName))
        ex.Data.Add("PatientFirstName" , "Patient first name required");
    if (rqst.InjuredBodyParts == null || rqst.InjuredBodyParts.Count == 0 || string.IsNullOrEmpty(rqst.InjuredBodyParts[0].BodyPartInjured))
        ex.Data.Add("BodyPartInjured" , "Injured body part required");
    if (rqst.InjuredBodyParts == null || rqst.InjuredBodyParts.Count == 0 || string.IsNullOrEmpty(rqst.InjuredBodyParts[0].BodyPartSide))
        ex.Data.Add("BodyPartSide" , "Body part side required");
    if (rqst.InjuryDateTime > DateTime.Now)
        ex.Data.Add("InjuryDateTime" , "Injury Date Cannot be in the Future");
    if (string.IsNullOrEmpty(rqst.JurisdictionState))
        ex.Data.Add("JurisdictionState" , "Jurisdiction State required");

    if (ex.Data.Count > 0)
        throw ex;
}

Should this be replaced as an unhandled exception process at the WCF service boundary as opposed to using a Fault Contract Exception Handler (which will be used for other exception types)?

What I am getting now is the OPPOSITE of what I want. If I intentionally throw the above error in a WCF test by calling the test service from a web page, the above ArguementException fault shows the stack trace, but NOT the extended data.

 

Jan 20, 2011 at 9:28 AM

You can utilize your Fault Contract Exception Handler's Propoerty Mappings.

The Name property of a mapping refers to a property name on the Fault Contract. The Source property of a mapping specifies the name of the property on the original exception from which the value should be retrieved. Therefore in your config you can have something like this;

<mappings>
 <add source="Data" name="FaultData" />
</mappings>

In your FaultContract;

        [DataMember]
        public IDictionary FaultData { get; set; }

Hope this helps.

Gino Terrado
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jan 22, 2011 at 4:05 PM
Edited Jan 22, 2011 at 10:19 PM

I tried your example, but it doesn't seem to be working for some reason. My test fault contract is:

 namespace Domain.Entities
{
    [DataContract]
    public class ServiceFault
    {
        [DataMember]
        public Guid FaultID { get; set; }

        [DataMember]
        public string FaultMessage { get; set; }

        [DataMember]
        public IDictionary FaultData { get; set; }
    }
}

Throwing the following ArgumentException when sending a new, unpopulated MedAuth record:

        private static void ValidateEmpMedAuthDetail(EmpMedAuthDetail  rqst)
        {
            var errormsg = new StringBuilder();

            if (rqst.CAID == 0)
                errormsg.Append("CAID:Invalid CAID|");
            if (string.IsNullOrEmpty(rqst.PatientLastName))
                errormsg.Append("PatientLastName:Patient last name required|");
            if (string.IsNullOrEmpty(rqst.PatientFirstName))
                errormsg.Append("PatientFirstName:Patient first name required|");
            if (rqst.InjuredBodyParts == null || rqst.InjuredBodyParts.Count == 0 || string.IsNullOrEmpty(rqst.InjuredBodyParts[0].BodyPartInjured))
                errormsg.Append("BodyPartInjured:Injured body part required|");
            if (rqst.InjuredBodyParts == null || rqst.InjuredBodyParts.Count == 0 || string.IsNullOrEmpty(rqst.InjuredBodyParts[0].BodyPartSide))
                errormsg.Append("BodyPartSide:Body part side required|");
            if (rqst.InjuryDateTime > DateTime.Now)
                errormsg.Append("InjuryDateTime:Injury Date Cannot be in the Future|");
            if (string.IsNullOrEmpty(rqst.JurisdictionState))
                errormsg.Append("JurisdictionState:Jurisdiction State required|");

            if (errormsg.Length > 0)
            {
                errormsg.Insert(0, "EmpMedAuthDetail Invalid Arguement[s] -- Values=|");
                throw new ArgumentException(errormsg.ToString());
            }
        }
And getting the following in the FaultContract at the WCF boundary:
<Fault>
   <Code>
      <Value>Sender</Value>
      <Subcode>
         <Value>Sender</Value>
      </Subcode>
   </Code>
   <Reason>
      <Text xml:lang="en-US">Invalid arguments.</Text>
   </Reason>
   <Detail>
      <ServiceFault>
         <FaultData i:nil="true"/>
         <FaultID>00000000-0000-0000-0000-000000000000</FaultID>
         <FaultMessage i:nil="true"/>
      </ServiceFault>
   </Detail>
</Fault>



 

 

Jan 24, 2011 at 7:34 AM

The more recent code you posted shows that you didn't add the details in the .Data property, you basically used those details as value for the Message property of the exception.  If you follow the first code you posted, it should work.

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com