13

This is an offshoot from this question Why is the HttpWebRequest body val null after "crossing the Rubicon"? which was answered (one hurdle is leapt), but the next hurdle trips me up.

With this code:

public async void PostArgsAndXMLFileAsStr([FromBody] string stringifiedXML, string serialNum, string siteNum)
{
    XDocument doc = XDocument.Parse(await Request.Content.ReadAsStringAsync()); 

...or this:

XDocument doc = XDocument.Load(await Request.Content.ReadAsStreamAsync());

...and this as the incoming stringifiedXML:

<?xml version=1.0?>
<LocateAndLaunch>
    <Tasks>Some Task</Tasks>
    <Locations>Some Location</Locations>
</LocateAndLaunch>

...I get the exception: "System.Xml.XmlException was unhandled by user code HResult=-2146232000 Message=Root element is missing."

With this code (same stringifiedXML):

XDocument doc = XDocument.Parse(stringifiedXML);

... I get

System.InvalidOperationException was unhandled by user code HResult=-2146233079 Message=Sequence contains no elements Source=System.Core StackTrace: at System.Linq.Enumerable.First[TSource](IEnumerable`1 source) at HandheldServer.Controllers.DeliveryItemsController.d__2.MoveNext() in c:\HandheldServer\HandheldServer \Controllers\DeliveryItemsController.cs:line 109 InnerException:

IOW, depending on how I parse the incoming string, I get either "Root element is missing" or "Sequence contains no elements"

What the Deuce McAlistair MacLean Virginia Weeper?!? Isn't <LocateAndLaunch> a root element? Aren't Some Task and Some Location elements?

Will I need to manually take the XML apart without being able to use XDocument or such?

Note: From Fiddler, sending the body data (XML text) works (what I send arrives as I would hope); but even then, the XML parse code on the server fails.

Trying to send the same data from the handheld/Compact Framework client code, though, results in just the data through the "=" (something like <xml version=" being passed to the server; and then on the client, I see "This operation cannot be performed after the request has been submitted"

UPDATE

So based on Marcin's answer, it seems if I stick with XDocument.Parse() I should be okay, and based on TToni's answer, the data/xml itself may be bad. Here is the contents of the file:

<?xml version="1.0"?>
<LocateAndLaunch>
    <Tasks>
    </Tasks>
    <Locations>
    </Locations>
</LocateAndLaunch>

So there are quotes around the version number - but do I need to escape these somehow - is this why the data is being truncated - because when it sees the first quote (before the "1.0") it thinks that is the string termination, maybe?

UPDATE 2

Marcin, the incoming "xml" data (string) is truncated before it ever gets to the XDocument code:

[Route("api/DeliveryItems/PostArgsAndXMLFileAsStr")]
public async void PostArgsAndXMLFileAsStr([FromBody] string stringifiedXML, string serialNum, string siteNum)
{
    string beginningInvoiceNum = string.Empty;
    string endingInvoiceNum = string.Empty;

    //XDocument doc = XDocument.Parse(stringifiedXML);
    //XDocument doc = XDocument.Parse(await Request.Content.ReadAsStringAsync()); 
    XDocument doc = XDocument.Load(await Request.Content.ReadAsStreamAsync());

UPDATE 3

By using TToni's suggestion and replacing the double with single quotes:

...I'm now getting the whole string into my server method:

enter image description here

...but I'm still getting "Root element is missing":

System.Xml.XmlException was unhandled by user code HResult=-2146232000 Message=Root element is missing. Source=System.Xml LineNumber=0 LinePosition=0 SourceUri="" StackTrace: at System.Xml.XmlTextReaderImpl.Throw(Exception e) at System.Xml.XmlTextReaderImpl.ParseDocumentContent() at System.Xml.XmlTextReaderImpl.Read() at System.Xml.Linq.XDocument.Load(XmlReader reader, LoadOptions options) at System.Xml.Linq.XDocument.Load(Stream stream, LoadOptions options) at System.Xml.Linq.XDocument.Load(Stream stream) at HandheldServer.Controllers.DeliveryItemsController.d__2.MoveNext() in c:\HandheldServer\HandheldServer\Controllers\DeliveryItemsController.cs:line 66 InnerException:

If I wasn't already crazy, this would drive me crazy. As it is, I don't know quite where I'm being driven. Many employers are looking for somebody who is driven; maybe this is what they mean?

UPDATE 4

Using this:

XDocument doc = XDocument.Parse(stringifiedXML);

...instead of this:

XDocument doc = XDocument.Load(await Request.Content.ReadAsStreamAsync());

...solved the "Root element is missing" err msg; thus, I marked Marcin's answer as correct.

Community
  • 1
  • 1
B. Clay Shannon-B. Crow Raven
  • 8,547
  • 144
  • 472
  • 862
  • 1
    Escaping things can be a real bitch, depending on how you pass and parse such strings. That's why XML allows you to use either single or double quotes. If your favorite language uses double quotes for strings, use single quotes in your XML docs and vice versa. If you cannot change the XML source, you have to go through the escaping routine. – TToni Mar 14 '14 at 22:31
  • "Escaping things can be a real bitch" <= Wasn't that a song by Neil Sedaka? Anyway, this is C# (of the double-quoted strings), so I will see what I can do about replacing " with ' in the html, I reckon. – B. Clay Shannon-B. Crow Raven Mar 14 '14 at 22:55
  • I'll give this a go: strData = strData.Replace("\"", "'"); – B. Clay Shannon-B. Crow Raven Mar 14 '14 at 23:03
  • Thanks for the escaping suggestion; that gets me past the initial hurdle; the answer to the actual question remains unsolved, though. – B. Clay Shannon-B. Crow Raven Mar 14 '14 at 23:24

4 Answers4

18

For those who find this page through google, but are still baffled. I believe I have found the answer thanks to a buried MS Post.

It lies in resetting the stream to the beginning utilizing:

xmlStream.Seek(0, SeekOrigin.Begin);

Without this before the read, you essentially begin your load at the end of the stream. No root element because no more stream.

Zexks Marquise
  • 1,497
  • 14
  • 18
  • I have this same issue, yet this and stream.Position = 0; don't seem to fix the issue... any suggestions? – user1040975 May 13 '16 at 19:38
  • Have you looked at your steam during runing (debugger or output-ing it directly)? Maybe check it's length make sure there's something there. Without looking at it all it's kind of hard to tell. – Zexks Marquise May 18 '16 at 18:43
  • Yeah. It was at the start of the stream. When I checked it again I realized that despite having set the root in the class - what I passed to the deserializer included an extra node and it was throwing it off. That and the namespace attribute. Class issues.... Thanks though – user1040975 May 19 '16 at 16:52
  • 1
    thx. i'm using MemoryStream, and .Seek() helped me to avoid "root element missing" error in XDocument Load method. – davor Sep 30 '16 at 21:39
  • Genius! This position seek to the start of the stream solved it. – scrat.squirrel May 01 '20 at 23:50
  • 1
    Same problem when downloading a blob to a `MemoryStream` from Azure Storage, I've seen this problem many times before but didn't click this was why code was failing this time! – aligray Nov 27 '22 at 13:23
8

Sample XML you've provided works just fine with XDocument:

var stringifiedXML = @"<?xml version=""1.0""?>
    <LocateAndLaunch>
        <Tasks>Some Task</Tasks>
        <Locations>Some Location</Locations>
    </LocateAndLaunch>";

XDocument doc = XDocument.Parse(stringifiedXML);

var tasks = (string)doc.Root.Element("Tasks");
var locations = (string)doc.Root.Element("Locations");

So your problem is with await Request.Content.ReadAsStringAsync(), not with XDocument.

Make sure ReadAsStringAsync() returns what you need first.

MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
2

If that is really your stringified XML, your XML declaration is broken. You need to enclose the version number in single or double quotes, so instead of <?xml version=1.0?> do <?xml version="1.0"?> or <?xml version='1.0'?>. That would also explain the errors IMO.

Syntax for XML declaration: http://www.w3.org/TR/REC-xml/#NT-XMLDecl

TToni
  • 9,145
  • 1
  • 28
  • 42
1

this can be achieved easily by setting a custom parameter binding as mentioned in the below blog post . i tried in one of my projects where i had to use raw xml post for a WebApi

Check this blog entry

prasanth shenoy
  • 245
  • 3
  • 5