views:

1590

answers:

3

I'm writing a WCF service for the first time. The service and all of its clients (at least for now) are written in C#. The service has to do a lot of input validation on the data it gets passed, so I need to have some way to indicate invalid data back to the client. I've been reading a lot about faults and exceptions, wrapping exceptions in faults, and a lot of conflicting articles that are just confusing me further. What is the proper way to handle this case?

Should I avoid exceptions altogether and package a Results return message? Should I create a special Fault, or a special Exception, or just throw ArgumentExceptions like I would for a non-WCF validation function?

The code I have right now (influenced by MSDN) is:

[DataContract]
public class ValidationFault
{
    [DataMember]
    public Dictionary<string, string> Errors { get; private set; }

    [DataMember]
    public bool Fatal { get; private set; }

    [DataMember]
    public Guid SeriesIdentifier { get; private set; }

    public ValidationFault(Guid id, string argument, string error, bool fatal)
    {
        SeriesIdentifier = id;
        Errors = new Dictionary<string, string> {{argument, error}};
        Fatal = fatal;
    }

    public void AddError(string argument, string error, bool fatal)
    {
        Errors.Add(argument, error);
        Fatal |= fatal;
    }
}

And on the method there's [FaultContract(typeof(ValidationFault))]. So is this the "right" way to approach this?

+2  A: 

If you are doing validation on the client and should have valid values once they are passed into the method (the web service call) then I would throw an exception. It could be an exception indicating that a parameters is invalid with the name of the parameter. (see: ArgumentException)

But you may not want to rely on the client to properly validate the data and that leaves you with the assumption that data could be invalid coming into the web service. In that case it is not truly an exceptional case and should not be an exception. In that case you could return an enum or a Result object that has a Status property set to an enum (OK, Invalid, Incomplete) and a Message property set with specifics, like the name of the parameter.

I would ensure that these sorts of errors are found and fixed during development. Your QA process should carefully test valid and invalid uses of the client and you do not want to relay these technical messages back to the client. What you want to do instead is update your validation system to prevent invalid data from getting to the service call.

My assumption for any WCF service is that there will be more than one UI. One could be a web UI now, but later I may add another using WinForms, WinCE or even a native iPhone/Android mobile application that does not conform to what you expect from .NET clients.

Brennan
A: 

you might want to take a look at the MS Patterns and Practices Enterprise Library Validation block in conjunction with the policy injection block link text it allows you to decorate your data contract members with validation attributes and also decorate the service implementation, this together with its integration with WCF this means that failures in validation are returned as ArgumentValidationException faults automatically each containing a ValidationDetail object for each validation failure.

Using the entlib with WCf you can get a lot of validation, error reporting without having to write much code

Richard
+2  A: 

Throwing an exception is not useful from a WCF service Why not? Because it comes back as a bare fault and you need to

a) Set the fault to include exceptions

b) Parse the fault to get the text of the exception and see what happened.

So yes you need a fault rather than an exception. I would, in your case, create a custom fault which contains a list of the fields that failed the validation as part of the fault contract.

Note that WCF does fun things with dictionaries, which aren't ISerializable; it has special handling, so check the message coming back looks good over the wire; if not it's back to arrays for you.

blowdart