Before I was given the wsdl for a web service, I had already generated the xml using SQL and FOR XML PATH.
Now I have the wsdl, should I go back and populate each object individually from SQL, should I deserialise my XML into the request object (if that is possible) or is there another choice? Any gotchas you can warn me about in advance?
As far as I can tell if you are posting a complicated xml structure from a SQL database to a WCF web service then there is no harm in creating the whole xml document using FOR XML PATH - in fact I would say it was better and simpler. You can then manually validate it against the xsd (which WILL validate against xsd:restrictions, minOccurs, maxOcurs etc) and then deserialise it into the complex object hierarchy created by the WSDL. Note that the WSDL does not do any validations (xsd:restrictions, minOccurs, maxOccurs are not validated on the client side) - it just creates the object hierarchy.
This assumes you are comfortable with SQL and XML PATH of course! Otherwise you can build the object hierarchy up in code, but you won't have any validation until you call the real web service.
The xsd validation is a belt and braces backup to avoid sending invalid data to the web service. Clearly, in the real world, whatever data you are sending should be validated properly with user friendly error messages.
Here's some sample code:
Imports System.Xml
Imports System.Xml.Schema
Imports System.Data.SqlClient
Imports System.Xml.Serialization
Imports ClassLibrary1.ServiceReferences.ClientX
Imports System.IO
Imports System.Configuration
Public Class ClientXWebServices
Private _isValid As Boolean?
Private _xmlErrorList As New List(Of String)
Private _xmlWarningList As New List(Of String)
Sub New()
End Sub
Function Send(id As Guid) As StoreData.storeDataResponse
Dim xdoc As XmlDocument = New XmlDocument()
Using cnn As New SqlConnection(ConfigurationManager.ConnectionStrings("ConnectionString").ConnectionString())
cnn.Open()
Dim cmd = New SqlCommand("employer.clientx_xml_setup_select", cnn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("@id", id)
Using reader = cmd.ExecuteXmlReader
If (reader.Read()) Then
xdoc.Load(reader)
End If
End Using
End Using
'Validate (belt and braces)
Dim myschema As XmlSchema
Using reader As XmlTextReader = New XmlTextReader("storeData.xsd")
myschema = XmlSchema.Read(reader, Nothing)
End Using
xdoc.Schemas.Add(myschema)
xdoc.Validate(AddressOf DocumentValidationCallback)
If Not _isValid.HasValue Then
_isValid = True
End If
If _isValid = False Then
MsgBox(String.Join(vbCrLf, _xmlErrorList.Union(_xmlWarningList).ToArray))
Return Nothing
End If
Dim xmlSer As XmlSerializer = New XmlSerializer(GetType(StoreData.storeDataRequest))
Dim ssdr As StoreData.storeDataRequest = xmlSer.Deserialize(New StringReader(xdoc.OuterXml))
Dim client As New StoreData.StoreDataClient
Dim response As StoreData.storeDataResponse
Try
response = client.ServiceReferences_CLIENTX_StoreData_StoreData_storeData(ssdr)
Catch ex As Exception
Throw New IOException("ClientX Web Service 'StoreData' could not be contacted.", ex)
End Try
Return response
End Function
Sub DocumentValidationCallback(ByVal sender As Object, ByVal args As ValidationEventArgs)
If args.Severity = XmlSeverityType.Warning Then
_xmlErrorList.Add(args.Message)
ElseIf args.Severity = XmlSeverityType.Error Then
_xmlWarningList.Add(args.Message)
End If
_isValid = False
End Sub
End Class