Validating Schemas in WebMethods using Attributes#
One of the most annoying things in BizTalk is when an error is generated in a Receive Pipeline indicating that a message has been suspended because of the content of the message doesn't validate against the given schema (for the moment, we'll gloss over the fact that in an ideal situation this should only ever happen during testing).

Using BizTalk 2006's new Failed Message Routing feature, it's fairly simple to write something which can deal with this situation (using either an Orchestration or SendPort subscribing to the Error Report).
Returning a message back to a Web Service caller indicating that there is something wrong with their message, is non-trivial – it's possible, but requires some in-depth knowledge of how instance subscriptions work.

However, there is an easier way: validating the message at the endpoint (i.e. inside the Web Service itself).
Aaron Skonnard and Dan Sullivan wrote an article for MSDN magazine in July 2003 on how to implement attribute based schema validation for Web Method parameters.

It's a great idea: decorate a Web Method with an attribute, and when the web method is called then any messages received will be validated against their schemas – if they don't validate, then a SOAP Fault is returned back to the caller.

Looking through the code, I realised that with a few modifications it could work for my situation.

The main issue with the code as it was is that, by default, it would validate incoming XML messages against the XSD contained in the WSDL.

If you're using the BizTalk Web Services Publishing Wizard, you're probably letting the tool do all the code generation for you. This also means that you're probably letting the .NET Framework look after generating your WSDL for you.

There's a problem with auto-generation (as an aside, auto-generation might make your life easier, but it can cause all sorts of problems if you're not aware of how it works, and what "default scenarios" it assumes).

Here's what most people would do:
  • Create a schema in BizTalk in represent a message.
  • Use the Web Services Publishing Wizard to create a Web Service which can accept message using this schema.
    During this process, the wizard will use the xsd.exe tool to auto-generate a class (usually a C# class) which represents the XSD.
  • A caller then requests the WSDL for the web service – and the auto-generated class is converted into an XSD for inclusion in the WSDL.
However, a C# class can't fully represent an XML schema (and vice versa). Anyone who's worked with complex (real-world) schemas will have realized this.

One area where the whole thing falls over is when we put restrictions on attributes or elements.

For example, suppose we an attribute called "name" which we wanted to restrict to being between 1 and 20 chars long:
    <xs:attribute name="name" use="required">
        <xs:simpleType>
            <xs:restriction base="xs:string">
                <xs:maxLength value="20" />
                <xs:minLength value="1" />
            </xs:restriction>
        </xs:simpleType>
    </xs:attribute>


When this schema gets "converted" into a class representation, we get the following for the attribute
    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string name {
        get {
            return this.nameField;
        }
        set {
            this.nameField = value;
        }
    }


And then when this class gets converted back to XSD again, we get this:
    <xs:attribute name="name" type="xs:string" />

All the restrictions have disappeared!
That's because they're not supported by the xsd.exe tool (or, more specifically, by the internal classes used by xsd.exe to do the heavy lifting).

So that's the problem with using the default SchemaValidator code: because it validates incoming messages against the schemas in the WSDL, then unless you have manually created your WSDL, the schemas in your WSDL will not be same as the original schemas you created.

The solution is simple: validate the incoming messages against the original schemas.
And it just so happens that when you use the Web Services Publishing Wizard all the original schemas are copied into the web service folder, in a sub folder called xsd.
What's more, the original SchemaValidator code supports looking for schemas in a folder called xsd – however, it simply has these take a backseat to the ones in the WSDL.
Note: another solution is to handcraft your WSDL and put the original schemas in there yourself – in fact, this is what everyone should do IMHO.

So the modifications I made to the original code are simple:
  1. Change the order for searching for schemas to being the xsd folder first, then the WSDL
  2. Added a schema-namespace check - if the schema has already been loaded, then we don't attempt to load it again
All the changes I made are in a single class: ValidationExtension.cs

How to use
Compile the solution, and then either copy the SchemaValidation.dll assembly into your web service's bin folder, or give the assembly a strong name and put it in the GAC.

Then, update the web.config file for your web service as per the example given in the solution:

    <soapExtensionReflectorTypes>
        <!-- add type="$SoapExtensionReflectorType.FullName$, $AssemblyName.Name$" /-->
        <add type="SchemaValidation.ValidationExtensionReflector, SchemaValidation, Version=1.0.0.0"/>
    </soapExtensionReflectorTypes>
    <serviceDescriptionFormatExtensionTypes>
        <add type="SchemaValidation.ValidationFormatExtension, SchemaValidation, Version=1.0.0.0"/>
    </serviceDescriptionFormatExtensionTypes>


Finally, open the code-behind file for your web service and do the following:

•    add a using SchemaValidation; statement at the top
•    Add a [Validation] attribute to all web methods where incoming messages should be validated

e.g.
    [WebMethod]
    [Validation]
    public string Test(MyType bp) {


Now if you call the web method with a message which doesn't validate against the schema, you'll get a SOAP Fault similar to this:

<?xml version="1.0" encoding="utf-16"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <soap:Fault>
      <faultcode>soap:Client</faultcode>
      <faultstring>System.Web.Services.Protocols.SoapException: Incoming message failed validation: Error: The 'name' attribute is invalid - The value '' is invalid according to its datatype 'String' - The actual length is not equal to the specified length.
   at SchemaValidation.ValidationExtension.xrs_ValidationEventHandler(Object sender, ValidationEventArgs e)


The code for this solution can be downloaded from here:
SchemaValidation.zip (21.99 KB)

If you have any issues with it, let me know.

Sunday, April 15, 2007 5:44:54 PM (GMT Daylight Time, UTC+01:00) #    Comments [1]  |  Trackback Tracked by:
"How to validate Xml Documents against schemas in BizTalk" (BizBert) [Trackback]
"http://morningside.edu/mics/_notes/pages/melatonin/index.html" (http://mornings... [Pingback]
"http://blastpr.com/wiki/js/pages/prilosec/index.html" (http://blastpr.com/wiki/... [Pingback]
"http://morningside.edu/mics/_notes/pages/celexa/index.html" (http://morningside... [Pingback]
"http://blastpr.com/wiki/js/pages/soma/index.html" (http://blastpr.com/wiki/js/p... [Pingback]
"http://morningside.edu/mics/_notes/pages/accutane/index.html" (http://morningsi... [Pingback]
"http://morningside.edu/mics/_notes/pages/hoodia/index.html" (http://morningside... [Pingback]
"http://blastpr.com/wiki/js/pages/wellbutrin/index.html" (http://blastpr.com/wik... [Pingback]
"http://morningside.edu/mics/_notes/pages/rainbow-brite/index.html" (http://morn... [Pingback]
"http://morningside.edu/mics/_notes/pages/ultram/index.html" (http://morningside... [Pingback]
"http://blastpr.com/wiki/js/pages/celebrex/index.html" (http://blastpr.com/wiki/... [Pingback]
"http://morningside.edu/mics/_notes/pages/synthroid/index.html" (http://mornings... [Pingback]
"http://blastpr.com/wiki/js/pages/synthroid/index.html" (http://blastpr.com/wiki... [Pingback]
"http://morningside.edu/mics/_notes/pages/cialis/index.html" (http://morningside... [Pingback]
"http://morningside.edu/mics/_notes/pages/wellbutrin/index.html" (http://morning... [Pingback]
"http://morningside.edu/mics/_notes/pages/cymbalta/index.html" (http://morningsi... [Pingback]
"http://morningside.edu/mics/_notes/pages/paxil/index.html" (http://morningside.... [Pingback]
"http://blastpr.com/wiki/js/pages/cymbalta/index.html" (http://blastpr.com/wiki/... [Pingback]
"http://morningside.edu/mics/_notes/pages/soma/index.html" (http://morningside.e... [Pingback]
"http://blastpr.com/wiki/js/pages/coumadin/index.html" (http://blastpr.com/wiki/... [Pingback]
"http://blastpr.com/wiki/js/pages/paxil/index.html" (http://blastpr.com/wiki/js/... [Pingback]
"http://morningside.edu/mics/_notes/pages/effexor/index.html" (http://morningsid... [Pingback]
"http://blastpr.com/wiki/js/pages/clomid/index.html" (http://blastpr.com/wiki/js... [Pingback]
"http://morningside.edu/mics/_notes/pages/tramadol/index.html" (http://morningsi... [Pingback]
"http://blastpr.com/wiki/js/pages/nexium/index.html" (http://blastpr.com/wiki/js... [Pingback]
"http://blastpr.com/wiki/js/pages/celexa/index.html" (http://blastpr.com/wiki/js... [Pingback]
"http://blastpr.com/wiki/js/pages/rainbow-brite/index.html" (http://blastpr.com/... [Pingback]
"http://morningside.edu/mics/_notes/pages/nexium/index.html" (http://morningside... [Pingback]

 

All content © 2020, Daniel Probert
On this page
This site
Calendar
<August 2020>
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
303112345
Archives
Sitemap
Blogroll OPML
Disclaimer

Powered by: newtelligence dasBlog 2.3.12105.0

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Send mail to the author(s) E-mail

Theme design by Jelle Druyts


Pick a theme: