Question

I am new to windows metro apps and totally stuck here. textbox1.text displaying the accurate data inside the function but Aya remains null outside the function. How can i solve this problem ? I think recursion is creating problem but how to solve it ?

public async void Aya_Parse()
    {

        // Initialize http client.
        HttpClient httpClient = new HttpClient();
        Stream stream = await httpClient.GetStreamAsync("some link");

        // Load html document from stream provided by http client.
        HtmlDocument htmlDocument = new HtmlDocument();
        htmlDocument.OptionFixNestedTags = true;
        htmlDocument.Load(stream);

        Aya_ParseHtmlNode(htmlDocument.DocumentNode);
    }

    int aia = 0;
    string Aya = null;
    private void Aya_ParseHtmlNode(HtmlNode htmlNode)
    {

        foreach (HtmlNode childNode in htmlNode.ChildNodes)
        {


            if (childNode.NodeType == HtmlNodeType.Text && aia == 1)
            {

                Aya += " " + childNode.InnerText.ToString(); aia = 0;

            }

            else if (childNode.NodeType == HtmlNodeType.Element)
            {
               Aya += " "; // removing this causes null exception at textbox1.text 

                switch (childNode.Name.ToLower())
                {

                    case "span":
                        Aya += childNode.NextSibling.InnerText.ToString();

                       Aya_ParseHtmlNode(childNode);
                        break;
                    case "td":

                        aia = 1;
                        Aya_ParseHtmlNode(childNode);break;

                    default:

                        Aya_ParseHtmlNode(childNode); break;
                }
            }
        }
        textBox1.Text = Aya;

    }
Was it helpful?

Solution

You never assign a starting value to Aya, so even though you try to add text to it in your Aya_ParseHtmlNode(HtmlNode htmlNode) method, you can't add text to a null value. This can be fixed by doing a check for null on the value and setting it to a default. I'm surprised you aren't getting a NullArgumentException inside your method...

public async void Aya_Parse()
{

    // Initialize http client.
    HttpClient httpClient = new HttpClient();
    Stream stream = await httpClient.GetStreamAsync("some link");

    // Load html document from stream provided by http client.
    HtmlDocument htmlDocument = new HtmlDocument();
    htmlDocument.OptionFixNestedTags = true;
    htmlDocument.Load(stream);
    //  greetingOutput.Text = htmlDocument.DocumentNode.InnerText.ToString();
    // Parse html node, this is a recursive function which call itself until
    // all the childs of html document has been navigated and parsed.
    Aya_ParseHtmlNode(htmlDocument.DocumentNode);
}

int aia = 0;
string Aya = null;
private void Aya_ParseHtmlNode(HtmlNode htmlNode)
{
    if (Aya == null)
    {
        Aya = String.empty;
    }
    foreach (HtmlNode childNode in htmlNode.ChildNodes)
    {


        if (childNode.NodeType == HtmlNodeType.Text && aia == 1)
        {

            Aya += " " + childNode.InnerText.ToString(); aia = 0;

        }

        else if (childNode.NodeType == HtmlNodeType.Element)
        {
           Aya += " ";

            switch (childNode.Name.ToLower())
            {

                case "span":
                    Aya += childNode.NextSibling.InnerText.ToString();

                   Aya_ParseHtmlNode(childNode);
                    break;
                case "td":

                    aia = 1;
                    Aya_ParseHtmlNode(childNode);break;

                default:

                    Aya_ParseHtmlNode(childNode); break;
            }
        }
    }
    textBox1.Text = Aya;

}

Using a StringBuilder might also be a better idea here since you could recurse and generate a very large string here, so a StringBuilder would be a easier on your memory

public void Aya_Parse()
{

    // Initialize http client.
    HttpClient httpClient = new HttpClient();
    Stream stream =  httpClient.GetStreamAsync("some link").Result;

    // Load html document from stream provided by http client.
    HtmlDocument htmlDocument = new HtmlDocument();
    htmlDocument.OptionFixNestedTags = true;
    htmlDocument.Load(stream);
    //  greetingOutput.Text = htmlDocument.DocumentNode.InnerText.ToString();
    // Parse html node, this is a recursive function which call itself until
    // all the childs of html document has been navigated and parsed.


    //you marked the method Async, and
    //since Aya is in the class, if multiple threads call this
    //method, you could get inconsistent results
    //I have changed it to a parameter here so this doesn't happen
    StringBuilder Aya = new StringBuilder()
    Aya_ParseHtmlNode(htmlDocument.DocumentNode, Aya);
    //I would also move your textbox update here, so you aren't calling
    //ToString() all the time, wasting all of the memory benefits
    textBox1.Text = Aya.ToString();
}

int aia = 0;
private void Aya_ParseHtmlNode(HtmlNode htmlNode, StringBuilder Aya)
{

    foreach (HtmlNode childNode in htmlNode.ChildNodes)
    {


        if (childNode.NodeType == HtmlNodeType.Text && aia == 1)
        {

            Aya.Append(childNode.InnerText); aia = 0;

        }

        else if (childNode.NodeType == HtmlNodeType.Element)
        {
           Aya.Append(" ");

            switch (childNode.Name.ToLower())
            {

                case "span":
                    Aya.Append(childNode.NextSibling.InnerText);

                   Aya_ParseHtmlNode(childNode, Aya);
                    break;
                case "td":

                    aia = 1;
                    Aya_ParseHtmlNode(childNode, Aya);break;

                default:

                    Aya_ParseHtmlNode(childNode, Aya); break;
            }
        }
    }
}

Edit: Your issue actually probably comes from your use of the async keyword on Aya_Parse() which means that the method calling Aya_Parse() may return immediately before it actually does any processing. So if you are checking the value of Aya after calling Aya_Parse(), it likely has not had enough time to do the computation before you actually check the value elsewhere in your code. I recommend removing the async tag, or changing Aya_Parse() to return the value of Aya when it finishes. Check here for some good info on how to use the async tag with return values.

OTHER TIPS

It could be. It's behaving as if your string variable is passed into the method by value rather than holding the reference.

Keep in mind that by using Async methods you are effectively multi threading, so multiple threads would be contending for the same module level variable. The compiler is likely choosing to make your code threadsafe for you.

If you declare a separate string inside your async method and pass it in by ref is should behave as you expect.

I would also suggest you do the same with your module level int.

OR... you could remove the async from the Aya_Parse and use the Task library (and toss in a Wait call below) to get your stream.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top