Novalis
Novalis

Reputation: 2325

Can not close StreamReader (reader.Close(); blocks code)

I get continous [ non-stop ] mesages from web url:

    string webUrl = "xxxxx/status.cgi";
    WebClient client = new WebClient();
    client.Credentials = new NetworkCredential("UUU", "PPP");

    StreamReader reader = new StreamReader(client.OpenRead(webUrl), Encoding.UTF8,true);
    string line;
    int counter = 0;
    while ((line = reader.ReadLine()) != null)
    {
        if( line == "XXXXXX")
        {
           break;
        }
    }


    Console.WriteLine("Try to Close Stream Reader...");
    reader.Close();
    Console.WriteLine("Stream Reader is closed...");

The problem is that when I break from while loop, i want to close the stream reader...But stream reader does not close...."reader.Close();" hangs/block the code...

Why this happen? How to fix it?

UPDATE: "using" DOES NOT WORK IN MY CASE: Exit the loop but stream reader is not disposed...Hang/Block

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Linq;
using System.Text;

namespace TestStreamReader
{
    class Program
    {
        static void Main(string[] args)
        {
            string  webUrl = "http://X.Y.Z:7000/status.cgi";
            int counter = 0;

            using (WebClient client = new WebClient())
            {
                client.Credentials = new NetworkCredential("admin", "000000");

                using (StreamReader reader = new StreamReader(client.OpenRead(webUrl), Encoding.UTF8, true))
                {
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        counter++;

                        Console.WriteLine("Input"+ line);

                        if (counter == 10)
                        {
                            Console.WriteLine("I am exiting the loop");
                            break;
                        }


                    }

                    Console.WriteLine("Exit the while loop");

                }

                Console.WriteLine("Reader should be desposed");
            }

            Console.WriteLine("Web Client should be disposed!");



        }
    }
}

Upvotes: 0

Views: 1475

Answers (4)

tele-bird
tele-bird

Reputation: 183

I had the same problem, but none of the suggestions made in this thread were helpful for me. But I WAS able to fix it a different way, so I thought I'd share...

I used the asynchronous version of client.OpenRead(uri) to open the stream, and then I was able to call client.CancelAsync() when I need to shut it down. The implementation in there must be disposing the StreamReader differently, because it works that way.

Upvotes: 1

PPC-Coder
PPC-Coder

Reputation: 3632

I've seen something similar. The problem is that it's waiting for a ReadTimeOut to occur. You can try setting the Stream.ReadTimeOut property to something sufficiently small.

Upvotes: 0

jamesbar2
jamesbar2

Reputation: 614

Instead of using WebClient, have you thought about using HttpWebRequest and getting the response stream?

//using System.Net;

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(ApiProcedure.FunctionUri);
    request.Credentials = (CredentialCache)Credentials;
    request.PreAuthenticate = true;

    //define the type of request
    request.Method = HttpMethod;
    request.ContentType = "application/json";

    //execute
    StreamReader sr = new StreamReader(response.GetResponseStream());
    return sr.ReadToEnd();

I know you're doing a continuous stream, but you should be able to treat the stream reader normally like you're doing in your example. I think this method will give you a little more control.

I normally only use WebClient if I need to perform a simple task where all the nitty gritty setup/streams are done for me. Find I get better results when managing the request and response separately.

Good luck!

EDIT: Also, this is just a snippet from my code. You might want to take a look here: C# - How to read a continuous stream of XML over HTTP for a good example of reading continuous chunks of data.

Upvotes: 0

Independent
Independent

Reputation: 2987

A Quick idea frm my side, try put the StreamReader in a Using.

        string webUrl = "http://www.google.com";
        using (WebClient client = new WebClient())
        {
            client.Credentials = new NetworkCredential("UUU", "PPP");

            int counter = 0;

            using (StreamReader reader = new StreamReader(client.OpenRead(webUrl), Encoding.UTF8, true))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    if (line == "XXXXXX")
                    {
                        break;
                    }
                    counter++;
                }

            }
        }

        Console.WriteLine("Try to Close Stream Reader...");
        Console.WriteLine("Stream Reader İSclosed...");

This will keep Connection open until it's no longer used. The Dispose() will be called automatically after then. No need of manual detach or close. [Update] I also move the WebClient into a using and the counter variable outside the StreamReaders using.

[Edit]
Due to comments the problem looks like a (untested speculation) side-effect of the WebClient can't quit, because it can't see the end of the stream. Therefore, the StreamReader wait. I attach Another approach to read from a webrequest. However this will far from sure work better.

    string webUrl = "http://www.google.com";

    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(webUrl);
    req.Credentials = new NetworkCredential("UUU", "PPP");
    using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
    {
        using (Stream stream = resp.GetResponseStream())
        {
            int read;
            string line;

            byte[] data = new byte[4096];
            while ((read = stream.Read(data, 0, data.Length)) > 0)
            {
                line = Encoding.GetEncoding("ASCII").GetString(data, 0, data.Length);

                if (line.Contains("(function(){try{var a=window.gbar;"))
                {
                    Console.WriteLine("End Bit founded..");
                    // Some more logic?
                    break;
                }
                data = new byte[4096];
                Console.WriteLine(line);
            }
        }
    }
    Console.WriteLine("End of Stream");

Please note I used Stream here and manually split to 4096 datablocks, just for the sake of the problem. The usual would be using (StreamReader stream2 = new StreamReader(resp.GetResponseStream())) { string test = stream2.ReadToEnd(); }.

Hope it will give any step further.
Also mind that Encoding is set to "ASCII" above.

Upvotes: 0

Related Questions