views:

23

answers:

1

I have a web service that has one method:

[WebMethod]
public bool SyncUserData(string userxml)

The xml is a series of user records and I use an XmlReader to read through the data and process it.

When I call the web service with 2000 records, it processes 2000 records. When my client calls it with the same xml, it processes 1000 records. It processes every other record.

Does anyone have any experience with this sort of problem? My thought is that it is an encoding issue but I have tried sending the data to the service as ASCII, ISO-8859-1 etc in my tests and cannot recreate.

Any help much appreciated.

This is the calling code:

while (userXml.Read())
{

    if (userXml.Name == NODE_NAME_FILE_NAME && userXml.NodeType == XmlNodeType.Element)
    {
        _importFilename = userXml.ReadString();
    }

    if (userXml.Name == NODE_NAME_USER && userXml.NodeType == XmlNodeType.Element)
    {
        ProcessUser(userXml);
    }
}

and this is what processUser does with teh xml reader

private void ProcessUser(XmlReader userXml)
{
    _usersinfeed++;
    XmlDocument user = new XmlDocument();
    user.LoadXml(userXml.ReadOuterXml());
     ...

}

A: 

What's biting you is the side-effect of ReadOuterXml - it most likely advances the current position of the XmlReader - but then, in your loop while (userXml.Read()) you advance it again - skipping one xml element in the process.

There are various ways of solving this - but the easiest and cleanest would be to not use XmlReader. Is that an option?

An easier way to process xml is Linq to Xml:

public static void Main()
{
    SyncUserData(@"
    <doc>
    <filename>test</filename>
    <user>Someone</user>
    <user>Someone2</user>

    <filename>testA</filename>
    <user>Someone else</user>
    <user>Someone else2</user>
    </doc>
    ");
}

const string  NODE_NAME_FILE_NAME = "filename";
const string  NODE_NAME_USER = "user";

static string _importFilename;
static int _usersinfeed;

public static bool SyncUserData(string userxml) {
    foreach(XElement el in XDocument.Parse(userxml).Descendants()) {
        //or: XDocument.Parse(userxml).Root.Elements() -- this depends on your document

        if (el.Name == NODE_NAME_FILE_NAME)
            _importFilename = el.Value;
        if (el.Name == NODE_NAME_USER)
            ProcessUser(el);
    }
    return true;
}

private static void ProcessUser(XElement el)
{
    _usersinfeed++;
    Console.WriteLine("User:{0}, file:{1}\n{2}\n",_usersinfeed,_importFilename,el);
    //you probably don't need the following anymore
    //XmlDocument user = new XmlDocument();
    //user.LoadXml(el.CreateReader());

    //...
}

Which outputs:

User:1, file:test
<user>Someone</user>

User:2, file:test
<user>Someone2</user>

User:3, file:testA
<user>Someone else</user>

User:4, file:testA
<user>Someone else2</user>

However, you may be able to use XML Serialization - that's a very easy way to parse/generate XML without much boilerplate at all also gives you a .NET native datastructure to work with to boot! Then, you just need a small set of classes to define the document structure, and the framework can create instances auto-magically from XML for you, without any manual parsing code whatsoever. Not all XML syntaxes are amenable to that, however.

Eamon Nerbonne
thanks for this. that was the correct issue with the code. the reason why it worked in dev and not production was the existence of whitespace nodes in the dev xml that did not exist in production xml. This meant the extra read did not read beyond the intended node
Which approach did you end up using? Did you try Xml-serialization? Really, you should take a peek - it's so much easier than hand-coding this stuff.
Eamon Nerbonne
I didnt' actually, just fixed the XmlReader - the xml was going straight to db and we didn't have domain objects for the import to deserialize into. also we were using .net 2 so no linqI have used xml serialization in the past and like it.thanks for all your help