How to validate XML with generated c# class from XSD - c#

I want to send a http request from client to local server and on the server I made a query with Linq that returns data in xml
I also have .xsd file and a .cs file enerated from my xsd file that I want to validate my xml with.
I have several questions:
how can I validate xml with c# generated class?
how can I return xml from server to client?
http://www.codeproject.com/Questions/898525/How-to-validate-XML-with-generated-csharp-class-fr
Thanks

Well, I see two separate questions, so I'll provide two separate answers:
1.) How can I validate XML [with a C# generated class]
The answer actually doesn't involve the C# generated class at all. Once you've validated the XML, you can deserialize it into your autogenerated class; however, validating XML against a schema doesn't require it. To validate XML against a known schema (assuming you have a XSD file), you can do the following:
// define your schema set by importing your schema from an xsd file
var schemaSet = new XmlSchemaSet();
var schema = XmlReader.Create("D:\myschema.xsd");
schemaSet.Add(null, schema);
schemaSet.Compile();
// your schema defines several types. Your incoming XML is (presumably) expected to of one of these types (e.g. type="_flashList")
// whatever the expected type is of the XML document root, use that string here to grab information about that type from the schema
var partialSchemaObject = schemaSet.GlobalTypes[new XmlQualifiedName("_flashList")];
// go get your xml, then validate!
// here, SchemaValidationEventHandler is a delegate that is called for every validation error or warning
var myXml = GoGetMyXmlIWantToValidate() as XDocument;
myXml.Root.Validate(partialSchemaObject, schemaSet, SchemaValidationEventHandler, true);
2.) How can I return XML from server to client?
You can use the 'StringContent' type for your HttpContent
var myResponseXml = GoGetMyResponseXml() as XElement;
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
// specify string content, with UTF8 encoding, with a content-type of application/xml
Content = new StringContent(myResponseXml.ToString(), Encoding.UTF8, "application/xml");
};

Related

C# SOAP client: sending generic XmlNode request

I have a C# project where I added a SOAP service reference, using the integrated visual studio functionality (right click -> add -> service reference)
The client classes are generated correctly without errors. However, the various methods of the service only accept a generic System.Xml.XmlNode as an input, rather than a structured object.
This should not be a problem in theory, since I have the complete XML file with the query that I need to perform. So I tried doing it like this:
NSIStdV20ServiceSoapClient client = new NSIStdV20ServiceSoapClient();
var getAllDataFlowQuery = File.ReadAllText(#"Query\get_all_dataflow.xml"); //file containing the query
XmlDocument doc = new XmlDocument();
doc.LoadXml(getAllDataFlowQuery);
var dataStructures = client.QueryStructure(doc); //this method accepts a System.Xml.XmlNode as parameter
However, this doesn't work, throwing
System.ServiceModel.FaultException: 'Error due to a non correct client message'
I thought initially that the query was incorrect, but I tried to perform the exact same query using SoapUI and it works perfectly! I even tried doing it with the exact XML returned by doc.InnerXml (just to be sure che XmlDocument object was not modifying the XML) and it works.
So basically it's only when calling the method from C# that it doesn't work.
If you want to try it out yourself, the service is freely accessible, the WSDL is here:
http://sdmx.istat.it/SDMXWS/NsiStdV20Service.asmx?WSDL
and you should try to call the QueryStructure method with the following payload:
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://ec.europa.eu/eurostat/sri/service/2.0"><soapenv:Header /><soapenv:Body><web:QueryStructure><!--Optional:--><web:Query><RegistryInterface xsi:schemaLocation="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message SDMXMessage.xsd" xmlns="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message" xmlns:common="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/common" xmlns:compact="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/compact" xmlns:cross="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/cross" xmlns:generic="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/generic" xmlns:query="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/query" xmlns:structure="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure" xmlns:registry="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/registry" xmlns:utility="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/utility" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Header><ID>JD014</ID><Test>true</Test><Truncated>false</Truncated><Name xml:lang="en">Trans46302</Name><Prepared>2001-03-11T09:30:47-05:00</Prepared><Sender id="BIS" /></Header><QueryStructureRequest resolveReferences="false"><registry:DataflowRef /></QueryStructureRequest></RegistryInterface></web:Query></web:QueryStructure></soapenv:Body></soapenv:Envelope>
As I said, this works perfectly in SoapUI, but doesn't work when calling the client method from C#
Well, it seems that the client generated by visual studio, even tho it accepts a XmlNode as input, creates some of the required outer structure itself (to be precise: all the outer nodes with the soapenv and web namespaces).
Which means I had to strip down the input XML to:
<?xml version="1.0" encoding="UTF-8"?><RegistryInterface xsi:schemaLocation="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message SDMXMessage.xsd" xmlns="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/message" xmlns:common="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/common" xmlns:compact="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/compact" xmlns:cross="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/cross" xmlns:generic="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/generic" xmlns:query="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/query" xmlns:structure="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/structure" xmlns:registry="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/registry" xmlns:utility="http://www.SDMX.org/resources/SDMXML/schemas/v2_0/utility" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><Header><ID>JD014</ID><Test>true</Test><Truncated>false</Truncated><Name xml:lang="en">Trans46302</Name><Prepared>2001-03-11T09:30:47-05:00</Prepared><Sender id="BIS" /></Header><QueryStructureRequest resolveReferences="false"><registry:DataflowRef /></QueryStructureRequest></RegistryInterface>

Envelop tag missing in xml object

I have a web application where the users can upload a specific XML file, then i need to convert the XML file to a object which is expect in a webservice.
Code:
var document = new XmlDocument();
document.Load(#"C:\Desktop\CteWebservice.xml");
var serializer =new XmlSerializer(typeof(OCTE));
var octe = (OCTE)serializer.Deserialize(new StringReader(document.OuterXml));
var serviceClient = new WSServiceClient();
serviceClient.InsertOCTE(octe);
I get this error when i try to deserialize the xml document as a OCTE object:
< Envelope xmlns='http://schemas.xmlsoap.org/soap/envelope/'> was not expect.
Obvious, the OCTE class doesn't have a Envelope property.
My question is, i need to include this tag in the OCTE class or i need to do something else in the client?
I can think of at least two different solutions to your problem, which seems to be caused by the fact that the XML file contain the full SOAP request, which will contain a SOAP Envelope, a SOAP Body element and potentially a SOAP header element.
The structure of SOAP body element is dependent on the SOAP Binding style, which most likely will be Document Literal Wrapped - for further details look at http://www.ibm.com/developerworks/webservices/library/ws-usagewsdl/index.html?ca=dat-
This means that the OCTE structure that you are looking for, might be embedded inside a request element, something like (document literal wrapped SOAP binding style)
<soap:envelope>
</soap:header>
<soap:body>
<insertOCTERequest>
<OCTE>
...
</OCTE>
</insertOCTERequest>
</soap:body>
</soap:envelope>
So to the possible solutions
Ensure that the CteWebService.xml is serialised to have the OCTE structure as it's root element.
Use etc. XPath to locate the OCTE element, and deserialise that instead.
var nsmgr = ...
var element = document.SelectSingleNode("//OCTE", nsmgr);
You only need to initialise a Xml NamespaceManager if the OCTE element belongs to a specified xml namespace, otherwise you can leave it out.

How to handle/cleanse invalid 0x14 in XML using Linq?

I'm working on a C# client that downloads XML files from a web service via SOAP. For some of the older records hosted on the service, the XML comes across with, apparently, a 0x14 buried somewhere in it, which kicks an "Invalid whitespace character" exception. I'm using Linq to dump the XML into files. Is there some way to instruct Linq to dispose of invalid characters without losing the rest of the XML?
EDIT:
Here's the code I currently have for putting the XML to file:
XDocument c =
new XDocument(
new XElement(nameSpace + "getCitationsResponse",
new XAttribute(XNamespace.Xmlns + "ns1", nameSpace),
new XElement("list",
record.reportDateSpecified ? new XElement("reportDate", record.reportDate) : null,
new XElement("reportType", record.reportType),
new XElement("title", record.title),
new XElement("projectNumber", record.projectNumber),
new XElement("author", record.author),
new XElement("abstract", record.#abstract),
new XElement("numPages", record.numPages),
record.isDataTypeSpecified ? new XElement("isDataType", record.isRestrictedData) : null,
new XElement("comments", record.comments),
new XElement("attachments", from a in record.attachments
select new XElement("list",
new XElement("id", a.id),
new XElement("filePath", a.filePath),
new XElement("type", a.type)))));
I had to hack out some of it for the usual reasons, but what I removed is identical to the what's shown here.
I used SoapUI before I posted to see if I could figure out where the flaw was, but I don't see anything in SoapUI, and it doesn't generate an error itself.
EDIT #2:
Here's the exact error message and stack trace. Makes me wonder if I can actually do something about it or if I just need to work in something to log which records have invalid characters and try to pull 'em down manually with SoapUI.
Invalid white space character (0x14) in text to output
at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
at Downloader.WebService.ApiService.getRecords(String username, String[] ids)
at Downloader.Central.RecordLoop(ApiService svc, Int32 offset, String username)
getRecords is the API call generated by the wsdl, and RecordLoop is a recursive function I wrote to handle iterating through the API call to find updated records and push them to the Linq function I posted already.
As mentioned in some of the comments above, it's possible to do execute different ninja tricks to get the SOAP response to comply with the XML specification.
If you choose to change the response to make it valid XML, you have to seriously consider if your changes are changing the meaning of the response.
As I see it, the problem is not on your side, but on the service side. If you can, you should try to get the service owner to upgrade the service to deliver proper formatted XML in their web services.
When dealing with 3rd party web services, I normally do the following:
Enable full XML Schema validation on any requests and responses to and from 3rd web services. If the requests or responses aren't XML schema valid, then we (client and service) have a problem, which can be minor or major - but at least it's being attended to.
Always log any schema validation errors, before trying to fix the content, to be sure that it's on record.
Ensure that I'm fully aware of the system, business or legal implications on modifying the content.
Ensure that I'm encoding the response using the proper encoding format - UTF8, Latin1 or others.
Invalid content is typically xml text elements, that contain illegal XML characters. The service side should either use XML encoding or base64 encoding, when transferring such text nodes, both to preserve formatting as well as content.
On the more technical part of actually changing the content so it become valid, I would normally add WCF behaviours, that would address the issues as doing so, kind of separate the concerns of fixing up the xml and the business purpose of service invocation.
It's also easy to remove the WCF behaviour, if or when the service gets updated to provide valid XML at any request.

Force WCF to create an xml namespace alias in client proxy

I used the Add Service Reference feature to create a proxy to an external web service.
By default, the WCF client is producing SOAP messages where the message body has namespace decorations that look like this:
<s:Body>
<BankingTransaction xmlns="http://tempuri.org/">
<amount>0</amount>
</BankingTransaction>
</s:Body>
I need the message body to look like this instead
<s:Body>
<bb:BankingTransaction xmlns:bb="http://tempuri.org/">
<amount>0</amount>
</bb:BankingTransaction>
</s:Body>
The distinction is the "bb" xml namespace alias. The web service that I'm trying to consume requires that the xml namespace for the message payload be aliased. And the default behavior the WCF client is to define the namespace as the DEFAULT namespace. I've searched high and low for a configuration / decoration solution to this problem and haven't found it. Barring a configuration solution, I'll have to inspect and alter each SOAP message after it is serialized. #lame.
Is there a simple solution here?
The solution to this problem is to create a custom MessageInspector (via IClientMessageInspector) to inspect and alter the SOAP messages that the WCF client proxy produces, prior to sending them over the wire. The basis for this solution is articulated in Steven Cheng's post, "[WCF] How to modify WCF message via custom MessageInspector", with further background from Kirk Evan's post, "Modify Message Content with WCF".
I used the code from Steven's post to wire up the custom MessageInspector infrastructure. Then I modified his Transformf2() method, which operates only on the <Body> portion of the SOAP message, to suit my particular needs. In my case, as described in the original question, I needed to define and use an alias for my target web service XML namespace, xmlns="http://tempuri.org", above.
To do this I must
obtain a reference to the operation node, <BankingTransaction>,
which will always be the first (and only) child of <Body>
remove the attribute that sets the default namespace to the target
namespace
set the prefix (namespace alias) for the node
The modified Transform2() code that does this is below:
private static Message Transform(Message oldMessage)
{
//load the old message into XML
var msgbuf = oldMessage.CreateBufferedCopy(int.MaxValue);
var tmpMessage = msgbuf.CreateMessage();
var xdr = tmpMessage.GetReaderAtBodyContents();
var xdoc = new XmlDocument();
xdoc.Load(xdr);
xdr.Close();
// We are making an assumption that the Operation element is the
// first child element of the Body element
var targetNodes = xdoc.SelectNodes("./*");
// There should be only one Operation element
var node = (null != targetNodes) ? targetNodes[0] : null;
if (null != node)
{
if(null != node.Attributes) node.Attributes.RemoveNamedItem("xmlns");
node.Prefix = "bb";
}
var ms = new MemoryStream();
var xw = XmlWriter.Create(ms);
xdoc.Save(xw);
xw.Flush();
xw.Close();
ms.Position = 0;
var xr = XmlReader.Create(ms);
//create new message from modified XML document
var newMessage = Message.CreateMessage(oldMessage.Version, null, xr);
newMessage.Headers.CopyHeadersFrom(oldMessage);
newMessage.Properties.CopyProperties(oldMessage.Properties);
return newMessage;
}
}

Encountered invalid root element name 'HTML'. 'root' is the only allowed root element name

i am using msdn sample code and it has jsonp wrapper files you can find the code here
of this article and MSDN article JSON with Padding (AJAX)
but when i run the code it throw me this error:
Encountered invalid root element name 'HTML'. 'root' is the only allowed root element name
what does it mean?
It means that you've made some kind of web request that is expecting to get some kind of XML data back but instead it is getting HTML data back. The usual cause is a messed up URL. If your URL were correct, then XML would be returned as expected. Since it is messed up you end up getting back HTML (probably an error page at that).
Check your URLs to make sure they are correct.
I found the solution to similar problem. In my case, I was getting similar error, when my service was returning raw JSON, that is to say it was returning a Stream which represented this JSON.
The error was: Encountered invalid root element name 'Binary'. 'root' is the only allowed root element name.
The problem is that the MS provided example uses JsonWriter to take convert the message to JSON, but this writer expects that your message consists of JSON objects which he can convert to Stream. In my case the message was compose of binary data, so instead of one "root" element I was having "Binary" element.
I got over this issue by modifying classes provided by the MS sample. Basically I check the format of the message - if it is JSON I can still use the JsonWriter, if it is Binary, I have to take a different approach. In your case the message is in HTML format (I am not sure how do you serve it), but you will find a different way to get the body of the message.
I wrote a blog post about my issue here: http://hoonzis.blogspot.com/2011/07/provide-jsonp-with-your-wcf-services.html
Hope it helps a bit, Honza
I ran into the same error message but in a different scenario. I was adding JSON support to a WCF web service that only supported XML.
Specifically I wanted to return the error messages object in JSON also.
I had a class that was implementing System.ServiceModel.Dispatcher.IErrorHandler. Within the ProvideFault method I was setting the `WebBodyFormateMessageProperty to the corresponding one wither, XML or JSON based on what it was passed in the accept header. I was also setting the content type accordingly. What I was missing was using the correct serializer for each case
Dim webBodyFormatMessageProp As Channels.WebBodyFormatMessageProperty
Dim contentType As String
Dim serializer As XmlObjectSerializer
If WebOperationContext.Current.OutgoingResponse.Format = WebMessageFormat.Json Then
webBodyFormatMessageProp = New System.ServiceModel.Channels.WebBodyFormatMessageProperty(System.ServiceModel.Channels.WebContentFormat.Json)
contentType = "application/json"
serializer = New DataContractJsonSerializer(GetType(MyErroClass))
Else
webBodyFormatMessageProp = New System.ServiceModel.Channels.WebBodyFormatMessageProperty(System.ServiceModel.Channels.WebContentFormat.Xml)
contentType = "text/xml"
serializer = New DataContractSerializer(GetType(MyErroClass))
End If
Dim detail = faultException.[GetType]().GetProperty("Detail").GetGetMethod().Invoke(faultException, Nothing)
fault = System.ServiceModel.Channels.Message.CreateMessage(version, "", detail, serializer)
fault.Properties.Add(System.ServiceModel.Channels.WebBodyFormatMessageProperty.Name, webBodyFormatMessageProp)
Dim httpResponseMessageProp = New System.ServiceModel.Channels.HttpResponseMessageProperty()
httpResponseMessageProp.Headers(System.Net.HttpResponseHeader.ContentType) = contentType
httpResponseMessageProp.StatusCode = System.Net.HttpStatusCode.OK
httpResponseMessageProp.StatusDescription = [error].Message
fault.Properties.Add(System.ServiceModel.Channels.HttpResponseMessageProperty.Name, httpResponseMessageProp)
Apologize for the VB.net but that is what I am currently working on.

Categories