Tuesday, September 27, 2011

SOAP Message validation in WCF

Well, after a bit more research it seems that Microsoft does support validating outgoing messages. It still doesn’t resolve the issues in my post (http://kenneth.gotcheese.co.za/post/Microsoft-cannot-stop-being-a-rebel.aspx) but does answer where Microsoft feels any validation should be done regarding SOAP. On one hand I agree with them but on the other I disagree. They allow for the INotify property if you enable data binding but they can’t enable the max length on field? Strange I know but I suppose they have their reasons!

 

Anyways, you are able to validate the outgoing message against the declaring XSD. Again this sounds fine but has a few issues, namely those around exposing the XSDs for public consumption. I suppose you could get round this via HTTP authentication but that means you have to push authentication backwards and forwards. The other option is to distribute the XSDs with the client proxies. I see that the Service Reference created in Visual Studio 2010 does exactly this (after rewriting your XSDs for you Smile).

 

To perform the validation you need to first create a client message inspector that implements the IClientMessageInspector.

 

Something like this:

public class MessageInspector : IClientMessageInspector


 



Once you have done that you need to implement the relevant methods (those that the interface declares).



 



The method we are going to focus on is the BeforeSendRequest method. In this method we will perform the validation using the XSD for the message. What you will need to do is check that the Message object is not a fault. If it is a fault return at this point. Next you want to get the Body of the Envelope. This can be achieved by calling GetReaderAtBodyContents()



var bodyReader = message.GetReaderAtBodyContents();


 



Next you going to need to get the XSD for your message. This might prove tricky if you have not got a naming convention that can be used to derive the name of the XSD. A way around this might be to load up the locations of the XSDs into a dictionary (perhaps even load all the XSD Schemas into that list so you can look it up via targetNamespace) but that I will leave to your imagination.



 



Once you have the body contents you open up the XSD file, load it into an XmlReader and read the XML document. If any errors occur, the callback method attached to the XmlReaderSettings.ValidationErrorHandler will be called.



 



First we configure the XmlReaderSettings:



var xsdPath = "pathtoyourfile.xsd;

using (var stream = File.OpenRead(xsdPath)) {

var schemaReader = XmlReader.Create(stream);

var readerSettings = new XmlReaderSettings
{
CloseInput = true,
Schemas = new XmlSchemaSet(),
ValidationFlags = XmlSchemaValidationFlags.None,
ValidationType = ValidationType.Schema
};


readerSettings.Schemas.Add("http://yournamespacehere.com", schemaReader);
readerSettings.Schemas.Compile();

//Attach to error event handler
readerSettings.ValidationEventHandler += new ValidationEventHandler(InspectionValidationHandler);
}


 



Then to validate the document you create an instance of a reader, attach the reader settings and read the document like so:



 



var wrappedReader = XmlReader.Create(bodyReader, readerSettings);

var startDepth = wrappedReader.Depth;

while (wrappedReader.Read())
{
if (wrappedReader.Depth == startDepth && wrappedReader.NodeType == XmlNodeType.EndElement)
{
break;
}
}


If there are any errors in the document they will be raised while reading and pushed to the callback handler.



 



For more information one solving this problem check out the references I found while solving it:



 



No comments:

Post a Comment