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.
Related
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>
I have an application in C# where I'm inspecting SOAP messages between client and server.
The request and response are always XML serialization. Part of the message has the action method and I need to get just the method but I have seen that the element that I need in the XML not always has the same name:
Here is an example:
This is the element that I need to parse:
<a:Action s:mustUnderstand="1">http://tempuri.org/IMember/GetAuthorizations</a:Action>
It can also appears sometimes like this:
<Action d1p1:mustUnderstand="1" xmlns:d1p1="http://www.w3.org/2003/05/soap-envelope" xmlns="http://www.w3.org/2005/08/addressing">http://tempuri.org/IMember/GetAuthorizations</Action>
What I need to get is the Method of the URL, in this case I need to parse this element so I can get GetAuthorizations
Any clue on how can I parse both? I don't know when it comes in the first way or in the second.
Try this
string input = "<a:Action xmlns:a=\"http://tempuri.org\" xmlns:s=\"http://tempuri.org\" s:mustUnderstand=\"1\">\"http://tempuri.org/IMember/GetAuthorizations\"</a:Action>";
XDocument doc = XDocument.Parse(input);
string mustUnderstand = doc.Elements().Where(x => x.Name.LocalName == "Action").Attributes().Where(y => y.Name.LocalName == "mustUnderstand").FirstOrDefault().Value;
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");
};
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;
}
}
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.